From 5e2bac01cb6e8d3de3cc0e496d94a729e4740247 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 30 Apr 2024 17:26:48 -0500 Subject: #1357 GLTF Export Prototype --- indra/newview/gltfscenemanager.cpp | 43 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 4e3439ea5c..f9f1240469 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -66,11 +66,50 @@ 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.notNull()) + { + LLFilePickerReplyThread::startPicker( + [](const std::vector& 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::save(const std::string& filename) +{ + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + if (obj && obj->mGLTFAsset.notNull()) + { + Asset* asset = obj->mGLTFAsset; + tinygltf::Model model; + asset->save(model); + + LLTinyGLTFHelper::saveModel(filename, model); } } -- cgit v1.3 From 170765fd3505410dced83b342f87030fd9151e35 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 30 Apr 2024 21:57:42 -0500 Subject: #1357 Proof of concept on decomposing a GLTF scene into its component parts --- indra/llmath/llvolumeoctree.h | 6 -- indra/newview/gltf/accessor.cpp | 18 ++++ indra/newview/gltf/accessor.h | 4 + indra/newview/gltf/asset.cpp | 102 +++++++++++++++++++++ indra/newview/gltf/asset.h | 11 ++- indra/newview/gltfscenemanager.cpp | 45 +++++++++ indra/newview/gltfscenemanager.h | 4 +- indra/newview/llviewermenu.cpp | 11 +++ indra/newview/skins/default/xui/en/menu_viewer.xml | 6 ++ 9 files changed, 199 insertions(+), 8 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index 0bbb793896..1df2bf5390 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -48,12 +48,6 @@ public: *this = rhs; } - const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) - { - LL_ERRS() << "Illegal operation!" << LL_ENDL; - return *this; - } - ~LLVolumeTriangle() { diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 55d36b7a32..9bfdc2afa6 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -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; diff --git a/indra/newview/gltf/accessor.h b/indra/newview/gltf/accessor.h index 9b8265d8da..6849cd8609 100644 --- a/indra/newview/gltf/accessor.h +++ b/indra/newview/gltf/accessor.h @@ -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); }; diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 233faac545..475cbcb6e5 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -30,9 +30,11 @@ #include "llvolumeoctree.h" #include "../llviewershadermgr.h" #include "../llviewercontrol.h" +#include "../llviewertexturelist.h" using namespace LL::GLTF; +#pragma optimize("", off) namespace LL { @@ -821,6 +823,106 @@ 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 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) { diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index b8300c2d8a..cb28c4a572 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -254,6 +254,9 @@ namespace LL return *this; } + // save image clear local data, and set uri + void decompose(Asset& asset, const std::string& filename); + void allocateGLResources() { // allocate texture @@ -322,7 +325,13 @@ namespace LL // 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); }; } } diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index f9f1240469..0aedcd653d 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -100,6 +100,51 @@ void GLTFSceneManager::saveAs() } } +void GLTFSceneManager::decomposeSelection() +{ + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + if (obj && obj->mGLTFAsset.notNull()) + { + LLFilePickerReplyThread::startPicker( + [](const std::vector& 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.notNull()) + { + // 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(); diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index ec50a0952f..57d9e019a5 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -41,7 +41,9 @@ namespace LL 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 + 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); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index fcda8fa767..631e1b57d9 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -8000,6 +8000,16 @@ class LLAdvancedClickGLTFSaveAs : public view_listener_t } }; +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 { @@ -9649,6 +9659,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview"); 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"); diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 9544a926f3..6238efe688 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2861,6 +2861,12 @@ function="World.EnvPreset" + + + Date: Wed, 1 May 2024 09:51:32 -0500 Subject: #1357 Preserve asset "extras" and switch to std::shared_ptr for referencing Asset from LLViewerObject to cut down rebuild time --- indra/newview/gltf/asset.cpp | 6 +++--- indra/newview/gltf/asset.h | 4 +++- indra/newview/gltfscenemanager.cpp | 29 +++++++++++++---------------- indra/newview/gltfscenemanager.h | 10 ++++++++++ indra/newview/llviewerobject.cpp | 7 ++++--- indra/newview/llviewerobject.h | 11 +++++++++-- 6 files changed, 42 insertions(+), 25 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 475cbcb6e5..42f064699c 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -34,8 +34,6 @@ using namespace LL::GLTF; -#pragma optimize("", off) - namespace LL { namespace GLTF @@ -280,6 +278,7 @@ namespace LL 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); @@ -739,9 +738,10 @@ const Asset& Asset::operator=(const tinygltf::Model& src) 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) diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index cb28c4a572..5a62313705 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -265,7 +265,7 @@ namespace LL }; // C++ representation of a GLTF Asset - class Asset : public LLRefCount + class Asset { public: std::vector mScenes; @@ -287,6 +287,8 @@ namespace LL std::string mCopyright; S32 mDefaultScene = INVALID_INDEX; + tinygltf::Value mExtras; + // the last time update() was called according to gFrameTimeSeconds F32 mLastUpdateTime = gFrameTimeSeconds; diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 0aedcd653d..6533f283e2 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -77,7 +77,7 @@ void GLTFSceneManager::load() void GLTFSceneManager::saveAs() { LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); - if (obj && obj->mGLTFAsset.notNull()) + if (obj && obj->mGLTFAsset) { LLFilePickerReplyThread::startPicker( [](const std::vector& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) @@ -103,7 +103,7 @@ void GLTFSceneManager::saveAs() void GLTFSceneManager::decomposeSelection() { LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); - if (obj && obj->mGLTFAsset.notNull()) + if (obj && obj->mGLTFAsset) { LLFilePickerReplyThread::startPicker( [](const std::vector& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) @@ -129,7 +129,7 @@ void GLTFSceneManager::decomposeSelection() void GLTFSceneManager::decomposeSelection(const std::string& filename) { LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); - if (obj && obj->mGLTFAsset.notNull()) + if (obj && obj->mGLTFAsset) { // copy asset out for decomposition Asset asset = *obj->mGLTFAsset; @@ -148,9 +148,9 @@ void GLTFSceneManager::decomposeSelection(const std::string& filename) void GLTFSceneManager::save(const std::string& filename) { LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); - if (obj && obj->mGLTFAsset.notNull()) + if (obj && obj->mGLTFAsset) { - Asset* asset = obj->mGLTFAsset; + Asset* asset = obj->mGLTFAsset.get(); tinygltf::Model model; asset->save(model); @@ -163,7 +163,7 @@ void GLTFSceneManager::load(const std::string& filename) tinygltf::Model model; LLTinyGLTFHelper::loadModel(filename, model); - LLPointer asset = new Asset(); + std::shared_ptr asset = std::make_shared(); *asset = model; gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions @@ -210,10 +210,7 @@ void GLTFSceneManager::update() continue; } - Asset* asset = mObjects[i]->mGLTFAsset; - - asset->update(); - + mObjects[i]->mGLTFAsset->update(); } } @@ -235,7 +232,7 @@ void GLTFSceneManager::render(bool opaque, bool rigged) continue; } - Asset* asset = mObjects[i]->mGLTFAsset; + Asset* asset = mObjects[i]->mGLTFAsset.get(); gGL.pushMatrix(); @@ -382,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) @@ -509,7 +506,7 @@ void GLTFSceneManager::renderDebug() matMul(mat, modelview, modelview); - Asset* asset = obj->mGLTFAsset; + Asset* asset = obj->mGLTFAsset.get(); for (auto& node : asset->mNodes) { @@ -524,7 +521,7 @@ void GLTFSceneManager::renderDebug() continue; } - Asset* asset = obj->mGLTFAsset; + Asset* asset = obj->mGLTFAsset.get(); LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); @@ -561,7 +558,7 @@ void GLTFSceneManager::renderDebug() matMul(mat, modelview, modelview); - Asset* asset = obj->mGLTFAsset; + Asset* asset = obj->mGLTFAsset.get(); for (auto& node : asset->mNodes) { @@ -622,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]; diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index 57d9e019a5..e380be7e3c 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -28,6 +28,16 @@ #include "llsingleton.h" #include "llviewerobject.h" +class LLVOVolume; +class LLDrawable; + +namespace LL +{ + namespace GLTF + { + class Asset; + } +} namespace LL { diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5b21040a04..cc6f4403dd 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -107,6 +107,7 @@ #include "llmeshrepository.h" #include "llgltfmateriallist.h" #include "llgl.h" +#include "gltf/asset.h" //#define DEBUG_UPDATE_TYPE @@ -4420,7 +4421,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]; @@ -4474,7 +4475,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]; @@ -4506,7 +4507,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]; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 64c1ee6633..e314992532 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -45,7 +45,14 @@ #include "llbbox.h" #include "llrigginginfo.h" #include "llreflectionmap.h" -#include "gltf/asset.h" + +namespace LL +{ + namespace GLTF + { + class Asset; + } +} class LLAgent; // TODO: Get rid of this. class LLAudioSource; @@ -736,7 +743,7 @@ public: F32 mPhysicsRestitution; // Associated GLTF Asset - LLPointer mGLTFAsset; + std::shared_ptr mGLTFAsset; // Pipeline classes LLPointer mDrawable; -- cgit v1.3 From 799ebf21624edb8b42ca16b8cf51c138643efd32 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 10 May 2024 15:16:06 +0200 Subject: Fix broken merge and BOOL/bool issues --- indra/llmath/llvolume.cpp | 23 ----------------------- indra/llprimitive/llgltfmaterial.h | 6 ------ indra/llrender/llshadermgr.cpp | 4 ++-- indra/newview/gltf/asset.cpp | 2 +- indra/newview/gltfscenemanager.cpp | 14 +++++++------- indra/newview/gltfscenemanager.h | 10 +++++----- indra/newview/lldrawpoolterrain.cpp | 6 +++--- indra/newview/lldrawpoolterrain.h | 2 +- indra/newview/lldynamictexture.cpp | 2 +- indra/newview/llenvironment.cpp | 4 ++-- indra/newview/llfloaterregioninfo.cpp | 2 +- indra/newview/llgltfmaterialpreviewmgr.cpp | 12 ++++++------ indra/newview/llgltfmaterialpreviewmgr.h | 2 +- indra/newview/llmaniprotate.cpp | 4 ++-- indra/newview/llmaniptranslate.cpp | 11 +++-------- indra/newview/llreflectionmapmanager.cpp | 4 ++-- indra/newview/llselectmgr.cpp | 4 ++-- indra/newview/llselectmgr.h | 2 +- indra/newview/llsurfacepatch.cpp | 2 +- indra/newview/llviewercamera.cpp | 2 +- indra/newview/llvlcomposition.cpp | 16 ++++++++-------- indra/newview/llvlcomposition.h | 2 +- indra/newview/pipeline.cpp | 4 ++-- 23 files changed, 53 insertions(+), 87 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index fa69699436..0b9712ff8c 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -353,29 +353,6 @@ bool LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& v return true; } -//helper for non-aligned vectors -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided) -{ - LLVector4a vert0a, vert1a, vert2a, origa, dira; - vert0a.load3(vert0.mV); - vert1a.load3(vert1.mV); - vert2a.load3(vert2.mV); - origa.load3(orig.mV); - dira.load3(dir.mV); - - if (two_sided) - { - return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, - intersection_a, intersection_b, intersection_t); - } - else - { - return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, - intersection_a, intersection_b, intersection_t); - } -} - //------------------------------------------------------------------- // statics //------------------------------------------------------------------- diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 90f1ecfa8f..a613fc52af 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -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 local_tex_map_t; - local_tex_map_t mTrackingIdToLocalTexture; public: diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 4e03882b7a..f649aa1963 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -188,7 +188,7 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (!shader->attachFragmentObject("deferred/globalF.glsl")) { - return FALSE; + return false; } if (features->hasSrgb || features->hasAtmospherics || features->calculatesAtmospherics || features->isDeferred) @@ -280,7 +280,7 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { if (!shader->attachFragmentObject("deferred/pbrterrainUtilF.glsl")) { - return FALSE; + return false; } } diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 42f064699c..5f2217a075 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -1092,7 +1092,7 @@ void Skin::uploadMatrixPalette(Asset& asset, Node& node) LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, mJoints.size(), - FALSE, + GL_FALSE, (GLfloat*)glmp.data()); } diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 6533f283e2..8bbcef1594 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -259,7 +259,7 @@ LLMatrix4a inverse(const LLMatrix4a& mat) return ret; } -bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_unselectable, S32* node_hit, S32* primitive_hit, +bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* node_hit, S32* primitive_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { @@ -353,10 +353,10 @@ bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const } LLDrawable* GLTFSceneManager::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - BOOL pick_transparent, - BOOL pick_rigged, - BOOL pick_unselectable, - BOOL pick_reflection_probe, + bool pick_transparent, + bool pick_rigged, + bool pick_unselectable, + bool pick_reflection_probe, S32* node_hit, // return the index of the node that was hit S32* primitive_hit, // return the index of the primitive that was hit LLVector4a* intersection, // return the intersection point @@ -539,7 +539,7 @@ void GLTFSceneManager::renderDebug() for (U32 i = 0; i < 2; ++i) { LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL); - LLGLState blend(GL_BLEND, i == 0 ? TRUE : FALSE); + LLGLState blend(GL_BLEND, i == 0 ? GL_TRUE : GL_FALSE); gGL.pushMatrix(); @@ -614,7 +614,7 @@ void GLTFSceneManager::renderDebug() S32 primitive_hit = -1; LLVector4a intersection; - LLDrawable* drawable = lineSegmentIntersect(gDebugRaycastStart, gDebugRaycastEnd, TRUE, TRUE, TRUE, TRUE, &node_hit, &primitive_hit, &intersection, nullptr, nullptr, nullptr); + LLDrawable* drawable = lineSegmentIntersect(gDebugRaycastStart, gDebugRaycastEnd, true, true, true, true, &node_hit, &primitive_hit, &intersection, nullptr, nullptr, nullptr); if (drawable) { diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index e380be7e3c..8f29f34c30 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -61,10 +61,10 @@ namespace LL void renderAlpha(); LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - BOOL pick_transparent, - BOOL pick_rigged, - BOOL pick_unselectable, - BOOL pick_reflection_probe, + bool pick_transparent, + bool pick_rigged, + bool pick_unselectable, + bool pick_reflection_probe, S32* node_hit, // return the index of the node that was hit S32* primitive_hit, // return the index of the primitive that was hit LLVector4a* intersection, // return the intersection point @@ -72,7 +72,7 @@ namespace LL LLVector4a* normal, // return the surface normal 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, 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); void renderDebug(); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index c5932a6ad9..c2caefa210 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -202,11 +202,11 @@ void LLDrawPoolTerrain::drawLoop() void LLDrawPoolTerrain::renderFullShader() { - const BOOL use_local_materials = gLocalTerrainMaterials.materialsReady(true, false); + const bool use_local_materials = gLocalTerrainMaterials.materialsReady(true, false); // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - const BOOL use_textures = !use_local_materials && (compp->getMaterialType() == LLTerrainMaterials::Type::TEXTURE); + const bool use_textures = !use_local_materials && (compp->getMaterialType() == LLTerrainMaterials::Type::TEXTURE); if (use_textures) { @@ -325,7 +325,7 @@ void LLDrawPoolTerrain::renderFullShaderTextures() } // *TODO: Investigate use of bindFast for PBR terrain textures -void LLDrawPoolTerrain::renderFullShaderPBR(BOOL local_materials) +void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials) { // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 13f031c8e7..d0de68d718 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -80,7 +80,7 @@ protected: void renderFull4TU(); void renderFullShader(); void renderFullShaderTextures(); - void renderFullShaderPBR(BOOL local_materials = false); + void renderFullShaderPBR(bool local_materials = false); void drawLoop(); private: diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 744c55d64a..407256bea2 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -196,7 +196,7 @@ bool LLViewerDynamicTexture::updateAllInstances() if (!bake_target.isComplete()) { llassert(false); - return FALSE; + return false; } llassert(bake_target.getWidth() >= LLPipeline::MAX_BAKE_WIDTH); llassert(bake_target.getHeight() >= LLPipeline::MAX_BAKE_WIDTH); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index cd766aba59..a3dc0a36c9 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1684,10 +1684,10 @@ void LLEnvironment::update(const LLViewerCamera * cam) && (gPipeline.canUseWindLightShaders() || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) { - shaders_iter->mUniformsDirty = TRUE; + shaders_iter->mUniformsDirty = true; if (shaders_iter->mRiggedVariant) { - shaders_iter->mRiggedVariant->mUniformsDirty = TRUE; + shaders_iter->mRiggedVariant->mUniformsDirty = true; } } } diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 780f4451cb..728c4fde18 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -1747,7 +1747,7 @@ bool LLPanelRegionTerrainInfo::sendUpdate() // Prevent applying unsupported alpha blend/double-sided materials if (!validateMaterials()) { - return FALSE; + return false; } // Check if terrain Elevation Ranges are correct diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp index 84dd081a0a..41d5fe5582 100644 --- a/indra/newview/llgltfmaterialpreviewmgr.cpp +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -118,7 +118,7 @@ namespace } else { - img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); } } if (img) @@ -185,7 +185,7 @@ namespace }; // namespace LLGLTFPreviewTexture::LLGLTFPreviewTexture(LLPointer material, S32 width) - : LLViewerDynamicTexture(width, width, 4, EOrder::ORDER_MIDDLE, FALSE) + : LLViewerDynamicTexture(width, width, 4, EOrder::ORDER_MIDDLE, false) , mGLTFMaterial(material) { } @@ -393,7 +393,7 @@ void fixup_shader_constants(LLGLSLShader& shader) const S32 channel = shader.getTextureChannel(LLShaderMgr::DEFERRED_SHADOW0+i); if (channel != -1) { - gGL.getTexUnit(channel)->bind(LLViewerFetchedTexture::sWhiteImagep, TRUE); + gGL.getTexUnit(channel)->bind(LLViewerFetchedTexture::sWhiteImagep, true); } } } @@ -423,7 +423,7 @@ bool LLGLTFPreviewTexture::render() { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - if (!mShouldRender) { return FALSE; } + if (!mShouldRender) { return false; } glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -464,7 +464,7 @@ bool LLGLTFPreviewTexture::render() camera.lookAt(origin, object_position); camera.setAspect(mFullHeight / mFullWidth); const LLRect texture_rect(0, mFullHeight, mFullWidth, 0); - camera.setPerspective(NOT_FOR_SELECTION, texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight(), FALSE, camera.getNear(), MAX_FAR_CLIP*2.f); + camera.setPerspective(NOT_FOR_SELECTION, texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight(), false, camera.getNear(), MAX_FAR_CLIP*2.f); // Generate sphere object on-the-fly. Discard afterwards. (Vertex buffer is // discarded, but the sphere should be cached in LLVolumeMgr.) @@ -554,7 +554,7 @@ bool LLGLTFPreviewTexture::render() gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(false); gSavedSettings.set("RenderLocalLightCount", old_local_light_count); - return TRUE; + return true; } void LLGLTFPreviewTexture::postRender(bool success) diff --git a/indra/newview/llgltfmaterialpreviewmgr.h b/indra/newview/llgltfmaterialpreviewmgr.h index 80f09ece88..f320886157 100644 --- a/indra/newview/llgltfmaterialpreviewmgr.h +++ b/indra/newview/llgltfmaterialpreviewmgr.h @@ -41,7 +41,7 @@ public: static LLPointer create(LLPointer material); bool needsRender() override; - void preRender(bool clear_depth = TRUE) override; + void preRender(bool clear_depth = true) override; bool render() override; void postRender(bool success) override; diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index f95eed44b6..eac1f753b0 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -554,8 +554,8 @@ void LLManipRotate::drag( S32 x, S32 y ) mRotation = dragConstrained(x, y); } - BOOL damped = mSmoothRotate; - mSmoothRotate = FALSE; + bool damped = mSmoothRotate; + mSmoothRotate = false; bool gltf_mode = false; for (LLObjectSelection::iterator iter = mObjectSelection->begin(); diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 9bfe48772a..02f67fe829 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -712,7 +712,7 @@ bool LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) if (selectNode->mIndividualSelection) { // counter-translate child objects if we are moving the root as an individual - object->resetChildrenPosition(old_position_local - new_position_local, TRUE); + object->resetChildrenPosition(old_position_local - new_position_local, true); } } else @@ -759,14 +759,14 @@ bool LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) LLViewerObject* root_object = object->getRootEdit(); new_position_agent -= root_object->getPositionAgent(); new_position_agent = new_position_agent * ~root_object->getRotation(); - object->setPositionParent(new_position_agent, FALSE); + object->setPositionParent(new_position_agent, false); rebuild(object); } if (selectNode->mIndividualSelection) { // counter-translate child objects if we are moving the root as an individual - object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE); + object->resetChildrenPosition(old_position_agent - new_position_agent, true); } } selectNode->mLastPositionLocal = object->getPosition(); @@ -1738,11 +1738,6 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, shader->bind(); } - if (shader) - { - shader->bind(); - } - //draw volume/plane intersections { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 1762d7d5c1..2c01495934 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -73,8 +73,8 @@ void load_exr(const std::string& filename) LLImageGL::generateTextures(1, &texName); gEXRImage = new LLImageGL(texName, 4, GL_TEXTURE_2D, GL_RGB16F, GL_RGB16F, GL_FLOAT, LLTexUnit::TAM_CLAMP); - gEXRImage->setHasMipMaps(TRUE); - gEXRImage->setUseMipMaps(TRUE); + gEXRImage->setHasMipMaps(true); + gEXRImage->setUseMipMaps(true); gEXRImage->setFilteringOption(LLTexUnit::TFO_TRILINEAR); gGL.getTexUnit(0)->bind(gEXRImage); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 546dd0c6b2..a885e6b45e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -481,7 +481,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3 // Place it in the list and tag it. // This will refresh dialogs. - addAsIndividual(object, face, TRUE, gltf_node, gltf_primitive); + addAsIndividual(object, face, true, gltf_node, gltf_primitive); // Stop the object from moving (this anticipates changes on the // simulator in LLTask::userSelect) @@ -1083,7 +1083,7 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, bool undoab // Handle glTF node selection if (gltf_node >= 0) { - nodep->selectGLTFNode(gltf_node, gltf_primitive, TRUE); + nodep->selectGLTFNode(gltf_node, gltf_primitive, true); } diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 7e6c239e89..de57db78cc 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -838,7 +838,7 @@ public: void remove(std::vector& objects); void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true); void removeAll(); - void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = TRUE, S32 gltf_node = -1, S32 gltf_primitive = -1); + void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true, S32 gltf_node = -1, S32 gltf_primitive = -1); void promoteSelectionToRoot(); void demoteSelectionToIndividuals(); diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 9703e2ae27..f58df95365 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -750,7 +750,7 @@ void LLSurfacePatch::updateNormals() calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2); calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2); calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2); - dirty_patch = TRUE; + dirty_patch = true; } // update the middle normals diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index f54b6f799e..cd7012dc6a 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -767,7 +767,7 @@ bool LLViewerCamera::cameraUnderWater() const if (gPipeline.mHeroProbeManager.isMirrorPass()) { // TODO: figure out how to handle this case - return FALSE; + return false; } if (!regionp) diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index dc97beac93..314582c395 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -115,19 +115,19 @@ LLTerrainMaterials::~LLTerrainMaterials() unboost(); } -BOOL LLTerrainMaterials::generateMaterials() +bool LLTerrainMaterials::generateMaterials() { if (texturesReady(true, true)) { - return TRUE; + return true; } if (materialsReady(true, true)) { - return TRUE; + return true; } - return FALSE; + return false; } void LLTerrainMaterials::boost() @@ -639,11 +639,11 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y, const bool use_textures = getMaterialType() != LLTerrainMaterials::Type::PBR; if (use_textures) { - if (!texturesReady(true, true)) { return FALSE; } + if (!texturesReady(true, true)) { return false; } } else { - if (!materialsReady(true, true)) { return FALSE; } + if (!materialsReady(true, true)) { return false; } } for (S32 i = 0; i < ASSET_COUNT; i++) @@ -688,8 +688,8 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y, bool delete_raw_post = false; bool delete_raw_post_emissive = false; - if (!prepare_raw_image(mRawImagesBaseColor[i], false, tex, delete_raw_post)) { return FALSE; } - if (tex_emissive && !prepare_raw_image(mRawImagesEmissive[i], true, tex_emissive, delete_raw_post_emissive)) { return FALSE; } + if (!prepare_raw_image(mRawImagesBaseColor[i], false, tex, delete_raw_post)) { return false; } + if (tex_emissive && !prepare_raw_image(mRawImagesEmissive[i], true, tex_emissive, delete_raw_post_emissive)) { return false; } // tex_emissive can be null, and then will be ignored // In the simplest case, the minimap image is just the base color. diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index cde0e216c3..4ca44d25d4 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -56,7 +56,7 @@ public: COUNT }; - BOOL generateMaterials(); + bool generateMaterials(); void boost(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 42e74c05ed..66797cd127 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -782,7 +782,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (sReflectionProbesEnabled) { - gCubeSnapshot = TRUE; + gCubeSnapshot = true; mReflectionMapManager.initReflectionMaps(); } @@ -1070,7 +1070,7 @@ void LLPipeline::refreshCachedSettings() RenderScreenSpaceReflectionAdaptiveStepMultiplier = gSavedSettings.getF32("RenderScreenSpaceReflectionAdaptiveStepMultiplier"); RenderScreenSpaceReflectionGlossySamples = gSavedSettings.getS32("RenderScreenSpaceReflectionGlossySamples"); RenderBufferVisualization = gSavedSettings.getS32("RenderBufferVisualization"); - if (gSavedSettings.getBOOL("RenderMirrors") != (BOOL)RenderMirrors) + if (gSavedSettings.getBOOL("RenderMirrors") != RenderMirrors) { RenderMirrors = gSavedSettings.getBOOL("RenderMirrors"); LLViewerShaderMgr::instance()->clearShaderCache(); -- cgit v1.3 From 03c4458bdcc6821a3047f93b729d412e274ab9af Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 20 May 2024 13:22:55 -0500 Subject: #1392 GLTF Upload (#1394) * #1392 WIP -- Functional texture upload, stubbed out .bin upload. * #1392 GLTF Upload WIP -- Emulates successful upload Successfully uploads texture Emulates successful .gltf and .bin upload by injecting into local asset cache. Emulates rez from inventory by setting sculpt ID of selected object Currently fails in tinygltf parsing due to missing .bin * Add missing notification * Build fix * #1392 Add boost::json .gltf reading support. * #1392 boost::json GLTF writing prototype * Create gltf/README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * #1392 Add ability to render directly from LL::GLTF::Material * Fix for mac build * Mac build fix * #1392 AssetType and Inventory Type plumbing * #1392 More sane error handling and scheduling of uploads. * #1392 Actually attempt to upload glbin * Mac build fix, upload nudge * Mac build fix * Fix glTF asset uploads to server * Mac build fix (inline not static) * More consistent inline * Add glm, mac nudge. * #1392 For consistency with spec, start using glm over glh:: and LLFoo * Another attempt at placating Mac builds * Another Mac nudge * Mac build take 23 * #1392 Prune LLMatrix4a from GLTF namespace. * #1392 Fix for orientation being off (glm::quat is wxyz, not xyzw) * #1392 WIP -- Actually send the sculpt type and id, nudge readme and alpha rendering * #1392 Working download! * #1394 Add support for GLTFEnabled SimulatorFeature * #1392 Review feedback --------- Co-authored-by: Pepper Linden <3782201+rohvani@users.noreply.github.com> --- autobuild.xml | 42 ++ indra/cmake/GLM.cmake | 7 + indra/llcommon/llassettype.cpp | 2 + indra/llcommon/llassettype.h | 4 +- indra/llfilesystem/lldiskcache.cpp | 2 + indra/llinventory/llinventorytype.cpp | 7 +- indra/llinventory/llinventorytype.h | 4 +- indra/llmath/llmatrix4a.h | 28 + indra/llmath/llvector4a.h | 10 + indra/llmath/llvolume.h | 6 +- indra/llprimitive/CMakeLists.txt | 1 + indra/llprimitive/llgltfmaterial.h | 1 + indra/llui/llui.h | 5 +- indra/newview/app_settings/settings.xml | 11 + indra/newview/gltf/README.md | 156 +++++ indra/newview/gltf/accessor.cpp | 175 ++++- indra/newview/gltf/accessor.h | 38 +- indra/newview/gltf/animation.cpp | 175 ++++- indra/newview/gltf/animation.h | 49 +- indra/newview/gltf/asset.cpp | 725 +++++++++++++++++---- indra/newview/gltf/asset.h | 146 +++-- indra/newview/gltf/buffer_util.h | 608 +++++++++++++++-- indra/newview/gltf/common.h | 66 ++ indra/newview/gltf/primitive.cpp | 79 ++- indra/newview/gltf/primitive.h | 8 +- indra/newview/gltfscenemanager.cpp | 451 +++++++++++-- indra/newview/gltfscenemanager.h | 12 + indra/newview/llfetchedgltfmaterial.cpp | 1 - indra/newview/llimprocessing.cpp | 40 +- indra/newview/llinventorymodel.cpp | 4 +- indra/newview/llviewerassettype.cpp | 2 + indra/newview/llviewerassetupload.cpp | 14 +- indra/newview/llviewermedia.cpp | 8 +- indra/newview/llviewermenu.cpp | 42 +- indra/newview/llviewerobject.cpp | 45 +- indra/newview/llviewerobject.h | 6 + indra/newview/llviewerregion.cpp | 18 +- indra/newview/llvovolume.cpp | 14 +- indra/newview/skins/default/xui/en/menu_viewer.xml | 48 ++ .../newview/skins/default/xui/en/notifications.xml | 22 + 40 files changed, 2680 insertions(+), 402 deletions(-) create mode 100644 indra/cmake/GLM.cmake create mode 100644 indra/newview/gltf/README.md create mode 100644 indra/newview/gltf/common.h (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/autobuild.xml b/autobuild.xml index 2cf5496bd0..85c1e5fbf5 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -739,6 +739,48 @@ description glh - is a platform-indepenedent C++ OpenGL helper library + glm + + canonical_repo + https://github.com/secondlife/3p-glm + copyright + Copyright (c) 2005 - G-Truc Creation + description + OpenGL Mathematics + license + MIT + license_file + LICENSES/glm_license.txt + name + glm + platforms + + common + + archive + + hash + 353ae3a560143732503a8e14499ae12db1e66056 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-glm/releases/download/v1.0.1-r1/glm-v1.0.1-common-9066386153.tar.zst + + name + common + + + source_type + git + vcs_branch + refs/tags/v1.0.1-r1 + vcs_revision + 399cd5ba57a9267a560ce07e50a0f8c5fe3dc66f + vcs_url + git://github.com/secondlife/3p-glm.git + version + v1.0.1 + gstreamer platforms diff --git a/indra/cmake/GLM.cmake b/indra/cmake/GLM.cmake new file mode 100644 index 0000000000..84b155f6c5 --- /dev/null +++ b/indra/cmake/GLM.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- +include(Prebuilt) + +add_library( ll::glm INTERFACE IMPORTED ) + +use_system_binary( glm ) +use_prebuilt_binary(glm) diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index beddfc53cd..d73b64454a 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -97,6 +97,8 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true)); + addEntry(LLAssetType::AT_GLTF, new AssetEntry("GLTF", "gltf", "GLTF", true, true, true)); + addEntry(LLAssetType::AT_GLTF_BIN, new AssetEntry("GLTF_BIN", "glbin", "GLTF binary", true, true, true)); addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false)); diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index e8df8574f7..4a35f666ff 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -128,8 +128,10 @@ public: AT_SETTINGS = 56, // Collection of settings AT_MATERIAL = 57, // Render Material + AT_GLTF = 58, // gltf json document + AT_GLTF_BIN = 59, // gltf binary data - AT_COUNT = 58, + AT_COUNT = 60, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index 54e49ebcb8..da2e960ed3 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -222,6 +222,8 @@ const std::string LLDiskCache::assetTypeToString(LLAssetType::EType at) { LLAssetType::AT_MESH, "MESH" }, { LLAssetType::AT_SETTINGS, "SETTINGS" }, { LLAssetType::AT_MATERIAL, "MATERIAL" }, + { LLAssetType::AT_GLTF, "GLTF" }, + { LLAssetType::AT_GLTF_BIN, "GLTF_BIN" }, { LLAssetType::AT_UNKNOWN, "UNKNOWN" } }; diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index ceda2f3caf..080c2f3ec9 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -83,6 +83,8 @@ LLInventoryDictionary::LLInventoryDictionary() addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION)); addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE)); addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH)); + addEntry(LLInventoryType::IT_GLTF, new InventoryEntry("gltf", "gltf", 1, LLAssetType::AT_GLTF)); + addEntry(LLInventoryType::IT_GLTF_BIN, new InventoryEntry("glbin", "glbin", 1, LLAssetType::AT_GLTF_BIN)); addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET)); addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON)); addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS)); @@ -153,9 +155,12 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // 52 AT_RESERVED_3 LLInventoryType::IT_NONE, // 53 AT_RESERVED_4 LLInventoryType::IT_NONE, // 54 AT_RESERVED_5 + LLInventoryType::IT_NONE, // 55 AT_RESERVED_6 - LLInventoryType::IT_SETTINGS, // 55 AT_SETTINGS <- why doesnt this match the value in llassettype.h? -brad + LLInventoryType::IT_SETTINGS, // 56 AT_SETTINGS LLInventoryType::IT_MATERIAL, // 57 AT_MATERIAL + LLInventoryType::IT_GLTF, // 58 AT_GLTF + LLInventoryType::IT_GLTF_BIN, // 59 AT_GLTF_BIN }; // static diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index a5543814d8..21098002b0 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -66,7 +66,9 @@ public: IT_PERSON = 24, IT_SETTINGS = 25, IT_MATERIAL = 26, - IT_COUNT = 27, + IT_GLTF = 27, + IT_GLTF_BIN = 28, + IT_COUNT = 29, IT_UNKNOWN = 255, IT_NONE = -1 diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 12fc6d570a..33a47bc2de 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -46,6 +46,34 @@ public: loadu(val); } + explicit LLMatrix4a(const F32* val) + { + loadu(val); + } + + static const LLMatrix4a& identity() + { + static const F32 v[] = + { 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + static LLMatrix4a identity_mat(v); + + return identity_mat; + } + + bool operator==(const LLMatrix4a& rhs) const + { + return mMatrix[0] == rhs.mMatrix[0] && mMatrix[1] == rhs.mMatrix[1] && mMatrix[2] == rhs.mMatrix[2] && mMatrix[3] == rhs.mMatrix[3]; + } + + bool operator!=(const LLMatrix4a& rhs) const + { + return !(*this == rhs); + } + inline F32* getF32ptr() { return (F32*) &mMatrix; diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 53c8f604f6..3e7c0d54fb 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -117,6 +117,16 @@ public: mQ = q; } + bool operator==(const LLVector4a& rhs) const + { + return equals4(rhs); + } + + bool operator!=(const LLVector4a& rhs) const + { + return !(*this == rhs); + } + //////////////////////////////////// // LOAD/STORE //////////////////////////////////// diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 98ad456396..75aabe0b90 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -190,11 +190,13 @@ constexpr U8 LL_SCULPT_TYPE_TORUS = 2; constexpr U8 LL_SCULPT_TYPE_PLANE = 3; constexpr U8 LL_SCULPT_TYPE_CYLINDER = 4; constexpr U8 LL_SCULPT_TYPE_MESH = 5; +constexpr U8 LL_SCULPT_TYPE_GLTF = 6; +constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_GLTF; + constexpr U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | - LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; + LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH | LL_SCULPT_TYPE_GLTF; // for value checks, assign new value after adding new types -constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; constexpr U8 LL_SCULPT_FLAG_INVERT = 64; constexpr U8 LL_SCULPT_FLAG_MIRROR = 128; diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index 2bd1edaacc..972f502aa9 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -8,6 +8,7 @@ include(LLCoreHttp) include(LLPhysicsExtensions) include(LLPrimitive) include(GLH) +include(GLM) include(TinyGLTF) set(llprimitive_SOURCE_FILES diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 23a39593cf..67b22f56e2 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -273,6 +273,7 @@ public: F32 mAlphaCutoff; AlphaMode mAlphaMode; + bool mDoubleSided = false; // Override specific flags for state that can't use off-by-epsilon or UUID diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 86b23c8c93..23df0c11e8 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -77,7 +77,10 @@ enum EDragAndDropType DAD_PERSON = 17, DAD_SETTINGS = 18, DAD_MATERIAL = 19, - DAD_COUNT = 20, // number of types in this enum + DAD_GLTF = 20, + DAD_GLTF_BIN = 21, + + DAD_COUNT = 22, // number of types in this enum }; // Reasons for drags to be denied. diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c3f9a64fd6..34c1c07cd3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -17955,5 +17955,16 @@ Value 0 + GLTFEnabled + + Comment + Enable GLTF support. Set by SimulatorFeatures + Persist + 0 + Type + Boolean + Value + 0 + diff --git a/indra/newview/gltf/README.md b/indra/newview/gltf/README.md new file mode 100644 index 0000000000..8e7df0a439 --- /dev/null +++ b/indra/newview/gltf/README.md @@ -0,0 +1,156 @@ +# Linden Lab GLTF Implementation + +Currently in prototype stage. Much functionality is missing (blend shapes, +multiple texture coordinates, etc). + +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. + +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 +LL::GLTF namespace. + +The implementation serves both the client and the server. + +## Design Principles + +- The implementation MUST be capable of round-trip serialization with no data loss beyond F64 to F32 conversions. +- The implementation MUST use the same indexing scheme as the GLTF specification. Do not store pointers where the +- GLTF specification stores indices, store indices. +- 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. +- 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. + +## Loading, Copying, and Serialization +Each class should provide two functions (Primitive shown for example): + +``` +// Serialize to the provided json object. +// "obj" should be "this" in json form on return +// Do not serialize default values +void serialize(boost::json::object& obj) const; + +// Initialize from a provided json value +const Primitive& operator=(const Value& src); +``` + +"serialize" implementations should use "write": + +``` +void Primitive::serialize(boost::json::object& dst) const +{ + write(mMaterial, "material", dst, -1); + write(mMode, "mode", dst, TINYGLTF_MODE_TRIANGLES); + write(mIndices, "indices", dst, INVALID_INDEX); + write(mAttributes, "attributes", dst); +} +``` + +And operator= implementations should use "copy": + +``` +const Primitive& Primitive::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "material", mMaterial); + copy(src, "mode", mMode); + copy(src, "indices", mIndices); + copy(src, "attributes", mAttributes); + + mGLMode = gltf_mode_to_gl_mode(mMode); + } + return *this; +} +``` + +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". + +When reading string constants from GLTF json (i.e. "OPAQUE", "TRIANGLES"), these +strings should be converted to enums inside operator=. It is permissible to +store the original strings during prototyping to aid in development, but eventually +we'll purge these strings from the implementation. However, implementations MUST +preserve any and all "name" members. + +"write" and "copy" implementations MUST be stored in buffer_util.h. +As implementers encounter new data types, you'll see compiler errors +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): + +``` +// vec3 +template<> +inline bool copy(const Value& src, vec3& dst) +{ + if (src.is_array()) + { + const boost::json::array& arr = src.as_array(); + if (arr.size() == 3) + { + if (arr[0].is_double() && + arr[1].is_double() && + arr[2].is_double()) + { + dst = vec3(arr[0].get_double(), arr[1].get_double(), arr[2].get_double()); + } + return true; + } + } + return false; +} + +template<> +inline bool write(const vec3& src, Value& dst) +{ + dst = boost::json::array(); + boost::json::array& arr = dst.as_array(); + arr.resize(3); + arr[0] = src.x; + arr[1] = src.y; + arr[2] = src.z; + return true; +} + +``` + +"write" MUST return true if ANY data was written +"copy" MUST return true if ANY data was copied + +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 +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 +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 +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 +indicates a place where we're missing "is_foo" checks. They are gold. Do not +bury them with an exception handler. + +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 +our existing implementations. + +### JSON Serialization ### + + + +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 +solution. Eventually the implementation should rely solely on boost::json for reading and writing .gltf +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. +The server MUST reject any data that violates this requirement. + +Clients MUST remove any Images from Buffers prior to upload to the server. +Servers MAY reject Assets that contain Buffers with unreferenced data. + +... to be continued. + + + diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 9bfdc2afa6..369ff4f240 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -27,8 +27,79 @@ #include "../llviewerprecompiledheaders.h" #include "asset.h" +#include "buffer_util.h" using namespace LL::GLTF; +using namespace boost::json; + +namespace LL +{ + namespace GLTF + { + Accessor::Type gltf_type_to_enum(const std::string& type) + { + if (type == "SCALAR") + { + return Accessor::Type::SCALAR; + } + else if (type == "VEC2") + { + return Accessor::Type::VEC2; + } + else if (type == "VEC3") + { + return Accessor::Type::VEC3; + } + else if (type == "VEC4") + { + return Accessor::Type::VEC4; + } + else if (type == "MAT2") + { + return Accessor::Type::MAT2; + } + else if (type == "MAT3") + { + return Accessor::Type::MAT3; + } + else if (type == "MAT4") + { + return Accessor::Type::MAT4; + } + + LL_WARNS("GLTF") << "Unknown accessor type: " << type << LL_ENDL; + llassert(false); + + return Accessor::Type::SCALAR; + } + + std::string enum_to_gltf_type(Accessor::Type type) + { + switch (type) + { + case Accessor::Type::SCALAR: + return "SCALAR"; + case Accessor::Type::VEC2: + return "VEC2"; + case Accessor::Type::VEC3: + return "VEC3"; + case Accessor::Type::VEC4: + return "VEC4"; + case Accessor::Type::MAT2: + return "MAT2"; + case Accessor::Type::MAT3: + return "MAT3"; + case Accessor::Type::MAT4: + return "MAT4"; + } + + LL_WARNS("GLTF") << "Unknown accessor type: " << (S32)type << LL_ENDL; + llassert(false); + + return "SCALAR"; + } + } +} void Buffer::erase(Asset& asset, S32 offset, S32 length) { @@ -48,6 +119,27 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length) } } +void Buffer::serialize(object& dst) const +{ + write(mName, "name", dst); + write(mUri, "uri", dst); + write_always(mByteLength, "byteLength", dst); +}; + +const Buffer& Buffer::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "uri", mUri); + + // NOTE: DO NOT attempt to handle the uri here. + // The uri is a reference to a file that is not loaded until + // after the json document is parsed + } + return *this; +} + const Buffer& Buffer::operator=(const tinygltf::Buffer& src) { mData = src.data; @@ -56,6 +148,31 @@ const Buffer& Buffer::operator=(const tinygltf::Buffer& src) return *this; } + +void BufferView::serialize(object& dst) const +{ + write_always(mBuffer, "buffer", dst); + write_always(mByteLength, "byteLength", dst); + write(mByteOffset, "byteOffset", dst, 0); + write(mByteStride, "byteStride", dst, 0); + write(mTarget, "target", dst, -1); + write(mName, "name", dst); +} + +const BufferView& BufferView::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "buffer", mBuffer); + copy(src, "byteLength", mByteLength); + copy(src, "byteOffset", mByteOffset); + copy(src, "byteStride", mByteStride); + copy(src, "target", mTarget); + copy(src, "name", mName); + } + return *this; +} + const BufferView& BufferView::operator=(const tinygltf::BufferView& src) { mBuffer = src.buffer; @@ -67,13 +184,69 @@ const BufferView& BufferView::operator=(const tinygltf::BufferView& src) 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 +{ + write(mName, "name", dst); + write(mBufferView, "bufferView", dst, INVALID_INDEX); + write(mByteOffset, "byteOffset", dst, 0); + write_always(mComponentType, "componentType", dst); + write_always(mCount, "count", dst); + write_always(enum_to_gltf_type(mType), "type", dst); + write(mNormalized, "normalized", dst, false); + write(mMax, "max", dst); + write(mMin, "min", dst); +} + +const Accessor& Accessor::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "bufferView", mBufferView); + copy(src, "byteOffset", mByteOffset); + copy(src, "componentType", mComponentType); + copy(src, "count", mCount); + copy(src, "type", mType); + copy(src, "normalized", mNormalized); + copy(src, "max", mMax); + copy(src, "min", mMin); + } + return *this; +} + const Accessor& Accessor::operator=(const tinygltf::Accessor& src) { mBufferView = src.bufferView; mByteOffset = src.byteOffset; mComponentType = src.componentType; mCount = src.count; - mType = src.type; + mType = tinygltf_type_to_enum(src.type); mNormalized = src.normalized; mName = src.name; mMax = src.maxValues; diff --git a/indra/newview/gltf/accessor.h b/indra/newview/gltf/accessor.h index 6849cd8609..3bbc5216bd 100644 --- a/indra/newview/gltf/accessor.h +++ b/indra/newview/gltf/accessor.h @@ -28,14 +28,15 @@ #include "../lltinygltfhelper.h" #include "llstrider.h" +#include "boost/json.hpp" + +#include "common.h" // LL GLTF Implementation namespace LL { namespace GLTF { - class Asset; - constexpr S32 INVALID_INDEX = -1; class Buffer @@ -44,11 +45,14 @@ namespace LL std::vector mData; std::string mName; std::string mUri; + S32 mByteLength = 0; // 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); + void serialize(boost::json::object& obj) const; + const Buffer& operator=(const Value& value); const Buffer& operator=(const tinygltf::Buffer& src); }; @@ -56,25 +60,25 @@ namespace LL { public: S32 mBuffer = INVALID_INDEX; - S32 mByteLength; - S32 mByteOffset; - S32 mByteStride; - S32 mTarget; - S32 mComponentType; + S32 mByteLength = 0; + S32 mByteOffset = 0; + S32 mByteStride = 0; + S32 mTarget = -1; std::string mName; + void serialize(boost::json::object& obj) const; + const BufferView& operator=(const Value& value); const BufferView& operator=(const tinygltf::BufferView& src); - }; class Accessor { public: S32 mBufferView = INVALID_INDEX; - S32 mByteOffset; - S32 mComponentType; - S32 mCount; + S32 mByteOffset = 0; + S32 mComponentType = 0; + S32 mCount = 0; std::vector mMax; std::vector mMin; @@ -89,11 +93,19 @@ namespace LL MAT4 = TINYGLTF_TYPE_MAT4 }; - S32 mType; - bool mNormalized; + Type mType = Type::SCALAR; + bool mNormalized = false; std::string mName; + void serialize(boost::json::object& obj) const; + const Accessor& operator=(const Value& value); const Accessor& operator=(const tinygltf::Accessor& src); }; + + // convert from "SCALAR", "VEC2", etc to Accessor::Type + Accessor::Type gltf_type_to_enum(const std::string& type); + + // convert from Accessor::Type to "SCALAR", "VEC2", etc + std::string enum_to_gltf_type(Accessor::Type type); } } diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp index da6d02b356..8a542fb315 100644 --- a/indra/newview/gltf/animation.cpp +++ b/indra/newview/gltf/animation.cpp @@ -30,6 +30,7 @@ #include "buffer_util.h" using namespace LL::GLTF; +using namespace boost::json; void Animation::allocateGLResources(Asset& asset) { @@ -84,7 +85,6 @@ void Animation::apply(Asset& asset, float time) } }; - void Animation::Sampler::allocateGLResources(Asset& asset) { Accessor& accessor = asset.mAccessors[mInput]; @@ -97,8 +97,96 @@ void Animation::Sampler::allocateGLResources(Asset& asset) copy(asset, accessor, frame_times); } + +void Animation::Sampler::serialize(object& obj) const +{ + write(mInput, "input", obj, INVALID_INDEX); + write(mOutput, "output", obj, INVALID_INDEX); + write(mInterpolation, "interpolation", obj, std::string("LINEAR")); + write(mMinTime, "min_time", obj); + write(mMaxTime, "max_time", obj); +} + +const Animation::Sampler& Animation::Sampler::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "input", mInput); + copy(src, "output", mOutput); + copy(src, "interpolation", mInterpolation); + copy(src, "min_time", mMinTime); + copy(src, "max_time", mMaxTime); + } + 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 +{ + return mNode == rhs.mNode && mPath == rhs.mPath; +} + +bool Animation::Channel::Target::operator!=(const Channel::Target& rhs) const +{ + return !(*this == rhs); +} + +void Animation::Channel::Target::serialize(object& obj) const +{ + write(mNode, "node", obj, INVALID_INDEX); + write(mPath, "path", obj); +} + +const Animation::Channel::Target& Animation::Channel::Target::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "node", mNode); + copy(src, "path", mPath); + } + return *this; +} + +void Animation::Channel::serialize(object& obj) const +{ + write(mSampler, "sampler", obj, INVALID_INDEX); + write(mTarget, "target", obj); +} + +const Animation::Channel& Animation::Channel::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "sampler", mSampler); + copy(src, "target", mTarget); + } + 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) { + LL_PROFILE_ZONE_SCOPED; + if (time < mMinTime) { frameIndex = 0; @@ -158,13 +246,11 @@ void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time) else { // interpolate - LLQuaternion q0(mRotations[frameIndex].get_value()); - LLQuaternion q1(mRotations[frameIndex + 1].get_value()); + quat qf = glm::slerp(mRotations[frameIndex], mRotations[frameIndex + 1], t); - LLQuaternion qf = slerp(t, q0, q1); + qf = glm::normalize(qf); - qf.normalize(); - node.setRotation(glh::quaternionf(qf.mQ)); + node.setRotation(qf); } } @@ -191,10 +277,10 @@ void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 ti else { // interpolate - const glh::vec3f& v0 = mTranslations[frameIndex]; - const glh::vec3f& v1 = mTranslations[frameIndex + 1]; + const vec3& v0 = mTranslations[frameIndex]; + const vec3& v1 = mTranslations[frameIndex + 1]; - glh::vec3f vf = v0 + t * (v1 - v0); + vec3 vf = v0 + t * (v1 - v0); node.setTranslation(vf); } @@ -223,15 +309,61 @@ void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time) else { // interpolate - const glh::vec3f& v0 = mScales[frameIndex]; - const glh::vec3f& v1 = mScales[frameIndex + 1]; + const vec3& v0 = mScales[frameIndex]; + const vec3& v1 = mScales[frameIndex + 1]; - glh::vec3f vf = v0 + t * (v1 - v0); + vec3 vf = v0 + t * (v1 - v0); node.setScale(vf); } } +void Animation::serialize(object& obj) const +{ + write(mName, "name", obj); + write(mSamplers, "samplers", obj); + + std::vector channels; + channels.insert(channels.end(), mRotationChannels.begin(), mRotationChannels.end()); + channels.insert(channels.end(), mTranslationChannels.begin(), mTranslationChannels.end()); + channels.insert(channels.end(), mScaleChannels.begin(), mScaleChannels.end()); + + write(channels, "channels", obj); +} + +const Animation& Animation::operator=(const Value& src) +{ + if (src.is_object()) + { + const object& obj = src.as_object(); + + copy(obj, "name", mName); + copy(obj, "samplers", mSamplers); + + // make a temporory copy of generic channels + std::vector channels; + copy(obj, "channels", channels); + + // break up into channel specific implementations + for (auto& channel: channels) + { + if (channel.mTarget.mPath == "rotation") + { + mRotationChannels.push_back(channel); + } + else if (channel.mTarget.mPath == "translation") + { + mTranslationChannels.push_back(channel); + } + else if (channel.mTarget.mPath == "scale") + { + mScaleChannels.push_back(channel); + } + } + } + return *this; +} + const Animation& Animation::operator=(const tinygltf::Animation& src) { mName = src.name; @@ -275,6 +407,18 @@ void Skin::allocateGLResources(Asset& asset) } } +const Skin& Skin::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "skeleton", mSkeleton); + copy(src, "inverseBindMatrices", mInverseBindMatrices); + copy(src, "joints", mJoints); + } + return *this; +} + const Skin& Skin::operator=(const tinygltf::Skin& src) { mName = src.name; @@ -285,3 +429,10 @@ const Skin& Skin::operator=(const tinygltf::Skin& src) return *this; } +void Skin::serialize(object& obj) const +{ + write(mInverseBindMatrices, "inverseBindMatrices", obj, INVALID_INDEX); + write(mJoints, "joints", obj); + write(mName, "name", obj); + write(mSkeleton, "skeleton", obj, INVALID_INDEX); +} diff --git a/indra/newview/gltf/animation.h b/indra/newview/gltf/animation.h index cc2045ebb2..53c11d4669 100644 --- a/indra/newview/gltf/animation.h +++ b/indra/newview/gltf/animation.h @@ -27,7 +27,6 @@ */ #include "accessor.h" - // LL GLTF Implementation namespace LL { @@ -52,14 +51,10 @@ namespace LL void allocateGLResources(Asset& asset); - const Sampler& operator=(const tinygltf::AnimationSampler& src) - { - mInput = src.input; - mOutput = src.output; - mInterpolation = src.interpolation; - - return *this; - } + void serialize(boost::json::object& dst) const; + const Sampler& operator=(const Value& value); + const Sampler& operator=(const tinygltf::AnimationSampler& src); + // get the frame index and time for the specified time // asset -- the asset to reference for Accessors @@ -77,27 +72,29 @@ namespace LL public: S32 mNode = INVALID_INDEX; std::string mPath; + + bool operator==(const Target& other) const; + bool operator!=(const Target& other) const; + + void serialize(boost::json::object& dst) const; + const Target& operator=(const Value& value); }; S32 mSampler = INVALID_INDEX; Target mTarget; - const Channel& operator=(const tinygltf::AnimationChannel& src) - { - mSampler = src.sampler; - - mTarget.mNode = src.target_node; - mTarget.mPath = src.target_path; - - return *this; - } - + void serialize(boost::json::object& dst) const; + const Channel& operator=(const Value& value); + const Channel& operator=(const tinygltf::AnimationChannel& src); }; class RotationChannel : public Channel { public: - std::vector mRotations; + RotationChannel() = default; + RotationChannel(const Channel& channel) : Channel(channel) {} + + std::vector mRotations; const RotationChannel& operator=(const tinygltf::AnimationChannel& src) { @@ -116,7 +113,10 @@ namespace LL class TranslationChannel : public Channel { public: - std::vector mTranslations; + TranslationChannel() = default; + TranslationChannel(const Channel& channel) : Channel(channel) {} + + std::vector mTranslations; const TranslationChannel& operator=(const tinygltf::AnimationChannel& src) { @@ -135,7 +135,10 @@ namespace LL class ScaleChannel : public Channel { public: - std::vector mScales; + ScaleChannel() = default; + ScaleChannel(const Channel& channel) : Channel(channel) {} + + std::vector mScales; const ScaleChannel& operator=(const tinygltf::AnimationChannel& src) { @@ -165,6 +168,8 @@ namespace LL std::vector mTranslationChannels; std::vector mScaleChannels; + void serialize(boost::json::object& dst) const; + const Animation& operator=(const Value& value); const Animation& operator=(const tinygltf::Animation& src); void allocateGLResources(Asset& asset); diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 5f2217a075..c64d48662c 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -31,13 +31,51 @@ #include "../llviewershadermgr.h" #include "../llviewercontrol.h" #include "../llviewertexturelist.h" +#include "../pipeline.h" +#include "buffer_util.h" using namespace LL::GLTF; +using namespace boost::json; namespace LL { namespace GLTF { + Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode) + { + if (alpha_mode == "OPAQUE") + { + return Material::AlphaMode::OPAQUE; + } + else if (alpha_mode == "MASK") + { + return Material::AlphaMode::MASK; + } + else if (alpha_mode == "BLEND") + { + return Material::AlphaMode::BLEND; + } + else + { + return Material::AlphaMode::OPAQUE; + } + } + + std::string enum_to_gltf_alpha_mode(Material::AlphaMode alpha_mode) + { + switch (alpha_mode) + { + case Material::AlphaMode::OPAQUE: + return "OPAQUE"; + case Material::AlphaMode::MASK: + return "MASK"; + case Material::AlphaMode::BLEND: + return "BLEND"; + default: + return "OPAQUE"; + } + } + template void copy(const std::vector& src, std::vector& dst) { @@ -45,49 +83,48 @@ namespace LL 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()) + if (src.mMatrix != glm::identity()) { dst.matrix.resize(16); + const F32* m = glm::value_ptr(src.mMatrix); for (U32 i = 0; i < 16; ++i) { - dst.matrix[i] = src.mMatrix.getF32ptr()[i]; + dst.matrix[i] = m[i]; } } } else if (src.mTRSValid) { - if (!src.mRotation.equals(glh::quaternionf::identity(), FLT_EPSILON)) + if (src.mRotation != glm::identity()) { dst.rotation.resize(4); - for (U32 i = 0; i < 4; ++i) - { - dst.rotation[i] = src.mRotation.get_value()[i]; - } - } + dst.rotation[0] = src.mRotation.x; + dst.rotation[1] = src.mRotation.y; + dst.rotation[2] = src.mRotation.z; + dst.rotation[3] = src.mRotation.w; + } - if (src.mTranslation != glh::vec3f(0.f, 0.f, 0.f)) + if (src.mTranslation != vec3(0.f, 0.f, 0.f)) { dst.translation.resize(3); - for (U32 i = 0; i < 3; ++i) - { - dst.translation[i] = src.mTranslation.v[i]; - } + dst.translation[0] = src.mTranslation.x; + dst.translation[1] = src.mTranslation.y; + dst.translation[2] = src.mTranslation.z; } - if (src.mScale != glh::vec3f(1.f, 1.f, 1.f)) + if (src.mScale != vec3(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.scale[0] = src.mScale.x; + dst.scale[1] = src.mScale.y; + dst.scale[2] = src.mScale.z; } } @@ -143,7 +180,7 @@ namespace LL 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] }; + dst.baseColorFactor = { src.mBaseColorFactor.r, src.mBaseColorFactor.g, src.mBaseColorFactor.b, src.mBaseColorFactor.a }; copy(src.mBaseColorTexture, dst.baseColorTexture); dst.metallicFactor = src.mMetallicFactor; dst.roughnessFactor = src.mRoughnessFactor; @@ -154,7 +191,7 @@ namespace LL { material.name = src.mName; - material.emissiveFactor = { src.mEmissiveFactor.v[0], src.mEmissiveFactor.v[1], src.mEmissiveFactor.v[2] }; + material.emissiveFactor = { src.mEmissiveFactor.r, src.mEmissiveFactor.g, src.mEmissiveFactor.b }; copy(src.mPbrMetallicRoughness, material.pbrMetallicRoughness); copy(src.mNormalTexture, material.normalTexture); copy(src.mEmissiveTexture, material.emissiveTexture); @@ -193,7 +230,7 @@ namespace LL accessor.maxValues = src.mMax; accessor.count = src.mCount; - accessor.type = src.mType; + accessor.type = (S32) src.mType; accessor.normalized = src.mNormalized; accessor.name = src.mName; } @@ -278,7 +315,8 @@ namespace LL dst.asset.version = src.mVersion; dst.asset.minVersion = src.mMinVersion; dst.asset.generator = "Linden Lab Experimental GLTF Export"; - dst.asset.extras = src.mExtras; + + // NOTE: extras are lost in the conversion for now copy(src.mScenes, dst.scenes); copy(src.mNodes, dst.nodes); @@ -297,8 +335,8 @@ namespace LL } void Scene::updateTransforms(Asset& asset) { - LLMatrix4a identity; - identity.setIdentity(); + mat4 identity = glm::identity(); + for (auto& nodeIndex : mNodes) { Node& node = asset.mNodes[nodeIndex]; @@ -306,7 +344,7 @@ void Scene::updateTransforms(Asset& asset) } } -void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) +void Scene::updateRenderTransforms(Asset& asset, const mat4& modelview) { for (auto& nodeIndex : mNodes) { @@ -315,9 +353,9 @@ void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) } } -void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) +void Node::updateRenderTransforms(Asset& asset, const mat4& modelview) { - matMul(mMatrix, modelview, mRenderMatrix); + mRenderMatrix = modelview * mMatrix; for (auto& childIndex : mChildren) { @@ -326,13 +364,12 @@ void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) } } -LLMatrix4a inverse(const LLMatrix4a& mat); - -void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix) +void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); - matMul(mMatrix, parentMatrix, mAssetMatrix); - mAssetMatrixInv = inverse(mAssetMatrix); + mAssetMatrix = parentMatrix * mMatrix; + + mAssetMatrixInv = glm::inverse(mAssetMatrix); S32 my_index = this - &asset.mNodes[0]; @@ -352,26 +389,13 @@ void Asset::updateTransforms() } } -void Asset::updateRenderTransforms(const LLMatrix4a& modelview) +void Asset::updateRenderTransforms(const mat4& modelview) { -#if 0 - // traverse hierarchy and update render transforms from scratch - for (auto& scene : mScenes) - { - scene.updateRenderTransforms(*this, modelview); - } -#else // use mAssetMatrix to update render transforms from node list for (auto& node : mNodes) { - //if (node.mMesh != INVALID_INDEX) - { - matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); - } + node.mRenderMatrix = modelview * node.mAssetMatrix; } - -#endif - } S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, @@ -398,9 +422,11 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, bool newHit = false; + LLMatrix4a ami; + ami.loadu(glm::value_ptr(node.mAssetMatrixInv)); // transform start and end to this node's local space - node.mAssetMatrixInv.affineTransform(start, local_start); - node.mAssetMatrixInv.affineTransform(asset_end, local_end); + ami.affineTransform(start, local_start); + ami.affineTransform(asset_end, local_end); Mesh& mesh = mMeshes[node.mMesh]; for (auto& primitive : mesh.mPrimitives) @@ -423,8 +449,10 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, if (newHit) { + LLMatrix4a am; + am.loadu(glm::value_ptr(node.mAssetMatrix)); // shorten line segment on hit - node.mAssetMatrix.affineTransform(p, asset_end); + am.affineTransform(p, asset_end); // transform results back to asset space if (intersection) @@ -434,12 +462,10 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, if (normal || tangent) { - LLMatrix4 normalMatrix(node.mAssetMatrixInv.getF32ptr()); - - normalMatrix.transpose(); + mat4 normalMatrix = glm::transpose(node.mAssetMatrixInv); LLMatrix4a norm_mat; - norm_mat.loadu((F32*)normalMatrix.mMatrix); + norm_mat.loadu(glm::value_ptr(normalMatrix)); if (normal) { @@ -481,22 +507,7 @@ void Node::makeMatrixValid() { if (!mMatrixValid && mTRSValid) { - glh::matrix4f rot; - mRotation.get_value(rot); - - glh::matrix4f trans; - trans.set_translate(mTranslation); - - glh::matrix4f sc; - sc.set_scale(mScale); - - glh::matrix4f t; - //t = sc * rot * trans; - //t = trans * rot * sc; // best so far, still wrong on negative scale - //t = sc * trans * rot; - t = trans * sc * rot; - - mMatrix.loadu(t.m); + mMatrix = glm::recompose(mScale, mRotation, mTranslation, vec3(0,0,0), vec4(0,0,0,1)); mMatrixValid = true; } @@ -507,43 +518,72 @@ void Node::makeTRSValid() { if (!mTRSValid && mMatrixValid) { - glh::matrix4f t(mMatrix.getF32ptr()); - - glh::vec4f p = t.get_column(3); - mTranslation.set_value(p.v[0], p.v[1], p.v[2]); - - mScale.set_value(t.get_column(0).length(), t.get_column(1).length(), t.get_column(2).length()); - mRotation.set_value(t); + vec3 skew; + vec4 perspective; + glm::decompose(mMatrix, mScale, mRotation, mTranslation, skew, perspective); + mTRSValid = true; } llassert(mTRSValid); } -void Node::setRotation(const glh::quaternionf& q) +void Node::setRotation(const quat& q) { makeTRSValid(); mRotation = q; mMatrixValid = false; } -void Node::setTranslation(const glh::vec3f& t) +void Node::setTranslation(const vec3& t) { makeTRSValid(); mTranslation = t; mMatrixValid = false; } -void Node::setScale(const glh::vec3f& s) +void Node::setScale(const vec3& s) { makeTRSValid(); mScale = s; mMatrixValid = false; } +void Node::serialize(object& dst) const +{ + write(mName, "name", dst); + write(mMatrix, "matrix", dst, glm::identity()); + write(mRotation, "rotation", dst); + write(mTranslation, "translation", dst); + write(mScale, "scale", dst, vec3(1.f,1.f,1.f)); + write(mChildren, "children", dst); + write(mMesh, "mesh", dst, INVALID_INDEX); + write(mSkin, "skin", dst, INVALID_INDEX); +} + +const Node& Node::operator=(const Value& src) +{ + copy(src, "name", mName); + mMatrixValid = copy(src, "matrix", mMatrix); + + copy(src, "rotation", mRotation); + copy(src, "translation", mTranslation); + copy(src, "scale", mScale); + copy(src, "children", mChildren); + copy(src, "mesh", mMesh); + copy(src, "skin", mSkin); + + if (!mMatrixValid) + { + mTRSValid = true; + } + + return *this; +} + const Node& Node::operator=(const tinygltf::Node& src) { - F32* dstMatrix = mMatrix.getF32ptr(); + F32* dstMatrix = glm::value_ptr(mMatrix); if (src.matrix.size() == 16) { @@ -560,22 +600,21 @@ const Node& Node::operator=(const tinygltf::Node& src) // node has rotation/translation/scale, convert to matrix if (src.rotation.size() == 4) { - mRotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]); + mRotation = quat((F32)src.rotation[3], (F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2]); } if (src.translation.size() == 3) { - mTranslation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); + mTranslation = vec3((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); } - glh::vec3f scale; if (src.scale.size() == 3) { - mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); + mScale = vec3((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); } else { - mScale.set_value(1.f, 1.f, 1.f); + mScale = vec3(1.f, 1.f, 1.f); } mTRSValid = true; @@ -583,7 +622,7 @@ const Node& Node::operator=(const tinygltf::Node& src) else { // node specifies no transformation, set to identity - mMatrix.setIdentity(); + mMatrix = glm::identity(); mMatrixValid = true; } @@ -595,6 +634,50 @@ const Node& Node::operator=(const tinygltf::Node& src) return *this; } +void Image::serialize(object& dst) const +{ + write(mUri, "uri", dst); + write(mMimeType, "mimeType", dst); + write(mBufferView, "bufferView", dst, INVALID_INDEX); + write(mName, "name", dst); + write(mWidth, "width", dst, -1); + write(mHeight, "height", dst, -1); + write(mComponent, "component", dst, -1); + write(mBits, "bits", dst, -1); + write(mPixelType, "pixelType", dst, -1); +} + +const Image& Image::operator=(const Value& src) +{ + copy(src, "uri", mUri); + copy(src, "mimeType", mMimeType); + copy(src, "bufferView", mBufferView); + copy(src, "name", mName); + copy(src, "width", mWidth); + copy(src, "height", mHeight); + copy(src, "component", mComponent); + copy(src, "bits", mBits); + copy(src, "pixelType", mPixelType); + + return *this; +} + +const Image& Image::operator=(const tinygltf::Image& src) +{ + mName = src.name; + mWidth = src.width; + mHeight = src.height; + mComponent = src.component; + mBits = src.bits; + mPixelType = src.pixel_type; + mUri = src.uri; + mBufferView = src.bufferView; + mMimeType = src.mimeType; + mData = src.image; + return *this; +} + + void Asset::render(bool opaque, bool rigged) { if (rigged) @@ -623,7 +706,6 @@ void Asset::render(bool opaque, bool rigged) continue; } - if (node.mMesh != INVALID_INDEX) { Mesh& mesh = mMeshes[node.mMesh]; @@ -631,19 +713,28 @@ void Asset::render(bool opaque, bool rigged) { if (!rigged) { - gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); } bool cull = true; if (primitive.mMaterial != INVALID_INDEX) { Material& material = mMaterials[primitive.mMaterial]; + bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND; - if ((material.mMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque) + if (mat_opaque != opaque) { continue; } - material.mMaterial->bind(); - cull = !material.mMaterial->mDoubleSided; + + if (mMaterials[primitive.mMaterial].mMaterial.notNull()) + { + material.mMaterial->bind(); + } + else + { + material.bind(*this); + } + cull = !material.mDoubleSided; } else { @@ -709,11 +800,16 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod image.allocateGLResources(); } + // do materials before meshes as meshes may depend on materials - for (U32 i = 0; i < mMaterials.size(); ++i) + if (!filename.empty()) { - mMaterials[i].allocateGLResources(*this); - LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + for (U32 i = 0; i < mMaterials.size(); ++i) + { + // HACK: local preview mode, load material from model for now + mMaterials[i].allocateGLResources(*this); + LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + } } for (auto& mesh : mMeshes) @@ -732,16 +828,26 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod } } +Asset::Asset(const tinygltf::Model& src) +{ + *this = src; +} + +Asset::Asset(const Value& src) +{ + *this = src; +} + 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; + + // note: extras are lost in the conversion for now mDefaultScene = src.defaultScene; - mScenes.resize(src.scenes.size()); for (U32 i = 0; i < src.scenes.size(); ++i) @@ -818,11 +924,69 @@ const Asset& Asset::operator=(const tinygltf::Model& src) return *this; } +const Asset& Asset::operator=(const Value& src) +{ + if (src.is_object()) + { + const object& obj = src.as_object(); + + const auto it = obj.find("asset"); + + if (it != obj.end()) + { + const Value& asset = it->value(); + + copy(asset, "version", mVersion); + copy(asset, "minVersion", mMinVersion); + copy(asset, "generator", mGenerator); + copy(asset, "copyright", mCopyright); + copy(asset, "extras", mExtras); + } + + copy(obj, "defaultScene", mDefaultScene); + copy(obj, "scenes", mScenes); + copy(obj, "nodes", mNodes); + copy(obj, "meshes", mMeshes); + copy(obj, "materials", mMaterials); + copy(obj, "buffers", mBuffers); + copy(obj, "bufferViews", mBufferViews); + copy(obj, "textures", mTextures); + copy(obj, "samplers", mSamplers); + copy(obj, "images", mImages); + copy(obj, "accessors", mAccessors); + copy(obj, "animations", mAnimations); + copy(obj, "skins", mSkins); + } + + return *this; +} + void Asset::save(tinygltf::Model& dst) { LL::GLTF::copy(*this, dst); } +void Asset::serialize(object& dst) const +{ + write(mVersion, "version", dst); + write(mMinVersion, "minVersion", dst, std::string()); + write(mGenerator, "generator", dst); + write(mDefaultScene, "defaultScene", dst, 0); + + write(mScenes, "scenes", dst); + write(mNodes, "nodes", dst); + write(mMeshes, "meshes", dst); + write(mMaterials, "materials", dst); + write(mBuffers, "buffers", dst); + write(mBufferViews, "bufferViews", dst); + write(mTextures, "textures", dst); + write(mSamplers, "samplers", dst); + write(mImages, "images", dst); + write(mAccessors, "accessors", dst); + write(mAnimations, "animations", dst); + write(mSkins, "skins", dst); +} + void Asset::decompose(const std::string& filename) { // get folder path @@ -857,6 +1021,41 @@ void Asset::eraseBufferView(S32 bufferView) } +LLViewerFetchedTexture* fetch_texture(const LLUUID& id); + +void Image::allocateGLResources() +{ + LLUUID id; + if (LLUUID::parseUUID(mUri, &id) && id.notNull()) + { + mTexture = fetch_texture(id); + } +} + + +void Image::clearData(Asset& asset) +{ + if (mBufferView != INVALID_INDEX) + { + // remove data from buffer + BufferView& bufferView = asset.mBufferViews[mBufferView]; + Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + + buffer.erase(asset, bufferView.mByteOffset, bufferView.mByteLength); + + asset.eraseBufferView(mBufferView); + } + + mData.clear(); + mBufferView = INVALID_INDEX; + mWidth = -1; + mHeight = -1; + mComponent = -1; + mBits = -1; + mPixelType = -1; + mMimeType = ""; +} + void Image::decompose(Asset& asset, const std::string& folder) { std::string name = mName; @@ -894,12 +1093,9 @@ void Image::decompose(Asset& asset, const std::string& folder) 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 0 if (!mData.empty()) { // save j2c image @@ -907,21 +1103,44 @@ void Image::decompose(Asset& asset, const std::string& folder) LLPointer raw = new LLImageRaw(mWidth, mHeight, mComponent); U8* data = raw->allocateData(); - llassert(mData.size() == raw->getDataSize()); + llassert_always(mData.size() == raw->getDataSize()); memcpy(data, mData.data(), mData.size()); LLViewerTextureList::createUploadFile(raw, filename, 4096); mData.clear(); } +#endif - mWidth = -1; - mHeight = -1; - mComponent = -1; - mBits = -1; - mPixelType = -1; - mMimeType = ""; + clearData(asset); +} + +void Material::TextureInfo::serialize(object& dst) const +{ + write(mIndex, "index", dst, INVALID_INDEX); + write(mTexCoord, "texCoord", dst, 0); +} + +const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "index", mIndex); + copy(src, "texCoord", mTexCoord); + } + + return *this; +} + +bool Material::TextureInfo::operator==(const Material::TextureInfo& rhs) const +{ + return mIndex == rhs.mIndex && mTexCoord == rhs.mTexCoord; +} + +bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const +{ + return !(*this == rhs); } const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src) @@ -931,6 +1150,25 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::Te return *this; } +void Material::OcclusionTextureInfo::serialize(object& dst) const +{ + write(mIndex, "index", dst, INVALID_INDEX); + write(mTexCoord, "texCoord", dst, 0); + write(mStrength, "strength", dst, 1.f); +} + +const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "index", mIndex); + copy(src, "texCoord", mTexCoord); + copy(src, "strength", mStrength); + } + + return *this; +} + const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src) { mIndex = src.index; @@ -939,6 +1177,24 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( return *this; } +void Material::NormalTextureInfo::serialize(object& dst) const +{ + write(mIndex, "index", dst, INVALID_INDEX); + write(mTexCoord, "texCoord", dst, 0); + write(mScale, "scale", dst, 1.f); +} + +const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "index", mIndex); + copy(src, "texCoord", mTexCoord); + copy(src, "scale", mScale); + } + + return *this; +} const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const tinygltf::NormalTextureInfo& src) { mIndex = src.index; @@ -947,11 +1203,48 @@ const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const return *this; } +const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "baseColorFactor", mBaseColorFactor); + copy(src, "baseColorTexture", mBaseColorTexture); + copy(src, "metallicFactor", mMetallicFactor); + copy(src, "roughnessFactor", mRoughnessFactor); + copy(src, "metallicRoughnessTexture", mMetallicRoughnessTexture); + } + + return *this; +} + +void Material::PbrMetallicRoughness::serialize(object& dst) const +{ + write(mBaseColorFactor, "baseColorFactor", dst, vec4(1.f, 1.f, 1.f, 1.f)); + write(mBaseColorTexture, "baseColorTexture", dst); + write(mMetallicFactor, "metallicFactor", dst, 1.f); + write(mRoughnessFactor, "roughnessFactor", dst, 1.f); + write(mMetallicRoughnessTexture, "metallicRoughnessTexture", dst); +} + +bool Material::PbrMetallicRoughness::operator==(const Material::PbrMetallicRoughness& rhs) const +{ + return mBaseColorFactor == rhs.mBaseColorFactor && + mBaseColorTexture == rhs.mBaseColorTexture && + mMetallicFactor == rhs.mMetallicFactor && + mRoughnessFactor == rhs.mRoughnessFactor && + mMetallicRoughnessTexture == rhs.mMetallicRoughnessTexture; +} + +bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRoughness& rhs) const +{ + return !(*this == rhs); +} + 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]); + mBaseColorFactor = vec4(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]); } mBaseColorTexture = src.baseColorTexture; @@ -961,13 +1254,129 @@ const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=( return *this; } + +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 Material::bind(Asset& asset) +{ + // 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 || (mAlphaMode == Material::AlphaMode::BLEND)) + { + if (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 (mPbrMetallicRoughness.mBaseColorFactor.a > 0.f) + { + min_alpha = mAlphaCutoff / mPbrMetallicRoughness.mBaseColorFactor.a; + } + else + { + min_alpha = 1024.f; + } + } + shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); + } + + bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, 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::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); + bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); + bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); + + // NOTE: base color factor is baked into vertex stream + + shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor); + shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mPbrMetallicRoughness.mMetallicFactor); + shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(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); + } +} + +void Material::serialize(object& dst) const +{ + write(mName, "name", dst); + write(mEmissiveFactor, "emissiveFactor", dst, vec3(0.f, 0.f, 0.f)); + write(mPbrMetallicRoughness, "pbrMetallicRoughness", dst); + write(mNormalTexture, "normalTexture", dst); + write(mOcclusionTexture, "occlusionTexture", dst); + write(mEmissiveTexture, "emissiveTexture", dst); + write(mAlphaMode, "alphaMode", dst, Material::AlphaMode::OPAQUE); + write(mAlphaCutoff, "alphaCutoff", dst, 0.5f); + write(mDoubleSided, "doubleSided", dst, false); +} + +const Material& Material::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "emissiveFactor", mEmissiveFactor); + copy(src, "pbrMetallicRoughness", mPbrMetallicRoughness); + copy(src, "normalTexture", mNormalTexture); + copy(src, "occlusionTexture", mOcclusionTexture); + copy(src, "emissiveTexture", mEmissiveTexture); + copy(src, "alphaMode", mAlphaMode); + copy(src, "alphaCutoff", mAlphaCutoff); + copy(src, "doubleSided", mDoubleSided); + } + 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]); + mEmissiveFactor = vec3(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); } mPbrMetallicRoughness = src.pbrMetallicRoughness; @@ -975,7 +1384,7 @@ const Material& Material::operator=(const tinygltf::Material& src) mOcclusionTexture = src.occlusionTexture; mEmissiveTexture = src.emissiveTexture; - mAlphaMode = src.alphaMode; + mAlphaMode = gltf_alpha_mode_to_enum(src.alphaMode); mAlphaCutoff = src.alphaCutoff; mDoubleSided = src.doubleSided; @@ -984,10 +1393,31 @@ const Material& Material::operator=(const tinygltf::Material& src) void Material::allocateGLResources(Asset& asset) { - // allocate material + // HACK: allocate an LLFetchedGLTFMaterial for now + // later we'll render directly from the GLTF Images + // and BufferViews mMaterial = new LLFetchedGLTFMaterial(); } +void Mesh::serialize(object& dst) const +{ + write(mPrimitives, "primitives", dst); + write(mWeights, "weights", dst); + write(mName, "name", dst); +} + +const Mesh& Mesh::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "primitives", mPrimitives); + copy(src, "weights", mWeights); + copy(src, "name", mName); + } + + return *this; + +} const Mesh& Mesh::operator=(const tinygltf::Mesh& src) { mPrimitives.resize(src.primitives.size()); @@ -1010,6 +1440,20 @@ void Mesh::allocateGLResources(Asset& asset) } } +void Scene::serialize(object& dst) const +{ + write(mNodes, "nodes", dst); + write(mName, "name", dst); +} + +const Scene& Scene::operator=(const Value& src) +{ + copy(src, "nodes", mNodes); + copy(src, "name", mName); + + return *this; +} + const Scene& Scene::operator=(const tinygltf::Scene& src) { mNodes = src.nodes; @@ -1018,6 +1462,25 @@ const Scene& Scene::operator=(const tinygltf::Scene& src) return *this; } +void Texture::serialize(object& dst) const +{ + write(mSampler, "sampler", dst, INVALID_INDEX); + write(mSource, "source", dst, INVALID_INDEX); + write(mName, "name", dst); +} + +const Texture& Texture::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "sampler", mSampler); + copy(src, "source", mSource); + copy(src, "name", mName); + } + + return *this; +} + const Texture& Texture::operator=(const tinygltf::Texture& src) { mSampler = src.sampler; @@ -1027,6 +1490,27 @@ const Texture& Texture::operator=(const tinygltf::Texture& src) return *this; } + +void Sampler::serialize(object& dst) const +{ + write(mMagFilter, "magFilter", dst, LINEAR); + write(mMinFilter, "minFilter", dst, LINEAR_MIPMAP_LINEAR); + write(mWrapS, "wrapS", dst, REPEAT); + write(mWrapT, "wrapT", dst, REPEAT); + write(mName, "name", dst); +} + +const Sampler& Sampler::operator=(const Value& src) +{ + copy(src, "magFilter", mMagFilter); + copy(src, "minFilter", mMinFilter); + copy(src, "wrapS", mWrapS); + copy(src, "wrapT", mWrapT); + copy(src, "name", mName); + + return *this; +} + const Sampler& Sampler::operator=(const tinygltf::Sampler& src) { mMagFilter = src.magFilter; @@ -1043,23 +1527,14 @@ void Skin::uploadMatrixPalette(Asset& asset, Node& node) // prepare matrix palette // modelview will be applied by the shader, so assume matrix palette is in asset space - std::vector t_mp; + std::vector t_mp; t_mp.resize(mJoints.size()); for (U32 i = 0; i < mJoints.size(); ++i) { Node& joint = asset.mNodes[mJoints[i]]; - - //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); - //t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; - - //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); - //t_mp[i] = mInverseBindMatricesData[i] * t_mp[i]; - - t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); - t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; - + t_mp[i] = joint.mRenderMatrix * mInverseBindMatricesData[i]; } std::vector glmp; @@ -1070,7 +1545,7 @@ void Skin::uploadMatrixPalette(Asset& asset, Node& node) for (U32 i = 0; i < mJoints.size(); ++i) { - F32* m = (F32*)t_mp[i].m; + F32* m = glm::value_ptr(t_mp[i]); U32 idx = i * 12; diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index 5a62313705..1d707cbeba 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -32,9 +32,16 @@ #include "accessor.h" #include "primitive.h" #include "animation.h" +#include "boost/json.hpp" +#include "common.h" extern F32SecondsImplicit gFrameTimeSeconds; +// wingdi defines OPAQUE, which conflicts with our enum +#if defined(OPAQUE) +#undef OPAQUE +#endif + // LL GLTF Implementation namespace LL { @@ -45,13 +52,26 @@ namespace LL class Material { public: + + enum class AlphaMode + { + OPAQUE, + MASK, + BLEND + }; + class TextureInfo { public: S32 mIndex = INVALID_INDEX; S32 mTexCoord = 0; + 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); + void serialize(boost::json::object& dst) const; }; class NormalTextureInfo : public TextureInfo @@ -60,6 +80,8 @@ namespace LL F32 mScale = 1.0f; const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src); + const NormalTextureInfo& operator=(const Value& src); + void serialize(boost::json::object& dst) const; }; class OcclusionTextureInfo : public TextureInfo @@ -68,17 +90,24 @@ namespace LL F32 mStrength = 1.0f; const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src); + const OcclusionTextureInfo& operator=(const Value& src); + void serialize(boost::json::object& dst) const; }; class PbrMetallicRoughness { public: - glh::vec4f mBaseColorFactor = glh::vec4f(1.f,1.f,1.f,1.f); + vec4 mBaseColorFactor = vec4(1.f,1.f,1.f,1.f); TextureInfo mBaseColorTexture; F32 mMetallicFactor = 1.0f; F32 mRoughnessFactor = 1.0f; TextureInfo mMetallicRoughnessTexture; + + 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); + void serialize(boost::json::object& dst) const; }; @@ -93,13 +122,16 @@ namespace LL std::string mName; - glh::vec3f mEmissiveFactor = glh::vec3f(0.f, 0.f, 0.f); - std::string mAlphaMode = "OPAQUE"; + vec3 mEmissiveFactor = vec3(0.f, 0.f, 0.f); + AlphaMode mAlphaMode = AlphaMode::OPAQUE; F32 mAlphaCutoff = 0.5f; bool mDoubleSided = false; - + // bind for rendering + void bind(Asset& asset); const Material& operator=(const tinygltf::Material& src); + const Material& operator=(const Value& src); + void serialize(boost::json::object& dst) const; void allocateGLResources(Asset& asset); }; @@ -112,6 +144,8 @@ namespace LL std::string mName; const Mesh& operator=(const tinygltf::Mesh& src); + const Mesh& operator=(const Value& src); + void serialize(boost::json::object& dst) const; void allocateGLResources(Asset& asset); }; @@ -119,14 +153,14 @@ namespace LL class Node { public: - LLMatrix4a mMatrix; //local transform - LLMatrix4a mRenderMatrix; //transform for rendering - LLMatrix4a mAssetMatrix; //transform from local to asset space - LLMatrix4a mAssetMatrixInv; //transform from asset to local space + mat4 mMatrix = glm::identity(); //local transform + mat4 mRenderMatrix; //transform for rendering + mat4 mAssetMatrix; //transform from local to asset space + mat4 mAssetMatrixInv; //transform from asset to local space - glh::vec3f mTranslation; - glh::quaternionf mRotation; - glh::vec3f mScale; + vec3 mTranslation = vec3(0,0,0); + quat mRotation = glm::identity(); + vec3 mScale = vec3(1.f,1.f,1.f); // if true, mMatrix is valid and up to date bool mMatrixValid = false; @@ -145,13 +179,15 @@ namespace LL std::string mName; const Node& operator=(const tinygltf::Node& src); + const Node& operator=(const Value& src); + void serialize(boost::json::object& dst) const; // Set mRenderMatrix to a transform that can be used for the current render pass // modelview -- parent's render matrix - void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview); + void updateRenderTransforms(Asset& asset, const mat4& modelview); // update mAssetMatrix and mAssetMatrixInv - void updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix); + void updateTransforms(Asset& asset, const mat4& parentMatrix); // ensure mMatrix is valid -- if mMatrixValid is false and mTRSValid is true, will update mMatrix to match Translation/Rotation/Scale void makeMatrixValid(); @@ -161,15 +197,15 @@ namespace LL // Set rotation of this node // SIDE EFFECT: invalidates mMatrix - void setRotation(const glh::quaternionf& rotation); + void setRotation(const quat& rotation); // Set translation of this node // SIDE EFFECT: invalidates mMatrix - void setTranslation(const glh::vec3f& translation); + void setTranslation(const vec3& translation); // Set scale of this node // SIDE EFFECT: invalidates mMatrix - void setScale(const glh::vec3f& scale); + void setScale(const vec3& scale); }; class Skin @@ -179,12 +215,14 @@ namespace LL S32 mSkeleton = INVALID_INDEX; std::vector mJoints; std::string mName; - std::vector mInverseBindMatricesData; + std::vector mInverseBindMatricesData; void allocateGLResources(Asset& asset); void uploadMatrixPalette(Asset& asset, Node& node); const Skin& operator=(const tinygltf::Skin& src); + const Skin& operator=(const Value& src); + void serialize(boost::json::object& dst) const; }; class Scene @@ -194,9 +232,11 @@ namespace LL std::string mName; const Scene& operator=(const tinygltf::Scene& src); - + const Scene& operator=(const Value& src); + void serialize(boost::json::object& dst) const; + void updateTransforms(Asset& asset); - void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview); + void updateRenderTransforms(Asset& asset, const mat4& modelview); }; class Texture @@ -207,18 +247,22 @@ namespace LL std::string mName; const Texture& operator=(const tinygltf::Texture& src); + const Texture& operator=(const Value& src); + void serialize(boost::json::object& dst) const; }; class Sampler { public: - S32 mMagFilter; - S32 mMinFilter; - S32 mWrapS; - S32 mWrapT; + S32 mMagFilter = LINEAR; + S32 mMinFilter = LINEAR_MIPMAP_LINEAR; + S32 mWrapS = REPEAT; + S32 mWrapT = REPEAT; std::string mName; const Sampler& operator=(const tinygltf::Sampler& src); + const Sampler& operator=(const Value& src); + void serialize(boost::json::object& dst) const; }; class Image @@ -231,43 +275,35 @@ namespace LL S32 mBufferView = INVALID_INDEX; std::vector mData; - S32 mWidth; - S32 mHeight; - S32 mComponent; - S32 mBits; - S32 mPixelType; + S32 mWidth = -1; + S32 mHeight = -1; + S32 mComponent = -1; + S32 mBits = -1; + S32 mPixelType = -1; LLPointer mTexture; - const Image& operator=(const tinygltf::Image& src) - { - mName = src.name; - mUri = src.uri; - mMimeType = src.mimeType; - mData = src.image; - mWidth = src.width; - mHeight = src.height; - mComponent = src.component; - mBits = src.bits; - mBufferView = src.bufferView; - mPixelType = src.pixel_type; - return *this; - } - + const Image& operator=(const tinygltf::Image& src); + const Image& operator=(const Value& src); + void serialize(boost::json::object& dst) const; + // save image clear local data, and set uri void decompose(Asset& asset, const std::string& filename); - void allocateGLResources() - { - // allocate texture + // erase the buffer view associated with this image + // free any associated resources + // preserve only uri and name + void clearData(Asset& asset); - } + void allocateGLResources(); }; // C++ representation of a GLTF Asset class Asset { public: + + static const std::string minVersion_default; std::vector mScenes; std::vector mNodes; std::vector mMeshes; @@ -287,14 +323,15 @@ namespace LL std::string mCopyright; S32 mDefaultScene = INVALID_INDEX; - tinygltf::Value mExtras; + Value mExtras; + U32 mPendingBuffers = 0; // the last time update() was called according to gFrameTimeSeconds F32 mLastUpdateTime = gFrameTimeSeconds; // prepare the asset for rendering - void allocateGLResources(const std::string& filename, const tinygltf::Model& model); + void allocateGLResources(const std::string& filename = "", const tinygltf::Model& model = tinygltf::Model()); // Called periodically (typically once per frame) // Any ongoing work (such as animations) should be handled here @@ -307,7 +344,7 @@ namespace LL void updateTransforms(); // update node render transforms - void updateRenderTransforms(const LLMatrix4a& modelview); + void updateRenderTransforms(const mat4& modelview); void render(bool opaque, bool rigged = false); void renderOpaque(); @@ -323,7 +360,13 @@ namespace LL S32* primitive_hitp = nullptr // return the index of the primitive that was hit ); + Asset() = default; + Asset(const tinygltf::Model& src); + Asset(const Value& src); + const Asset& operator=(const tinygltf::Model& src); + const Asset& operator=(const Value& src); + void serialize(boost::json::object& dst) const; // save the asset to a tinygltf model void save(tinygltf::Model& dst); @@ -335,5 +378,8 @@ namespace LL // updates all bufferview indices in this Asset as needed void eraseBufferView(S32 bufferView); }; + + Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode); + std::string enum_to_gltf_alpha_mode(Material::AlphaMode alpha_mode); } } diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index 4e6f5901e7..b0fbc8524d 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -36,55 +36,60 @@ #define LL_FUNCSIG __PRETTY_FUNCTION__ #endif +#include "accessor.h" + namespace LL { namespace GLTF { + + using string_view = boost::json::string_view; + // copy one Scalar from src to dst template - static void copyScalar(S* src, T& dst) + inline void copyScalar(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } // copy one vec2 from src to dst template - static void copyVec2(S* src, T& dst) + inline void copyVec2(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } // copy one vec3 from src to dst template - static void copyVec3(S* src, T& dst) + inline void copyVec3(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } // copy one vec4 from src to dst template - static void copyVec4(S* src, T& dst) + inline void copyVec4(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } - // copy one vec2 from src to dst + // copy one mat2 from src to dst template - static void copyMat2(S* src, T& dst) + inline void copyMat2(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } - // copy one vec3 from src to dst + // copy one mat3 from src to dst template - static void copyMat3(S* src, T& dst) + inline void copyMat3(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } - // copy one vec4 from src to dst + // copy one mat4 from src to dst template - static void copyMat4(S* src, T& dst) + inline void copyMat4(S* src, T& dst) { LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } @@ -93,135 +98,128 @@ namespace LL // concrete implementations for different types of source and destination //========================================================================================================= -// suppress unused function warning -- clang complains here but these specializations are definitely used -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - template<> - void copyScalar(F32* src, F32& dst) + inline void copyScalar(F32* src, F32& dst) { dst = *src; } template<> - void copyScalar(U32* src, U32& dst) + inline void copyScalar(U32* src, U32& dst) { dst = *src; } template<> - void copyScalar(U32* src, U16& dst) + inline void copyScalar(U32* src, U16& dst) { dst = *src; } template<> - void copyScalar(U16* src, U16& dst) + inline void copyScalar(U16* src, U16& dst) { dst = *src; } template<> - void copyScalar(U16* src, U32& dst) + inline void copyScalar(U16* src, U32& dst) { dst = *src; } template<> - void copyScalar(U8* src, U16& dst) + inline void copyScalar(U8* src, U16& dst) { dst = *src; } template<> - void copyScalar(U8* src, U32& dst) + inline void copyScalar(U8* src, U32& dst) { dst = *src; } template<> - void copyVec2(F32* src, LLVector2& dst) + inline void copyVec2(F32* src, LLVector2& dst) { dst.set(src[0], src[1]); } template<> - void copyVec3(F32* src, glh::vec3f& dst) + inline void copyVec3(F32* src, vec3& dst) { - dst.set_value(src[0], src[1], src[2]); + dst = vec3(src[0], src[1], src[2]); } template<> - void copyVec3(F32* src, LLVector4a& dst) + inline void copyVec3(F32* src, LLVector4a& dst) { dst.load3(src); } template<> - void copyVec3(U16* src, LLColor4U& dst) + inline void copyVec3(U16* src, LLColor4U& dst) { dst.set(src[0], src[1], src[2], 255); } template<> - void copyVec4(U8* src, LLColor4U& dst) + inline void copyVec4(U8* src, LLColor4U& dst) { dst.set(src[0], src[1], src[2], src[3]); } template<> - void copyVec4(U16* src, LLColor4U& dst) + inline void copyVec4(U16* src, LLColor4U& dst) { dst.set(src[0], src[1], src[2], src[3]); } template<> - void copyVec4(F32* src, LLColor4U& dst) + inline void copyVec4(F32* src, LLColor4U& dst) { dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255); } template<> - void copyVec4(F32* src, LLVector4a& dst) + inline void copyVec4(F32* src, LLVector4a& dst) { dst.loadua(src); } template<> - void copyVec4(U16* src, LLVector4a& dst) + inline void copyVec4(U16* src, LLVector4a& dst) { dst.set(src[0], src[1], src[2], src[3]); } template<> - void copyVec4(U8* src, LLVector4a& dst) + inline void copyVec4(U8* src, LLVector4a& dst) { dst.set(src[0], src[1], src[2], src[3]); } template<> - void copyVec4(F32* src, glh::quaternionf& dst) + inline void copyVec4(F32* src, quat& dst) { - dst.set_value(src); + dst.x = src[0]; + dst.y = src[1]; + dst.z = src[2]; + dst.w = src[3]; } template<> - void copyMat4(F32* src, glh::matrix4f& dst) + inline void copyMat4(F32* src, mat4& dst) { - dst.set_value(src); + dst = glm::make_mat4(src); } -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - //========================================================================================================= // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyScalar(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyScalar(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -233,7 +231,7 @@ namespace LL // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyVec2(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyVec2(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -245,7 +243,7 @@ namespace LL // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyVec3(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyVec3(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -257,7 +255,7 @@ namespace LL // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyVec4(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyVec4(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -269,7 +267,7 @@ namespace LL // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyMat2(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyMat2(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -281,7 +279,7 @@ namespace LL // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyMat3(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyMat3(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -293,7 +291,7 @@ namespace LL // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy template - static void copyMat4(S* src, LLStrider dst, S32 stride, S32 count) + inline void copyMat4(S* src, LLStrider dst, S32 stride, S32 count) { for (S32 i = 0; i < count; ++i) { @@ -304,39 +302,39 @@ namespace LL } template - static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider& dst, S32 byteStride) + inline void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider& dst, S32 byteStride) { - if (accessor.mType == (S32)Accessor::Type::SCALAR) + if (accessor.mType == Accessor::Type::SCALAR) { S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride; copyScalar((S*)src, dst, stride, accessor.mCount); } - else if (accessor.mType == (S32)Accessor::Type::VEC2) + else if (accessor.mType == Accessor::Type::VEC2) { S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride; copyVec2((S*)src, dst, stride, accessor.mCount); } - else if (accessor.mType == (S32)Accessor::Type::VEC3) + else if (accessor.mType == Accessor::Type::VEC3) { S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride; copyVec3((S*)src, dst, stride, accessor.mCount); } - else if (accessor.mType == (S32)Accessor::Type::VEC4) + else if (accessor.mType == Accessor::Type::VEC4) { S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; copyVec4((S*)src, dst, stride, accessor.mCount); } - else if (accessor.mType == (S32)Accessor::Type::MAT2) + else if (accessor.mType == Accessor::Type::MAT2) { S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; copyMat2((S*)src, dst, stride, accessor.mCount); } - else if (accessor.mType == (S32)Accessor::Type::MAT3) + else if (accessor.mType == Accessor::Type::MAT3) { S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride; copyMat3((S*)src, dst, stride, accessor.mCount); } - else if (accessor.mType == (S32)Accessor::Type::MAT4) + else if (accessor.mType == Accessor::Type::MAT4) { S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride; copyMat4((S*)src, dst, stride, accessor.mCount); @@ -349,7 +347,7 @@ namespace LL // copy data from accessor to strider template - static void copy(Asset& asset, Accessor& accessor, LLStrider& dst) + inline void copy(Asset& asset, Accessor& accessor, LLStrider& dst) { const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; @@ -391,12 +389,504 @@ namespace LL // copy data from accessor to vector template - static void copy(Asset& asset, Accessor& accessor, std::vector& dst) + inline void copy(Asset& asset, Accessor& accessor, std::vector& dst) { dst.resize(accessor.mCount); LLStrider strider = dst.data(); copy(asset, accessor, strider); } + + + //========================================================================================================= + // boost::json copying utilities + // ======================================================================================================== + + //====================== unspecialized base template, single value =========================== + + // to/from Value + template + inline bool copy(const Value& src, T& dst) + { + dst = src; + return true; + } + + template + inline bool write(const T& src, Value& dst) + { + dst = boost::json::object(); + src.serialize(dst.as_object()); + return true; + } + + template + inline bool copy(const Value& src, std::unordered_map& dst) + { + if (src.is_object()) + { + const boost::json::object& obj = src.as_object(); + for (const auto& [key, value] : obj) + { + copy(value, dst[key]); + } + return true; + } + return false; + } + + template + inline bool write(const std::unordered_map& src, Value& dst) + { + boost::json::object obj; + for (const auto& [key, value] : src) + { + Value v; + if (write(value, v)) + { + obj[key] = v; + } + else + { + return false; + } + } + dst = obj; + return true; + } + + // to/from array + template + inline bool copy(const Value& src, std::vector& dst) + { + if (src.is_array()) + { + const boost::json::array& arr = src.get_array(); + dst.resize(arr.size()); + for (size_t i = 0; i < arr.size(); ++i) + { + copy(arr[i], dst[i]); + } + return true; + } + + return false; + } + + template + inline bool write(const std::vector& src, Value& dst) + { + boost::json::array arr; + for (const T& t : src) + { + Value v; + if (write(t, v)) + { + arr.push_back(v); + } + else + { + return false; + } + } + dst = arr; + return true; + } + + // to/from object member + template + inline bool copy(const boost::json::object& src, string_view member, T& dst) + { + auto it = src.find(member); + if (it != src.end()) + { + return copy(it->value(), dst); + } + return false; + } + + // always write a member to an object without checking default + template + inline bool write_always(const T& src, string_view member, boost::json::object& dst) + { + Value& v = dst[member]; + if (!write(src, v)) + { + dst.erase(member); + return false; + } + return true; + } + + // conditionally write a member to an object if the member + // is not the default value + template + inline bool write(const T& src, string_view member, boost::json::object& dst, const T& default_value = T()) + { + if (src != default_value) + { + return write_always(src, member, dst); + } + return false; + } + + template + inline bool write(const std::unordered_map& src, string_view member, boost::json::object& dst, const std::unordered_map& default_value = std::unordered_map()) + { + if (!src.empty()) + { + Value v; + if (write(src, v)) + { + dst[member] = v; + return true; + } + } + return false; + } + + template + inline bool write(const std::vector& src, string_view member, boost::json::object& dst, const std::vector& deafault_value = std::vector()) + { + if (!src.empty()) + { + Value v; + if (write(src, v)) + { + dst[member] = v; + return true; + } + } + return false; + } + + template + inline bool copy(const Value& src, string_view member, T& dst) + { + if (src.is_object()) + { + const boost::json::object& obj = src.as_object(); + return copy(obj, member, dst); + } + + return false; + } + + // vec4 + template<> + inline bool copy(const Value& src, vec4& dst) + { + if (src.is_array()) + { + const boost::json::array& arr = src.as_array(); + if (arr.size() == 4) + { + if (arr[0].is_double() && + arr[1].is_double() && + arr[2].is_double() && + arr[3].is_double()) + { + dst = vec4(arr[0].get_double(), arr[1].get_double(), arr[2].get_double(), arr[3].get_double()); + return true; + } + } + } + return false; + } + + template<> + inline bool write(const vec4& src, Value& dst) + { + dst = boost::json::array(); + boost::json::array& arr = dst.get_array(); + arr.resize(4); + arr[0] = src.x; + arr[1] = src.y; + arr[2] = src.z; + arr[3] = src.w; + return true; + } + + // quat + template<> + inline bool copy(const Value& src, quat& dst) + { + if (src.is_array()) + { + const boost::json::array& arr = src.as_array(); + if (arr.size() == 4) + { + if (arr[0].is_double() && + arr[1].is_double() && + arr[2].is_double() && + arr[3].is_double()) + { + dst.x = arr[0].get_double(); + dst.y = arr[1].get_double(); + dst.z = arr[2].get_double(); + dst.w = arr[3].get_double(); + return true; + } + } + } + return false; + } + + template<> + inline bool write(const quat& src, Value& dst) + { + dst = boost::json::array(); + boost::json::array& arr = dst.get_array(); + arr.resize(4); + arr[0] = src.x; + arr[1] = src.y; + arr[2] = src.z; + arr[3] = src.w; + return true; + } + + + // vec3 + template<> + inline bool copy(const Value& src, vec3& dst) + { + if (src.is_array()) + { + const boost::json::array& arr = src.as_array(); + if (arr.size() == 3) + { + if (arr[0].is_double() && + arr[1].is_double() && + arr[2].is_double()) + { + dst = vec3(arr[0].get_double(), arr[1].get_double(), arr[2].get_double()); + } + return true; + } + } + return false; + } + + template<> + inline bool write(const vec3& src, Value& dst) + { + dst = boost::json::array(); + boost::json::array& arr = dst.as_array(); + arr.resize(3); + arr[0] = src.x; + arr[1] = src.y; + arr[2] = src.z; + return true; + } + + // bool + template<> + inline bool copy(const Value& src, bool& dst) + { + if (src.is_bool()) + { + dst = src.get_bool(); + return true; + } + return false; + } + + template<> + inline bool write(const bool& src, Value& dst) + { + dst = src; + return true; + } + + // F32 + template<> + inline bool copy(const Value& src, F32& dst) + { + if (src.is_double()) + { + dst = src.get_double(); + return true; + } + return false; + } + + template<> + inline bool write(const F32& src, Value& dst) + { + dst = src; + return true; + } + + + // U32 + template<> + inline bool copy(const Value& src, U32& dst) + { + if (src.is_int64()) + { + dst = src.get_int64(); + return true; + } + return false; + } + + template<> + inline bool write(const U32& src, Value& dst) + { + dst = src; + return true; + } + + // F64 + template<> + inline bool copy(const Value& src, F64& dst) + { + if (src.is_double()) + { + dst = src.get_double(); + return true; + } + return false; + } + + template<> + inline bool write(const F64& src, Value& dst) + { + dst = src; + return true; + } + + // Accessor::Type + template<> + inline bool copy(const Value& src, Accessor::Type& dst) + { + if (src.is_string()) + { + dst = gltf_type_to_enum(src.get_string().c_str()); + return true; + } + return false; + } + + template<> + inline bool write(const Accessor::Type& src, Value& dst) + { + dst = enum_to_gltf_type(src); + return true; + } + + // S32 + template<> + inline bool copy(const Value& src, S32& dst) + { + if (src.is_int64()) + { + dst = src.get_int64(); + return true; + } + return false; + } + + template<> + inline bool write(const S32& src, Value& dst) + { + dst = src; + return true; + } + + + // std::string + template<> + inline bool copy(const Value& src, std::string& dst) + { + if (src.is_string()) + { + dst = src.get_string().c_str(); + return true; + } + return false; + } + + template<> + inline bool write(const std::string& src, Value& dst) + { + dst = src; + return true; + } + + // mat4 + template<> + inline bool copy(const Value& src, mat4& dst) + { + if (src.is_array()) + { + const boost::json::array& arr = src.get_array(); + if (arr.size() == 16) + { + // populate a temporary local in case + // we hit an error in the middle of the array + // (don't partially write a matrix) + mat4 t; + F32* p = glm::value_ptr(t); + + for (U32 i = 0; i < arr.size(); ++i) + { + if (arr[i].is_double()) + { + p[i] = arr[i].get_double(); + } + else + { + return false; + } + } + + dst = t; + return true; + } + } + + return false; + } + + template<> + inline bool write(const mat4& src, Value& dst) + { + dst = boost::json::array(); + boost::json::array& arr = dst.get_array(); + arr.resize(16); + const F32* p = glm::value_ptr(src); + for (U32 i = 0; i < 16; ++i) + { + arr[i] = p[i]; + } + return true; + } + + // Material::AlphaMode + template<> + inline bool copy(const Value& src, Material::AlphaMode& dst) + { + if (src.is_string()) + { + dst = gltf_alpha_mode_to_enum(src.get_string().c_str()); + return true; + } + return true; + } + + template<> + inline bool write(const Material::AlphaMode& src, Value& dst) + { + dst = enum_to_gltf_alpha_mode(src); + return true; + } + + // + // ======================================================================================================== + } } + + + diff --git a/indra/newview/gltf/common.h b/indra/newview/gltf/common.h new file mode 100644 index 0000000000..859e202738 --- /dev/null +++ b/indra/newview/gltf/common.h @@ -0,0 +1,66 @@ +#pragma once + +/** + * @file common.h + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#define GLM_ENABLE_EXPERIMENTAL 1 + +#include "glm/vec2.hpp" +#include "glm/vec3.hpp" +#include "glm/vec4.hpp" +#include "glm/mat4x4.hpp" +#include "glm/gtc/type_ptr.hpp" +#include "glm/ext/quaternion_float.hpp" +#include "glm/gtx/quaternion.hpp" +#include "glm/gtx/matrix_decompose.hpp" + +// Common types and constants used in the GLTF implementation +namespace LL +{ + namespace GLTF + { + using Value = boost::json::value; + + using mat4 = glm::mat4; + using vec4 = glm::vec4; + using vec3 = glm::vec3; + using vec2 = glm::vec2; + using quat = glm::quat; + + constexpr S32 LINEAR = 9729; + constexpr S32 NEAREST = 9728; + constexpr S32 NEAREST_MIPMAP_NEAREST = 9984; + constexpr S32 LINEAR_MIPMAP_NEAREST = 9985; + constexpr S32 NEAREST_MIPMAP_LINEAR = 9986; + constexpr S32 LINEAR_MIPMAP_LINEAR = 9987; + constexpr S32 CLAMP_TO_EDGE = 33071; + constexpr S32 MIRRORED_REPEAT = 33648; + constexpr S32 REPEAT = 10497; + + class Asset; + } +} + diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index b57a0af18d..1bde7327e6 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -28,10 +28,12 @@ #include "asset.h" #include "buffer_util.h" +#include "../llviewershadermgr.h" #include "../lltinygltfhelper.h" using namespace LL::GLTF; +using namespace boost::json; void Primitive::allocateGLResources(Asset& asset) { @@ -92,6 +94,10 @@ void Primitive::allocateGLResources(Asset& asset) mask |= LLVertexBuffer::MAP_WEIGHT4; } + 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 @@ -129,7 +135,7 @@ void Primitive::allocateGLResources(Asset& asset) if (mMaterial != INVALID_INDEX) { const Material& material = asset.mMaterials[mMaterial]; - LLColor4 baseColor = material.mMaterial->mBaseColor; + LLColor4 baseColor(glm::value_ptr(material.mPbrMetallicRoughness.mBaseColorFactor)); for (auto& dst : mColors) { dst = LLColor4U(baseColor * LLColor4(dst)); @@ -351,6 +357,50 @@ Primitive::~Primitive() mOctree = nullptr; } +U32 gltf_mode_to_gl_mode(U32 mode) +{ + switch (mode) + { + case TINYGLTF_MODE_POINTS: + return LLRender::POINTS; + case TINYGLTF_MODE_LINE: + return LLRender::LINES; + case TINYGLTF_MODE_LINE_LOOP: + return LLRender::LINE_LOOP; + case TINYGLTF_MODE_LINE_STRIP: + return LLRender::LINE_STRIP; + case TINYGLTF_MODE_TRIANGLES: + return LLRender::TRIANGLES; + case TINYGLTF_MODE_TRIANGLE_STRIP: + return LLRender::TRIANGLE_STRIP; + case TINYGLTF_MODE_TRIANGLE_FAN: + return LLRender::TRIANGLE_FAN; + default: + return LLRender::TRIANGLES; + } +} + +void Primitive::serialize(boost::json::object& dst) const +{ + write(mMaterial, "material", dst, -1); + write(mMode, "mode", dst, TINYGLTF_MODE_TRIANGLES); + write(mIndices, "indices", dst, INVALID_INDEX); + write(mAttributes, "attributes", dst); +} + +const Primitive& Primitive::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "material", mMaterial); + copy(src, "mode", mMode); + copy(src, "indices", mIndices); + copy(src, "attributes", mAttributes); + + mGLMode = gltf_mode_to_gl_mode(mMode); + } + return *this; +} const Primitive& Primitive::operator=(const tinygltf::Primitive& src) { @@ -369,32 +419,7 @@ const Primitive& Primitive::operator=(const tinygltf::Primitive& src) mAttributes[it.first] = it.second; } - switch (mMode) - { - case TINYGLTF_MODE_POINTS: - mGLMode = LLRender::POINTS; - break; - case TINYGLTF_MODE_LINE: - mGLMode = LLRender::LINES; - break; - case TINYGLTF_MODE_LINE_LOOP: - mGLMode = LLRender::LINE_LOOP; - break; - case TINYGLTF_MODE_LINE_STRIP: - mGLMode = LLRender::LINE_STRIP; - break; - case TINYGLTF_MODE_TRIANGLES: - mGLMode = LLRender::TRIANGLES; - break; - case TINYGLTF_MODE_TRIANGLE_STRIP: - mGLMode = LLRender::TRIANGLE_STRIP; - break; - case TINYGLTF_MODE_TRIANGLE_FAN: - mGLMode = LLRender::TRIANGLE_FAN; - break; - default: - mGLMode = GL_TRIANGLES; - } + mGLMode = gltf_mode_to_gl_mode(mMode); return *this; } diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index 07e8e7deb2..18aadce808 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -28,12 +28,14 @@ #include "llvertexbuffer.h" #include "llvolumeoctree.h" +#include "boost/json.hpp" // LL GLTF Implementation namespace LL { namespace GLTF { + using Value = boost::json::value; class Asset; constexpr U32 ATTRIBUTE_MASK = @@ -66,10 +68,10 @@ namespace LL std::vector mOctreeTriangles; S32 mMaterial = -1; - U32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles + S32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles U32 mGLMode = LLRender::TRIANGLES; S32 mIndices = -1; - std::unordered_map mAttributes; + std::unordered_map mAttributes; // create octree based on vertex buffer // must be called before buffer is unmapped and after buffer is populated with good data @@ -85,6 +87,8 @@ namespace LL LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); + void serialize(boost::json::object& obj) const; + const Primitive& operator=(const Value& src); const Primitive& operator=(const tinygltf::Primitive& src); void allocateGLResources(Asset& asset); diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 8bbcef1594..ae4d252d34 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -39,7 +39,14 @@ #include "gltf/asset.h" #include "pipeline.h" #include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llimagej2c.h" +#include "llfloaterperms.h" +#include "llagentbenefits.h" +#include "llfilesystem.h" +#include "boost/json.hpp" +#define GLTF_SIM_SUPPORT 1 using namespace LL; @@ -126,6 +133,170 @@ void GLTFSceneManager::decomposeSelection() } } +void GLTFSceneManager::uploadSelection() +{ + if (mUploadingAsset) + { // upload already in progress + LLNotificationsUtil::add("GLTFUploadInProgress"); + return; + } + + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + if (obj && obj->mGLTFAsset) + { + // make a copy of the asset prior to uploading + mUploadingAsset = std::make_shared(); + mUploadingObject = obj; + *mUploadingAsset = *obj->mGLTFAsset; + + GLTF::Asset& asset = *mUploadingAsset; + + for (auto& image : asset.mImages) + { + if (!image.mData.empty()) + { + mPendingImageUploads++; + + LLPointer raw = new LLImageRaw(image.mWidth, image.mHeight, image.mComponent); + 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 + raw->verticalFlip(); + + LLPointer 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()) + { + + name = llformat("Image_%d", idx); + } + else + { + name = image.mName; + } + + LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) + { + // TODO: handle failure + mPendingImageUploads--; + return false; + }; + + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response) + { + if (mUploadingAsset && mUploadingAsset->mImages.size() > idx) + { + mUploadingAsset->mImages[idx].mUri = assetId.asString(); + mPendingImageUploads--; + } + }; + + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c); + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared( + 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); + + image.clearData(asset); + } + } + + // upload .bin + for (auto& bin : asset.mBuffers) + { + mPendingBinaryUploads++; + + S32 idx = (S32)(&bin - &asset.mBuffers[0]); + + std::string buffer; + buffer.assign((const char*)bin.mData.data(), bin.mData.size()); + + LLUUID asset_id = LLUUID::generateNewID(); + + LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) + { + // TODO: handle failure + mPendingBinaryUploads--; + mUploadingAsset = nullptr; + mUploadingObject = nullptr; + LL_WARNS("GLTF") << "Failed to upload GLTF binary: " << reason << LL_ENDL; + LL_WARNS("GLTF") << response << LL_ENDL; + return false; + }; + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx](LLUUID assetId, LLSD response) + { + if (mUploadingAsset && mUploadingAsset->mBuffers.size() > idx) + { + mUploadingAsset->mBuffers[idx].mUri = assetId.asString(); + mPendingBinaryUploads--; + + // HACK: save buffer to cache to emulate a successful download + LLFileSystem cache(assetId, LLAssetType::AT_GLTF_BIN, LLFileSystem::WRITE); + auto& data = mUploadingAsset->mBuffers[idx].mData; + + cache.write((const U8*)data.data(), data.size()); + } + }; +#if GLTF_SIM_SUPPORT + S32 expected_upload_cost = 1; + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared( + buffer, + asset_id, + "", + "", + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_GLTF_BIN, + LLAssetType::AT_GLTF_BIN, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost, + false, + finish, + failure)); + + upload_new_resource(uploadInfo); +#else + // dummy finish + finish(LLUUID::generateNewID(), LLSD()); +#endif + } + } + else + { + LLNotificationsUtil::add("GLTFUploadSelection"); + } +} + void GLTFSceneManager::decomposeSelection(const std::string& filename) { LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); @@ -176,7 +347,7 @@ void GLTFSceneManager::load(const std::string& filename) if (obj) { // assign to self avatar obj->mGLTFAsset = asset; - + obj->markForUpdate(); if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) { mObjects.push_back(obj); @@ -199,6 +370,109 @@ void GLTFSceneManager::renderAlpha() render(false); } +void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) +{ + llassert(obj->getVolume()->getParams().getSculptID() == gltf_id); + llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF); + + obj->ref(); + gAssetStorage->getAssetData(gltf_id, LLAssetType::AT_GLTF, onGLTFLoadComplete, obj); +} + +//static +void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status) +{ + LLViewerObject* obj = (LLViewerObject*)user_data; + llassert(asset_type == LLAssetType::AT_GLTF_BIN); + + if (status == LL_ERR_NOERR) + { + if (obj) + { + // find the Buffer with the given id in the asset + if (obj->mGLTFAsset) + { + for (auto& buffer : obj->mGLTFAsset->mBuffers) + { + LLUUID buffer_id; + if (LLUUID::parseUUID(buffer.mUri, &buffer_id) && buffer_id == id) + { + LLFileSystem file(id, asset_type, LLFileSystem::READ); + + 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& 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 load GLTF asset: " << id << LL_ENDL; + obj->unref(); + } +} + +//static +void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status) +{ + LLViewerObject* obj = (LLViewerObject*)user_data; + llassert(asset_type == LLAssetType::AT_GLTF); + + if (status == LL_ERR_NOERR) + { + if (obj) + { + LLFileSystem file(id, asset_type, LLFileSystem::READ); + std::string data; + data.resize(file.getSize()); + file.read((U8*)data.data(), data.size()); + + boost::json::value json = boost::json::parse(data); + + std::shared_ptr asset = std::make_shared(json); + obj->mGLTFAsset = asset; + + for (auto& buffer : asset->mBuffers) + { + // for now just assume the buffer is already in the asset cache + LLUUID buffer_id; + if (LLUUID::parseUUID(buffer.mUri, &buffer_id)) + { + asset->mPendingBuffers++; + + gAssetStorage->getAssetData(buffer_id, LLAssetType::AT_GLTF_BIN, onGLTFBinLoadComplete, obj); + } + else + { + LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << LL_ENDL; + obj->unref(); + return; + } + } + } + } + else + { + LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; + obj->unref(); + } +} + void GLTFSceneManager::update() { for (U32 i = 0; i < mObjects.size(); ++i) @@ -212,6 +486,107 @@ void GLTFSceneManager::update() mObjects[i]->mGLTFAsset->update(); } + + // process pending uploads + if (mUploadingAsset && !mGLTFUploadPending) + { + 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; + mUploadingAsset->serialize(obj); + std::string json = 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) + { + // TODO: handle failure + LL_WARNS("GLTF") << "Failed to upload GLTF json: " << reason << LL_ENDL; + LL_WARNS("GLTF") << response << LL_ENDL; + + mUploadingAsset = nullptr; + mUploadingObject = nullptr; + mGLTFUploadPending = false; + return false; + }; + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, buffer](LLUUID assetId, LLSD response) + { + LLAppViewer::instance()->postToMainCoro( + [=]() + { + if (mUploadingAsset) + { + // HACK: save buffer to cache to emulate a successful upload + LLFileSystem cache(assetId, LLAssetType::AT_GLTF, LLFileSystem::WRITE); + + LL_INFOS("GLTF") << "Uploaded GLTF json: " << assetId << LL_ENDL; + cache.write((const U8 *) buffer.c_str(), buffer.size()); + + mUploadingAsset = nullptr; + } + + if (mUploadingObject) + { + mUploadingObject->mGLTFAsset = nullptr; + mUploadingObject->setGLTFAsset(assetId); + mUploadingObject->markForUpdate(); + mUploadingObject = nullptr; + } + + mGLTFUploadPending = false; + }); + }; + +#if GLTF_SIM_SUPPORT + S32 expected_upload_cost = 1; + LLUUID asset_id = LLUUID::generateNewID(); + + mGLTFUploadPending = true; + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared( + buffer, + asset_id, + "", + "", + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_GLTF, + LLAssetType::AT_GLTF, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost, + false, + finish, + failure)); + + upload_new_resource(uploadInfo); +#else + // dummy finish + finish(LLUUID::generateNewID(), LLSD()); +#endif + } + } } void GLTFSceneManager::render(bool opaque, bool rigged) @@ -219,7 +594,7 @@ void GLTFSceneManager::render(bool opaque, bool rigged) // for debugging, just render the whole scene as opaque // by traversing the whole scenegraph // Assumes camera transform is already set and - // appropriate shader is already bound + // appropriate shader is already boundd gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -243,7 +618,8 @@ void GLTFSceneManager::render(bool opaque, bool rigged) matMul(mat, modelview, modelview); - asset->updateRenderTransforms(modelview); + mat4 mdv = glm::make_mat4(modelview.getF32ptr()); + asset->updateRenderTransforms(mdv); asset->render(opaque, rigged); gGL.popMatrix(); @@ -411,20 +787,24 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) // get raycast in asset space LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform(); - LLVector4a start; - LLVector4a end; + vec4 start; + vec4 end; - agent_to_asset.affineTransform(gDebugRaycastStart, start); - agent_to_asset.affineTransform(gDebugRaycastEnd, end); + LLVector4a t; + agent_to_asset.affineTransform(gDebugRaycastStart, t); + start = glm::make_vec4(t.getF32ptr()); + agent_to_asset.affineTransform(gDebugRaycastEnd, t); + end = glm::make_vec4(t.getF32ptr()); + + start.w = end.w = 1.0; - for (auto& node : asset->mNodes) { Mesh& mesh = asset->mMeshes[node.mMesh]; if (node.mMesh != INVALID_INDEX) { - gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); // draw bounding box of mesh primitives if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) @@ -442,24 +822,24 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) } } -#if 0 +#if 1 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { gGL.flush(); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // convert raycast to node local space - LLVector4a local_start; - LLVector4a local_end; - - node.mAssetMatrixInv.affineTransform(start, local_start); - node.mAssetMatrixInv.affineTransform(end, local_end); + vec4 local_start = node.mAssetMatrixInv * start; + vec4 local_end = node.mAssetMatrixInv * end; for (auto& primitive : mesh.mPrimitives) { if (primitive.mOctree.notNull()) { - renderOctreeRaycast(local_start, local_end, primitive.mOctree); + LLVector4a s, e; + s.load3(glm::value_ptr(local_start)); + e.load3(glm::value_ptr(local_end)); + renderOctreeRaycast(s, e, primitive.mOctree); } } @@ -499,18 +879,18 @@ void GLTFSceneManager::renderDebug() continue; } - LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); - - LLMatrix4a modelview; - modelview.loadu(gGLModelView); + mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr()); - matMul(mat, modelview, modelview); + mat4 modelview = glm::make_mat4(gGLModelView); + + modelview = modelview * mat; + Asset* asset = obj->mGLTFAsset.get(); for (auto& node : asset->mNodes) { - matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + node.mRenderMatrix = modelview * node.mAssetMatrix; } } @@ -523,13 +903,6 @@ void GLTFSceneManager::renderDebug() Asset* asset = obj->mGLTFAsset.get(); - LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); - - LLMatrix4a modelview; - modelview.loadu(gGLModelView); - - matMul(mat, modelview, modelview); - renderAssetDebug(obj, asset); } @@ -551,21 +924,20 @@ void GLTFSceneManager::renderDebug() continue; } - LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr()); - LLMatrix4a modelview; - modelview.loadu(gGLModelView); + mat4 modelview = glm::make_mat4(gGLModelView); - matMul(mat, modelview, modelview); + modelview = modelview * mat; Asset* asset = obj->mGLTFAsset.get(); for (auto& node : asset->mNodes) { // force update all mRenderMatrix, not just nodes with meshes - matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + node.mRenderMatrix = modelview * node.mAssetMatrix; - gGL.loadMatrix(node.mRenderMatrix.getF32ptr()); + gGL.loadMatrix(glm::value_ptr(node.mRenderMatrix)); // render x-axis red, y-axis green, z-axis blue gGL.color4f(1.f, 0.f, 0.f, 0.5f); gGL.begin(LLRender::LINES); @@ -595,7 +967,9 @@ void GLTFSceneManager::renderDebug() { Node& child = asset->mNodes[child_idx]; gGL.vertex3f(0.f, 0.f, 0.f); - gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr()); + + + gGL.vertex3fv(glm::value_ptr(child.mMatrix[3])); } gGL.end(); gGL.flush(); @@ -628,9 +1002,8 @@ void GLTFSceneManager::renderDebug() gGL.color3f(1, 0, 1); drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f)); - gGL.loadMatrix((F32*) node->mRenderMatrix.mMatrix); + gGL.loadMatrix(glm::value_ptr(node->mRenderMatrix)); - auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0); drawBoxOutline(listener->mBounds[0], listener->mBounds[1]); @@ -643,3 +1016,5 @@ void GLTFSceneManager::renderDebug() gDebugProgram.unbind(); } + + diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index 8f29f34c30..a6754d0484 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -54,6 +54,7 @@ namespace LL 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 update(); void render(bool opaque, bool rigged = false); @@ -77,7 +78,18 @@ namespace LL void renderDebug(); + void addGLTFObject(LLViewerObject* object, LLUUID gltf_id); + static void onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status); + static void onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status); + std::vector> mObjects; + + std::shared_ptr mUploadingAsset; + bool mGLTFUploadPending = false; + LLPointer mUploadingObject; + U32 mPendingImageUploads = 0; + U32 mPendingBinaryUploads = 0; + U32 mPendingGLTFUploads = 0; }; } diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index 6e45e2a0f3..ee4f1b0fe5 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -142,7 +142,6 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex) mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed); } - } LLViewerFetchedTexture* fetch_texture(const LLUUID& id) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 44705acb07..ba270949cc 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1637,23 +1637,29 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) { session_id = message_data["asset_id"].asUUID(); } - LLIMProcessing::processNewMessage( - message_data["from_agent_id"].asUUID(), - from_group, - message_data["to_agent_id"].asUUID(), - message_data.has("offline") ? static_cast(message_data["offline"].asInteger()) : IM_OFFLINE, - dialog, - session_id, - static_cast(message_data["timestamp"].asInteger()), - message_data["from_agent_name"].asString(), - message_data["message"].asString(), - static_cast((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland - message_data["region_id"].asUUID(), - position, - bin_bucket.data(), - bin_bucket.size(), - sender, - message_data["asset_id"].asUUID()); + + LLAppViewer::instance()->postToMainCoro([=]() + { + std::vector local_bin_bucket = bin_bucket; + LLHost local_sender = sender; + LLIMProcessing::processNewMessage( + message_data["from_agent_id"].asUUID(), + from_group, + message_data["to_agent_id"].asUUID(), + message_data.has("offline") ? static_cast(message_data["offline"].asInteger()) : IM_OFFLINE, + dialog, + session_id, + static_cast(message_data["timestamp"].asInteger()), + message_data["from_agent_name"].asString(), + message_data["message"].asString(), + static_cast((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland + message_data["region_id"].asUUID(), + position, + local_bin_bucket.data(), + local_bin_bucket.size(), + local_sender, + message_data["asset_id"].asUUID()); + }); } } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index b8bef6361f..198fdad616 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1400,7 +1400,9 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) return mask; } - if (item->getType() == LLAssetType::AT_MESH) + if (item->getType() == LLAssetType::AT_MESH || + item->getType() == LLAssetType::AT_GLTF || + item->getType() == LLAssetType::AT_GLTF_BIN) { return mask; } diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp index 481086f760..b6a9a7c160 100644 --- a/indra/newview/llviewerassettype.cpp +++ b/indra/newview/llviewerassettype.cpp @@ -89,6 +89,8 @@ LLViewerAssetDictionary::LLViewerAssetDictionary() addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE)); addEntry(LLViewerAssetType::AT_SETTINGS, new ViewerAssetEntry(DAD_SETTINGS)); addEntry(LLViewerAssetType::AT_MATERIAL, new ViewerAssetEntry(DAD_MATERIAL)); + addEntry(LLViewerAssetType::AT_GLTF, new ViewerAssetEntry(DAD_GLTF)); + addEntry(LLViewerAssetType::AT_GLTF_BIN, new ViewerAssetEntry(DAD_GLTF_BIN)); }; EDragAndDropType LLViewerAssetType::lookupDragAndDropType(EType asset_type) diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 68ed7633b9..d11cdae482 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -299,9 +299,17 @@ void LLResourceUploadInfo::assignDefaults() mDescription = "(No Description)"; } - mFolderId = gInventory.findUserDefinedCategoryUUIDForType( - (mDestinationFolderType == LLFolderType::FT_NONE) ? - (LLFolderType::EType)mAssetType : mDestinationFolderType); + if (mAssetType == LLAssetType::AT_GLTF || + mAssetType == LLAssetType::AT_GLTF_BIN) + { + mFolderId = LLUUID::null; + } + else + { + mFolderId = gInventory.findUserDefinedCategoryUUIDForType( + (mDestinationFolderType == LLFolderType::FT_NONE) ? + (LLFolderType::EType)mAssetType : mDestinationFolderType); + } } std::string LLResourceUploadInfo::getDisplayName() const diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index f32bbdf3c2..b74fde48c3 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2674,7 +2674,13 @@ void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url) { if (initializeMedia(mimeType)) { - loadURI(); + ref(); + LLAppViewer::instance()->postToMainCoro([this]() + { + loadURI(); + unref(); + }); + } } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 5f2eafd62e..0b1c6c1329 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -139,6 +139,7 @@ #include "boost/unordered_map.hpp" #include #include +#include #include "llcleanup.h" #include "llviewershadermgr.h" #include "gltfscenemanager.h" @@ -3317,6 +3318,13 @@ bool enable_os_exception() #endif } + +bool enable_gltf() +{ + static LLCachedControl enablegltf(gSavedSettings, "GLTFEnabled", false); + return enablegltf; +} + class LLSelfRemoveAllAttachments : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -8047,7 +8055,6 @@ class LLAdvancedClickGLTFOpen: 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().load(); return true; } @@ -8057,7 +8064,6 @@ 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; } @@ -8067,12 +8073,39 @@ 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; } }; +class LLAdvancedClickGLTFUpload: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LL::GLTFSceneManager::instance().uploadSelection(); + return true; + } +}; + +class LLAdvancedClickResizeWindow : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + S32 w = 0; + S32 h = 0; + + sscanf(userdata.asString().c_str(), "%dx%d", &w, &h); + + if (w > 0 && h > 0) + { + gViewerWindow->getWindow()->setSize(LLCoordWindow(w, h)); + } + + return true; + } +}; + + // these are used in the gl menus to set control values that require shader recompilation class LLToggleShaderControl : public view_listener_t { @@ -9728,6 +9761,8 @@ void initialize_menus() 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 LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload"); + view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow"); view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain"); @@ -10032,6 +10067,7 @@ void initialize_menus() commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects)); enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters)); enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception)); + enable.add("EnableGLTF", boost::bind(&enable_gltf)); view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d8f522163c..16d874717a 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -4303,7 +4303,9 @@ LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform(); LLMatrix4a node_to_agent; - matMul(node.mAssetMatrix, asset_to_agent, node_to_agent); + LLMatrix4a am; + am.loadu(glm::value_ptr(node.mAssetMatrix)); + matMul(am, asset_to_agent, node_to_agent); mat = node_to_agent; } @@ -4314,6 +4316,7 @@ LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const return mat; } + void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const { LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index); @@ -4361,7 +4364,9 @@ void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion if (node.mParent != -1) { auto& parent = mGLTFAsset->mNodes[node.mParent]; - matMul(agent_to_asset, parent.mAssetMatrixInv, agent_to_node); + LLMatrix4a ami; + ami.loadu(glm::value_ptr(parent.mAssetMatrixInv)); + matMul(agent_to_asset, ami, agent_to_node); } LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4()); @@ -4373,9 +4378,13 @@ void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion LLVector3 pos; LLQuaternion rot; LLVector3 scale; - decomposeMatrix(node.mMatrix, pos, rot, scale); + LLMatrix4a mat; + mat.loadu(glm::value_ptr(node.mMatrix)); + decomposeMatrix(mat, pos, rot, scale); + + mat.asMatrix4().initAll(scale, new_rot, pos); - node.mMatrix.asMatrix4().initAll(scale, new_rot, pos); + node.mMatrix = glm::make_mat4(mat.getF32ptr()); mGLTFAsset->updateTransforms(); } @@ -4389,7 +4398,9 @@ void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset) LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform(); LLMatrix4a agent_to_node; - matMul(agent_to_asset, node.mAssetMatrixInv, agent_to_node); + LLMatrix4a ami; + ami.loadu(glm::value_ptr(node.mAssetMatrixInv)); + matMul(agent_to_asset, ami, agent_to_node); LLVector4a origin = LLVector4a::getZero(); LLVector4a offset_v; @@ -4406,7 +4417,12 @@ void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset) trans.setIdentity(); trans.mMatrix[3] = offset_v; - matMul(trans, node.mMatrix, node.mMatrix); + LLMatrix4a mat; + mat.loadu(glm::value_ptr(node.mMatrix)); + + matMul(trans, mat, mat); + + node.mMatrix = glm::make_mat4(mat.getF32ptr()); // TODO -- only update transforms for this node and its children (or use a dirty flag) mGLTFAsset->updateTransforms(); @@ -7497,6 +7513,23 @@ void LLViewerObject::shrinkWrap() } } +void LLViewerObject::setGLTFAsset(const LLUUID& id) +{ + //get the sculpt params and set the sculpt type and id + auto* param = getExtraParameterEntryCreate(LLNetworkData::PARAMS_SCULPT); + + LLSculptParams* sculpt_params = (LLSculptParams*)param->data; + sculpt_params->setSculptTexture(id, LL_SCULPT_TYPE_GLTF); + + setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, true, true); + + // Update the volume + LLVolumeParams volume_params; + volume_params.setSculptID(id, LL_SCULPT_TYPE_GLTF); + updateVolume(volume_params); +} + + class ObjectPhysicsProperties : public LLHTTPNode { public: diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 4da8b25357..f29de6bfc6 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -1,3 +1,4 @@ + /** * @file llviewerobject.h * @brief Description of LLViewerObject class, which is the base class for most objects in the viewer. @@ -742,6 +743,11 @@ public: F32 mPhysicsDensity; F32 mPhysicsRestitution; + // set the GLTF asset for this LLViewerObject to the specified asset id + // id MUST be for a GLTF asset (LLAssetType::AT_GLTF) + // will relesae any currently held references to a GLTF asset on id change + void setGLTFAsset(const LLUUID& id); + // Associated GLTF Asset std::shared_ptr mGLTFAsset; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 6668384f52..2cdba5dee1 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -2466,24 +2466,14 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) gSavedSettings.setS32("max_texture_dimension_Y", 1024); } - if (features.has("PBRTerrainEnabled")) + if (features.has("GLTFEnabled")) { - bool enabled = features["PBRTerrainEnabled"]; - gSavedSettings.setBOOL("RenderTerrainPBREnabled", enabled); + bool enabled = features["GLTFEnabled"]; + gSavedSettings.setBOOL("GLTFEnabled", enabled); } else { - gSavedSettings.setBOOL("RenderTerrainPBREnabled", false); - } - - if (features.has("PBRMaterialSwatchEnabled")) - { - bool enabled = features["PBRMaterialSwatchEnabled"]; - gSavedSettings.setBOOL("UIPreviewMaterial", enabled); - } - else - { - gSavedSettings.setBOOL("UIPreviewMaterial", false); + gSavedSettings.setBOOL("GLTFEnabled", false); } }; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a4835849eb..46df5e206f 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -89,6 +89,7 @@ #include "llsculptidsize.h" #include "llavatarappearancedefines.h" #include "llgltfmateriallist.h" +#include "gltfscenemanager.h" const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -1133,6 +1134,11 @@ bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo } } + if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_GLTF) + { // notify GLTFSceneManager about new GLTF object + LL::GLTFSceneManager::instance().addGLTFObject(this, volume_params.getSculptID()); + } + return true; } else if (NO_LOD == lod) @@ -1407,6 +1413,12 @@ bool LLVOVolume::calcLOD() return false; } + if (mGLTFAsset != nullptr) + { + // do not calculate LOD for GLTF objects + return false; + } + S32 cur_detail = 0; F32 radius; @@ -5623,7 +5635,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LLVOVolume* vobj = drawablep->getVOVolume(); - if (!vobj || vobj->isDead()) + if (!vobj || vobj->isDead() || vobj->mGLTFAsset) { continue; } diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 9697774fd9..e7898ef146 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2852,21 +2852,69 @@ function="World.EnvPreset" + + + + + + + + + + + + + + + + + + + + + + + You must select an object that has local-only GLTF asset associated with it. + fail + + + + + Upload is currently in progress. Please try again later. + fail + + + -- cgit v1.3 From 2f4120038429c6aff865f153f708ceefb60d67f4 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 28 May 2024 09:45:40 -0500 Subject: Remove tinygltf dependency from LL::GLTF (#1541) * #1535 Image loading/saving support in boost::json driven GLTF parser * #1536 GLB Support in boost::json drvien GLTF parser --- indra/llcommon/lluuid.h | 4 +- indra/llimage/llimage.cpp | 56 ++ indra/llimage/llimage.h | 3 + indra/llrender/llglslshader.cpp | 6 + indra/llrender/llglslshader.h | 17 + .../shaders/class1/gltf/pbrmetallicroughnessF.glsl | 117 +++ .../shaders/class1/gltf/pbrmetallicroughnessV.glsl | 106 +++ indra/newview/gltf/README.md | 30 +- indra/newview/gltf/accessor.cpp | 158 ++-- indra/newview/gltf/accessor.h | 49 +- indra/newview/gltf/animation.cpp | 104 +-- indra/newview/gltf/animation.h | 36 +- indra/newview/gltf/asset.cpp | 862 ++++++++------------- indra/newview/gltf/asset.h | 67 +- indra/newview/gltf/buffer_util.h | 100 ++- indra/newview/gltf/common.h | 1 + indra/newview/gltf/primitive.cpp | 86 +- indra/newview/gltf/primitive.h | 24 +- indra/newview/gltfscenemanager.cpp | 252 ++---- indra/newview/gltfscenemanager.h | 2 - indra/newview/llfilepicker.cpp | 8 +- indra/newview/lllocalbitmaps.cpp | 19 +- indra/newview/lllocalbitmaps.h | 1 + indra/newview/llviewermenu.cpp | 10 - indra/newview/llviewermessage.cpp | 186 ----- indra/newview/llviewershadermgr.cpp | 65 ++ indra/newview/llviewertexture.cpp | 6 + indra/newview/llviewertexture.h | 4 +- indra/newview/llviewertexturelist.cpp | 140 ++-- indra/newview/llviewertexturelist.h | 2 + indra/newview/skins/default/xui/en/menu_viewer.xml | 8 - .../newview/skins/default/xui/en/notifications.xml | 22 + 32 files changed, 1220 insertions(+), 1331 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 68c4b05fdc..b178868591 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -37,8 +37,8 @@ class LLMutex; const S32 UUID_BYTES = 16; const S32 UUID_WORDS = 4; -const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below -const S32 UUID_STR_SIZE = 37; +const S32 UUID_STR_LENGTH = 37; // number of bytes needed to store a UUID as a string +const S32 UUID_STR_SIZE = 36; // .size() of a UUID in a std::string const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL. struct uuid_time_t { diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 863a28996d..acd382d9a8 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2232,6 +2232,61 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec) 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 LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring) { @@ -2412,6 +2467,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size) //---------------------------------------------------------------------------- + bool LLImageFormatted::load(const std::string &filename, int load_size) { resetLastError(); diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 7f759f7679..42eecbb97c 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -322,7 +322,10 @@ class LLImageFormatted : public LLImageBase { public: 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* createFromMimeType(std::string_view mimetype); + static S8 getCodecFromMimeType(std::string_view mimetype); protected: /*virtual*/ ~LLImageFormatted(); diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index f6b1ca3741..ecd0c6908b 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1049,6 +1049,12 @@ void LLGLSLShader::bind() } } +void LLGLSLShader::bind(LLGLSLShader::GLTFVariant variant) +{ + llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); + mGLTFVariants[variant].bind(); +} + void LLGLSLShader::bind(bool rigged) { if (rigged) diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 75e1bdfd54..fa01d212e1 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -44,6 +44,7 @@ public: bool hasTransport = false; // implies no lighting (it's possible to have neither though) bool hasSkinning = false; bool hasObjectSkinning = false; + bool mGLTF = false; bool hasAtmospherics = false; bool hasGamma = false; bool hasShadows = false; @@ -318,6 +319,22 @@ public: // this pointer should be set to whichever shader represents this shader's rigged variant LLGLSLShader* mRiggedVariant = nullptr; + // variants for use by GLTF renderer + // "this" is considered to be OPAQUE + enum GLTFVariant + { + STATIC_OPAQUE, + STATIC_BLEND, + RIGGED_OPAQUE, + RIGGED_BLEND, + NUM_GLTF_VARIANTS + }; + + std::vector mGLTFVariants; + + //helper to bind GLTF variant + void bind(GLTFVariant variant); + // hacky flag used for optimization in LLDrawPoolAlpha bool mCanBindFast = false; diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl new file mode 100644 index 0000000000..dbee58b76a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -0,0 +1,117 @@ +/** + * @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 + +uniform sampler2D diffuseMap; //always in sRGB space + +uniform float metallicFactor; +uniform float roughnessFactor; +uniform vec3 emissiveColor; +uniform sampler2D bumpMap; +uniform sampler2D emissiveMap; +uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness + +out vec4 frag_data[4]; + +in vec3 vary_position; +in vec4 vertex_color; +in vec3 vary_normal; +in vec3 vary_tangent; +flat in float vary_sign; + +in vec2 base_color_texcoord; +in vec2 normal_texcoord; +in vec2 metallic_roughness_texcoord; +in vec2 emissive_texcoord; + +uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +uniform vec4 clipPlane; +uniform float clipSign; + +void mirrorClip(vec3 pos); + +uniform mat3 normal_matrix; + +void main() +{ + mirrorClip(vary_position); + + 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 col = basecolor.rgb; + + // from mikktspace.com + vec3 vNt = texture(bumpMap, 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 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); + + // RGB = Occlusion, Roughness, Metal + // default values, see LLViewerTexture::sDefaultPBRORMImagep + // occlusion 1.0 + // roughness 0.0 + // metal 0.0 + vec3 spec = texture(specularMap, metallic_roughness_texcoord.xy).rgb; + + spec.g *= roughnessFactor; + spec.b *= metallicFactor; + + vec3 emissive = emissiveColor; + emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); + + tnorm *= gl_FrontFacing ? 1.0 : -1.0; + + //spec.rgb = vec3(1,1,0); + //col = vec3(0,0,0); + //emissive = vary_tangent.xyz*0.5+0.5; + //emissive = vec3(sign*0.5+0.5); + //emissive = vNt * 0.5 + 0.5; + //emissive = tnorm*0.5+0.5; + // See: C++: addDeferredAttachments(), GLSL: softenLightF + frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse + frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. + frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags + frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive +} + diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl new file mode 100644 index 0000000000..0add509002 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -0,0 +1,106 @@ +/** + * @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; +mat4 getObjectSkinnedTransform(); +#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 vec3 normal; +in vec4 tangent; +in vec2 texcoord0; + +out vec2 base_color_texcoord; +out vec2 normal_texcoord; +out vec2 metallic_roughness_texcoord; +out vec2 emissive_texcoord; + +out vec4 vertex_color; + +out vec3 vary_tangent; +flat out float vary_sign; +out vec3 vary_normal; +out vec3 vary_position; + +vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); + +void main() +{ +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + + mat = modelview_matrix * mat; + + vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; + vary_position = pos; + gl_Position = projection_matrix*vec4(pos,1.0); + +#else + vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +#endif + + base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0); + normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0); + metallic_roughness_texcoord = texture_transform(texcoord0, texture_metallic_roughness_transform, texture_matrix0); + emissive_texcoord = texture_transform(texcoord0, texture_emissive_transform, texture_matrix0); + +#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; + + vertex_color = diffuse_color; +} + + + + diff --git a/indra/newview/gltf/README.md b/indra/newview/gltf/README.md index 8e7df0a439..a2d43be1d6 100644 --- a/indra/newview/gltf/README.md +++ b/indra/newview/gltf/README.md @@ -1,13 +1,13 @@ # 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). 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. 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. 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 - GLTF specification stores indices, store indices. - 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. - "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". 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 we'll purge these strings from the implementation. However, implementations MUST preserve any and all "name" members. "write" and "copy" implementations MUST be stored in buffer_util.h. 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): ``` @@ -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 (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 -WILL NOT throw exceptions on get_foo with a mismatched type. ALWAYS check is_foo +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 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 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. -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 +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 our existing implementations. ### 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 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. 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. - + diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 369ff4f240..0619c617e2 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -28,6 +28,7 @@ #include "asset.h" #include "buffer_util.h" +#include "llfilesystem.h" using namespace LL::GLTF; 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); + mByteLength = mData.size(); + for (BufferView& view : asset.mBufferViews) { if (view.mBuffer == idx) @@ -119,6 +122,95 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length) } } +bool Buffer::prep(Asset& asset) +{ + // PRECONDITION: mByteLength must not be 0 + llassert(mByteLength != 0); + + 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); + + mData.resize(file.getSize()); + 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 { write(mName, "name", dst); @@ -132,23 +224,15 @@ const Buffer& Buffer::operator=(const Value& src) { copy(src, "name", mName); copy(src, "uri", mUri); - - // NOTE: DO NOT attempt to handle the uri here. + copy(src, "byteLength", mByteLength); + + // NOTE: DO NOT attempt to handle the uri here. // The uri is a reference to a file that is not loaded until // after the json document is parsed } 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 { write_always(mBuffer, "buffer", dst); @@ -173,43 +257,6 @@ const BufferView& BufferView::operator=(const Value& src) 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 { write(mName, "name", dst); @@ -240,18 +287,3 @@ const Accessor& Accessor::operator=(const Value& src) 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; -} - diff --git a/indra/newview/gltf/accessor.h b/indra/newview/gltf/accessor.h index 3bbc5216bd..ec68c5f624 100644 --- a/indra/newview/gltf/accessor.h +++ b/indra/newview/gltf/accessor.h @@ -26,7 +26,6 @@ * $/LicenseInfo$ */ -#include "../lltinygltfhelper.h" #include "llstrider.h" #include "boost/json.hpp" @@ -51,9 +50,12 @@ namespace LL // also updates all buffer views in given asset that reference this buffer void erase(Asset& asset, S32 offset, S32 length); + bool prep(Asset& asset); + void serialize(boost::json::object& obj) const; const Buffer& operator=(const Value& value); - const Buffer& operator=(const tinygltf::Buffer& src); + + bool save(Asset& asset, const std::string& folder); }; class BufferView @@ -69,37 +71,44 @@ namespace LL void serialize(boost::json::object& obj) const; const BufferView& operator=(const Value& value); - const BufferView& operator=(const tinygltf::BufferView& src); }; - + class Accessor { public: - S32 mBufferView = INVALID_INDEX; - S32 mByteOffset = 0; - S32 mComponentType = 0; - S32 mCount = 0; - std::vector mMax; - std::vector mMin; + enum class Type : U8 + { + SCALAR, + VEC2, + VEC3, + VEC4, + MAT2, + MAT3, + MAT4 + }; - enum class Type : S32 + enum class ComponentType : U32 { - SCALAR = TINYGLTF_TYPE_SCALAR, - VEC2 = TINYGLTF_TYPE_VEC2, - VEC3 = TINYGLTF_TYPE_VEC3, - VEC4 = TINYGLTF_TYPE_VEC4, - MAT2 = TINYGLTF_TYPE_MAT2, - MAT3 = TINYGLTF_TYPE_MAT3, - MAT4 = TINYGLTF_TYPE_MAT4 + BYTE = 5120, + UNSIGNED_BYTE = 5121, + SHORT = 5122, + UNSIGNED_SHORT = 5123, + UNSIGNED_INT = 5125, + FLOAT = 5126 }; + std::vector mMax; + std::vector mMin; + std::string mName; + S32 mBufferView = INVALID_INDEX; + S32 mByteOffset = 0; + ComponentType mComponentType = ComponentType::BYTE; + S32 mCount = 0; Type mType = Type::SCALAR; bool mNormalized = false; - std::string mName; void serialize(boost::json::object& obj) const; const Accessor& operator=(const Value& value); - const Accessor& operator=(const tinygltf::Accessor& src); }; // convert from "SCALAR", "VEC2", etc to Accessor::Type diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp index 8a542fb315..f18bba788c 100644 --- a/indra/newview/gltf/animation.cpp +++ b/indra/newview/gltf/animation.cpp @@ -32,7 +32,7 @@ using namespace LL::GLTF; using namespace boost::json; -void Animation::allocateGLResources(Asset& asset) +bool Animation::prep(Asset& asset) { if (!mSamplers.empty()) { @@ -40,7 +40,10 @@ void Animation::allocateGLResources(Asset& asset) mMaxTime = -FLT_MAX; for (auto& sampler : mSamplers) { - sampler.allocateGLResources(asset); + if (!sampler.prep(asset)) + { + return false; + } mMinTime = llmin(sampler.mMinTime, mMinTime); mMaxTime = llmax(sampler.mMaxTime, mMaxTime); } @@ -52,13 +55,21 @@ void Animation::allocateGLResources(Asset& asset) for (auto& channel : mRotationChannels) { - channel.allocateGLResources(asset, mSamplers[channel.mSampler]); + if (!channel.prep(asset, mSamplers[channel.mSampler])) + { + return false; + } } 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) @@ -85,7 +96,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]; mMinTime = accessor.mMin[0]; @@ -95,6 +106,8 @@ void Animation::Sampler::allocateGLResources(Asset& asset) LLStrider frame_times = mFrameTimes.data(); copy(asset, accessor, frame_times); + + return true; } @@ -120,16 +133,6 @@ const Animation::Sampler& Animation::Sampler::operator=(const Value& src) 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 { return mNode == rhs.mNode && mPath == rhs.mPath; @@ -172,17 +175,6 @@ const Animation::Channel& Animation::Channel::operator=(const Value& src) 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) { LL_PROFILE_ZONE_SCOPED; @@ -223,11 +215,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]; copy(asset, accessor, mRotations); + + return true; } void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time) @@ -254,11 +248,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]; copy(asset, accessor, mTranslations); + + return true; } void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time) @@ -286,11 +282,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]; copy(asset, accessor, mScales); + + return true; } void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time) @@ -364,47 +362,15 @@ const Animation& Animation::operator=(const Value& src) return *this; } -const Animation& Animation::operator=(const tinygltf::Animation& src) -{ - mName = src.name; - - mSamplers.resize(src.samplers.size()); - for (U32 i = 0; i < src.samplers.size(); ++i) - { - mSamplers[i] = src.samplers[i]; - } - - for (U32 i = 0; i < src.channels.size(); ++i) - { - if (src.channels[i].target_path == "rotation") - { - mRotationChannels.push_back(RotationChannel()); - mRotationChannels.back() = src.channels[i]; - } - - if (src.channels[i].target_path == "translation") - { - mTranslationChannels.push_back(TranslationChannel()); - mTranslationChannels.back() = src.channels[i]; - } - - if (src.channels[i].target_path == "scale") - { - mScaleChannels.push_back(ScaleChannel()); - mScaleChannels.back() = src.channels[i]; - } - } - - return *this; -} - -void Skin::allocateGLResources(Asset& asset) +bool Skin::prep(Asset& asset) { if (mInverseBindMatrices != INVALID_INDEX) { Accessor& accessor = asset.mAccessors[mInverseBindMatrices]; copy(asset, accessor, mInverseBindMatricesData); } + + return true; } const Skin& Skin::operator=(const Value& src) @@ -419,16 +385,6 @@ const Skin& Skin::operator=(const Value& src) 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 { write(mInverseBindMatrices, "inverseBindMatrices", obj, INVALID_INDEX); diff --git a/indra/newview/gltf/animation.h b/indra/newview/gltf/animation.h index 53c11d4669..d5426fd4ce 100644 --- a/indra/newview/gltf/animation.h +++ b/indra/newview/gltf/animation.h @@ -49,12 +49,10 @@ namespace LL S32 mOutput = INVALID_INDEX; std::string mInterpolation; - void allocateGLResources(Asset& asset); + bool prep(Asset& asset); void serialize(boost::json::object& dst) const; const Sampler& operator=(const Value& value); - const Sampler& operator=(const tinygltf::AnimationSampler& src); - // get the frame index and time for the specified time // asset -- the asset to reference for Accessors @@ -85,7 +83,6 @@ namespace LL void serialize(boost::json::object& dst) const; const Channel& operator=(const Value& value); - const Channel& operator=(const tinygltf::AnimationChannel& src); }; class RotationChannel : public Channel @@ -96,16 +93,10 @@ namespace LL std::vector mRotations; - const RotationChannel& operator=(const tinygltf::AnimationChannel& src) - { - Channel::operator=(src); - return *this; - } - // prepare data needed for rendering // asset -- asset to reference for Accessors // sampler -- Sampler associated with this channel - void allocateGLResources(Asset& asset, Sampler& sampler); + bool prep(Asset& asset, Sampler& sampler); void apply(Asset& asset, Sampler& sampler, F32 time); }; @@ -118,16 +109,10 @@ namespace LL std::vector mTranslations; - const TranslationChannel& operator=(const tinygltf::AnimationChannel& src) - { - Channel::operator=(src); - return *this; - } - // prepare data needed for rendering // asset -- asset to reference for Accessors // sampler -- Sampler associated with this channel - void allocateGLResources(Asset& asset, Sampler& sampler); + bool prep(Asset& asset, Sampler& sampler); void apply(Asset& asset, Sampler& sampler, F32 time); }; @@ -140,16 +125,10 @@ namespace LL std::vector mScales; - const ScaleChannel& operator=(const tinygltf::AnimationChannel& src) - { - Channel::operator=(src); - return *this; - } - // prepare data needed for rendering // asset -- asset to reference for Accessors // sampler -- Sampler associated with this channel - void allocateGLResources(Asset& asset, Sampler& sampler); + bool prep(Asset& asset, Sampler& sampler); void apply(Asset& asset, Sampler& sampler, F32 time); }; @@ -160,7 +139,7 @@ namespace LL // min/max time values for all samplers combined F32 mMinTime = 0.f; F32 mMaxTime = 0.f; - + // current time of the animation F32 mTime = 0.f; @@ -170,9 +149,8 @@ namespace LL void serialize(boost::json::object& dst) const; const Animation& operator=(const Value& value); - const Animation& operator=(const tinygltf::Animation& src); - - void allocateGLResources(Asset& asset); + + bool prep(Asset& asset); void update(Asset& asset, float dt); diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index c64d48662c..485984fac1 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -33,6 +33,8 @@ #include "../llviewertexturelist.h" #include "../pipeline.h" #include "buffer_util.h" +#include +#include "llimagejpeg.h" using namespace LL::GLTF; using namespace boost::json; @@ -75,268 +77,14 @@ namespace LL return "OPAQUE"; } } - - template - void copy(const std::vector& src, std::vector& 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 != glm::identity()) - { - dst.matrix.resize(16); - const F32* m = glm::value_ptr(src.mMatrix); - for (U32 i = 0; i < 16; ++i) - { - dst.matrix[i] = m[i]; - } - } - } - else if (src.mTRSValid) - { - if (src.mRotation != glm::identity()) - { - dst.rotation.resize(4); - dst.rotation[0] = src.mRotation.x; - dst.rotation[1] = src.mRotation.y; - dst.rotation[2] = src.mRotation.z; - dst.rotation[3] = src.mRotation.w; - } - - if (src.mTranslation != vec3(0.f, 0.f, 0.f)) - { - dst.translation.resize(3); - dst.translation[0] = src.mTranslation.x; - dst.translation[1] = src.mTranslation.y; - dst.translation[2] = src.mTranslation.z; - } - - if (src.mScale != vec3(1.f, 1.f, 1.f)) - { - dst.scale.resize(3); - dst.scale[0] = src.mScale.x; - dst.scale[1] = src.mScale.y; - dst.scale[2] = src.mScale.z; - } - } - - 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.r, src.mBaseColorFactor.g, src.mBaseColorFactor.b, src.mBaseColorFactor.a }; - 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.r, src.mEmissiveFactor.g, src.mEmissiveFactor.b }; - 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 = (S32) 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"; - - // NOTE: extras are lost in the conversion for now - - 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) { mat4 identity = glm::identity(); - + for (auto& nodeIndex : mNodes) { Node& node = asset.mNodes[nodeIndex]; @@ -368,9 +116,9 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); mAssetMatrix = parentMatrix * mMatrix; - + mAssetMatrixInv = glm::inverse(mAssetMatrix); - + S32 my_index = this - &asset.mNodes[0]; for (auto& childIndex : mChildren) @@ -419,7 +167,6 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, { if (node.mMesh != INVALID_INDEX) { - bool newHit = false; LLMatrix4a ami; @@ -452,7 +199,7 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLMatrix4a am; am.loadu(glm::value_ptr(node.mAssetMatrix)); // shorten line segment on hit - am.affineTransform(p, asset_end); + am.affineTransform(p, asset_end); // transform results back to asset space if (intersection) @@ -521,7 +268,7 @@ void Node::makeTRSValid() vec3 skew; vec4 perspective; glm::decompose(mMatrix, mScale, mRotation, mTranslation, skew, perspective); - + mTRSValid = true; } @@ -577,59 +324,6 @@ const Node& Node::operator=(const Value& src) { mTRSValid = true; } - - return *this; -} - -const Node& Node::operator=(const tinygltf::Node& src) -{ - F32* dstMatrix = glm::value_ptr(mMatrix); - - if (src.matrix.size() == 16) - { - // Node has a transformation matrix, just copy it - for (U32 i = 0; i < 16; ++i) - { - dstMatrix[i] = (F32)src.matrix[i]; - } - - mMatrixValid = true; - } - else if (!src.rotation.empty() || !src.translation.empty() || !src.scale.empty()) - { - // node has rotation/translation/scale, convert to matrix - if (src.rotation.size() == 4) - { - mRotation = quat((F32)src.rotation[3], (F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2]); - } - - if (src.translation.size() == 3) - { - mTranslation = vec3((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); - } - - if (src.scale.size() == 3) - { - mScale = vec3((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); - } - else - { - mScale = vec3(1.f, 1.f, 1.f); - } - - mTRSValid = true; - } - else - { - // node specifies no transformation, set to identity - mMatrix = glm::identity(); - mMatrixValid = true; - } - - mChildren = src.children; - mMesh = src.mesh; - mSkin = src.skin; - mName = src.name; return *this; } @@ -662,22 +356,6 @@ const Image& Image::operator=(const Value& src) return *this; } -const Image& Image::operator=(const tinygltf::Image& src) -{ - mName = src.name; - mWidth = src.width; - mHeight = src.height; - mComponent = src.component; - mBits = src.bits; - mPixelType = src.pixel_type; - mUri = src.uri; - mBufferView = src.bufferView; - mMimeType = src.mimeType; - mData = src.image; - return *this; -} - - void Asset::render(bool opaque, bool rigged) { if (rigged) @@ -726,14 +404,8 @@ void Asset::render(bool opaque, bool rigged) continue; } - if (mMaterials[primitive.mMaterial].mMaterial.notNull()) - { - material.mMaterial->bind(); - } - else - { - material.bind(*this); - } + material.bind(*this); + cull = !material.mDoubleSided; } else @@ -792,45 +464,50 @@ void Asset::update() } } -void Asset::allocateGLResources(const std::string& filename, const tinygltf::Model& model) +bool Asset::prep() { - // do images first as materials may depend on images - for (auto& image : mImages) + // do buffers first as other resources depend on them + for (auto& buffer : mBuffers) { - image.allocateGLResources(); + if (!buffer.prep(*this)) + { + return false; + } } - - // do materials before meshes as meshes may depend on materials - if (!filename.empty()) + for (auto& image : mImages) { - for (U32 i = 0; i < mMaterials.size(); ++i) + if (!image.prep(*this)) { - // HACK: local preview mode, load material from model for now - mMaterials[i].allocateGLResources(*this); - LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + return false; } } for (auto& mesh : mMeshes) { - mesh.allocateGLResources(*this); + if (!mesh.prep(*this)) + { + return false; + } } for (auto& animation : mAnimations) { - animation.allocateGLResources(*this); + if (!animation.prep(*this)) + { + return false; + } } for (auto& skin : mSkins) { - skin.allocateGLResources(*this); + if (!skin.prep(*this)) + { + return false; + } } -} -Asset::Asset(const tinygltf::Model& src) -{ - *this = src; + return true; } Asset::Asset(const Value& src) @@ -838,90 +515,141 @@ Asset::Asset(const Value& src) *this = src; } -const Asset& Asset::operator=(const tinygltf::Model& src) +bool Asset::load(std::string_view filename) { - mVersion = src.asset.version; - mMinVersion = src.asset.minVersion; - mGenerator = src.asset.generator; - mCopyright = src.asset.copyright; + mFilename = filename; + std::string ext = gDirUtilp->getExtension(mFilename); - // note: extras are lost in the conversion for now - - mDefaultScene = src.defaultScene; - - mScenes.resize(src.scenes.size()); - for (U32 i = 0; i < src.scenes.size(); ++i) + std::ifstream file(filename.data(), std::ios::binary); + if (file.is_open()) { - mScenes[i] = src.scenes[i]; - } + std::string str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); - mNodes.resize(src.nodes.size()); - for (U32 i = 0; i < src.nodes.size(); ++i) - { - mNodes[i] = src.nodes[i]; + if (ext == "gltf") + { + Value val = parse(str); + *this = val; + return prep(); + } + else if (ext == "glb") + { + return loadBinary(str); + } + else + { + LL_WARNS() << "Unsupported file type: " << ext << LL_ENDL; + return false; + } } - - mMeshes.resize(src.meshes.size()); - for (U32 i = 0; i < src.meshes.size(); ++i) + else { - mMeshes[i] = src.meshes[i]; + LL_WARNS() << "Failed to open file: " << filename << LL_ENDL; + return false; } - mMaterials.resize(src.materials.size()); - for (U32 i = 0; i < src.materials.size(); ++i) - { - mMaterials[i] = src.materials[i]; - } + return false; +} - mBuffers.resize(src.buffers.size()); - for (U32 i = 0; i < src.buffers.size(); ++i) - { - mBuffers[i] = src.buffers[i]; - } +bool Asset::loadBinary(const std::string& data) +{ + // load from binary gltf + const U8* ptr = (const U8*)data.data(); + const U8* end = ptr + data.size(); - mBufferViews.resize(src.bufferViews.size()); - for (U32 i = 0; i < src.bufferViews.size(); ++i) + if (end - ptr < 12) { - mBufferViews[i] = src.bufferViews[i]; + LL_WARNS("GLTF") << "GLB file too short" << LL_ENDL; + return false; } - mTextures.resize(src.textures.size()); - for (U32 i = 0; i < src.textures.size(); ++i) + U32 magic = *(U32*)ptr; + ptr += 4; + + if (magic != 0x46546C67) { - mTextures[i] = src.textures[i]; + LL_WARNS("GLTF") << "Invalid GLB magic" << LL_ENDL; + return false; } - mSamplers.resize(src.samplers.size()); - for (U32 i = 0; i < src.samplers.size(); ++i) + U32 version = *(U32*)ptr; + ptr += 4; + + if (version != 2) { - mSamplers[i] = src.samplers[i]; + LL_WARNS("GLTF") << "Unsupported GLB version" << LL_ENDL; + return false; } - mImages.resize(src.images.size()); - for (U32 i = 0; i < src.images.size(); ++i) + U32 length = *(U32*)ptr; + ptr += 4; + + if (length != data.size()) { - mImages[i] = src.images[i]; + LL_WARNS("GLTF") << "GLB length mismatch" << LL_ENDL; + return false; } - mAccessors.resize(src.accessors.size()); - for (U32 i = 0; i < src.accessors.size(); ++i) + U32 chunkLength = *(U32*)ptr; + ptr += 4; + + if (end - ptr < chunkLength + 8) { - mAccessors[i] = src.accessors[i]; + LL_WARNS("GLTF") << "GLB chunk too short" << LL_ENDL; + return false; } - mAnimations.resize(src.animations.size()); - for (U32 i = 0; i < src.animations.size(); ++i) + U32 chunkType = *(U32*)ptr; + ptr += 4; + + if (chunkType != 0x4E4F534A) { - mAnimations[i] = src.animations[i]; + LL_WARNS("GLTF") << "Invalid GLB chunk type" << LL_ENDL; + return false; } - mSkins.resize(src.skins.size()); - for (U32 i = 0; i < src.skins.size(); ++i) + Value val = parse(std::string_view((const char*)ptr, chunkLength)); + *this = val; + + if (mBuffers.size() > 0 && mBuffers[0].mUri.empty()) { - mSkins[i] = src.skins[i]; + // load binary chunk + ptr += chunkLength; + + if (end - ptr < 8) + { + LL_WARNS("GLTF") << "GLB chunk too short" << LL_ENDL; + return false; + } + + chunkLength = *(U32*)ptr; + ptr += 4; + + chunkType = *(U32*)ptr; + ptr += 4; + + if (chunkType != 0x004E4942) + { + LL_WARNS("GLTF") << "Invalid GLB chunk type" << LL_ENDL; + return false; + } + + auto& buffer = mBuffers[0]; + + if (ptr + buffer.mByteLength <= end) + { + buffer.mData.resize(buffer.mByteLength); + memcpy(buffer.mData.data(), ptr, buffer.mByteLength); + ptr += buffer.mByteLength; + } + else + { + LL_WARNS("GLTF") << "Buffer too short" << LL_ENDL; + return false; + } } - - return *this; + + return prep(); } const Asset& Asset::operator=(const Value& src) @@ -943,7 +671,7 @@ const Asset& Asset::operator=(const Value& src) copy(asset, "extras", mExtras); } - copy(obj, "defaultScene", mDefaultScene); + copy(obj, "scene", mScene); copy(obj, "scenes", mScenes); copy(obj, "nodes", mNodes); copy(obj, "meshes", mMeshes); @@ -961,18 +689,17 @@ const Asset& Asset::operator=(const Value& src) return *this; } -void Asset::save(tinygltf::Model& dst) -{ - LL::GLTF::copy(*this, dst); -} - void Asset::serialize(object& dst) const { - write(mVersion, "version", dst); - write(mMinVersion, "minVersion", dst, std::string()); - write(mGenerator, "generator", dst); - write(mDefaultScene, "defaultScene", dst, 0); - + static const std::string sGenerator = "Linden Lab GLTF Prototype v0.1"; + + dst["asset"] = object{}; + object& asset = dst["asset"].get_object(); + + write(mVersion, "version", asset); + write(mMinVersion, "minVersion", asset, std::string()); + write(sGenerator, "generator", asset); + write(mScene, "scene", dst, INVALID_INDEX); write(mScenes, "scenes", dst); write(mNodes, "nodes", dst); write(mMeshes, "meshes", dst); @@ -987,16 +714,39 @@ void Asset::serialize(object& dst) const write(mSkins, "skins", dst); } -void Asset::decompose(const std::string& filename) +bool Asset::save(const std::string& filename) { // get folder path std::string folder = gDirUtilp->getDirName(filename); - // decompose images + // save images for (auto& image : mImages) { - image.decompose(*this, folder); + if (!image.save(*this, folder)) + { + return false; + } + } + + // save buffers + // NOTE: save buffers after saving images as saving images + // may remove image data from buffers + for (auto& buffer : mBuffers) + { + if (!buffer.save(*this, folder)) + { + return false; + } } + + // save .gltf + object obj; + serialize(obj); + std::string buffer = boost::json::serialize(obj, {}); + std::ofstream file(filename, std::ios::binary); + file.write(buffer.c_str(), buffer.size()); + + return true; } void Asset::eraseBufferView(S32 bufferView) @@ -1023,13 +773,63 @@ void Asset::eraseBufferView(S32 bufferView) LLViewerFetchedTexture* fetch_texture(const LLUUID& id); -void Image::allocateGLResources() +bool Image::prep(Asset& asset) { LLUUID id; - if (LLUUID::parseUUID(mUri, &id) && id.notNull()) - { + if (mUri.size() == UUID_STR_SIZE && LLUUID::parseUUID(mUri, &id) && id.notNull()) + { // loaded from an asset, fetch the texture from the asset system mTexture = fetch_texture(id); } + else if (mUri.find("data:") == 0) + { // embedded in a data URI, load the texture from the URI + LL_WARNS() << "Data URIs not yet supported" << LL_ENDL; + return false; + } + else if (mBufferView != INVALID_INDEX) + { // embedded in a buffer, load the texture from the buffer + BufferView& bufferView = asset.mBufferViews[mBufferView]; + Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + + U8* data = buffer.mData.data() + bufferView.mByteOffset; + + mTexture = LLViewerTextureManager::getFetchedTextureFromMemory(data, bufferView.mByteLength, mMimeType); + + if (mTexture.isNull()) + { + LL_WARNS("GLTF") << "Failed to load image from buffer:" << LL_ENDL; + LL_WARNS("GLTF") << " image: " << mName << LL_ENDL; + LL_WARNS("GLTF") << " mimeType: " << mMimeType << LL_ENDL; + + return false; + } + } + else if (!asset.mFilename.empty() && !mUri.empty()) + { // loaded locally and not embedded, load the texture as a local preview + std::string dir = gDirUtilp->getDirName(asset.mFilename); + std::string img_file = dir + gDirUtilp->getDirDelimiter() + mUri; + + LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(img_file); + if (tracking_id.notNull()) + { + LLUUID world_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); + mTexture = LLViewerTextureManager::getFetchedTexture(world_id); + } + else + { + LL_WARNS("GLTF") << "Failed to load image from file:" << LL_ENDL; + LL_WARNS("GLTF") << " image: " << mName << LL_ENDL; + LL_WARNS("GLTF") << " file: " << img_file << LL_ENDL; + + return false; + } + } + else + { + LL_WARNS("GLTF") << "Failed to load image: " << mName << LL_ENDL; + return false; + } + + return true; } @@ -1046,7 +846,6 @@ void Image::clearData(Asset& asset) asset.eraseBufferView(mBufferView); } - mData.clear(); mBufferView = INVALID_INDEX; mWidth = -1; mHeight = -1; @@ -1056,9 +855,15 @@ void Image::clearData(Asset& asset) mMimeType = ""; } -void Image::decompose(Asset& asset, const std::string& folder) +bool Image::save(Asset& asset, const std::string& folder) { + // NOTE: this *MUST* be a lossless save + // Artists use this to save their work repeatedly, so + // adding any compression artifacts here will degrade + // images over time. std::string name = mName; + std::string error; + const std::string& delim = gDirUtilp->getDirDelimiter(); if (name.empty()) { S32 idx = this - asset.mImages.data(); @@ -1067,10 +872,11 @@ void Image::decompose(Asset& asset, const std::string& folder) if (mBufferView != INVALID_INDEX) { - // save original image + // we have the bytes of the original image, save that out in its + // original format BufferView& bufferView = asset.mBufferViews[mBufferView]; Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; - + std::string extension; if (mMimeType == "image/jpeg") @@ -1083,37 +889,76 @@ void Image::decompose(Asset& asset, const std::string& folder) } else { + error = "Unknown mime type, saved as .bin"; extension = ".bin"; } - std::string filename = folder + "/" + name + "." + extension; + std::string filename = folder + delim + name + extension; // set URI to non-j2c file for now, but later we'll want to reference the j2c hash - mUri = name + "." + extension; + mUri = name + extension; std::ofstream file(filename, std::ios::binary); file.write((const char*)buffer.mData.data() + bufferView.mByteOffset, bufferView.mByteLength); } - -#if 0 - if (!mData.empty()) + else if (mTexture.notNull()) { - // save j2c image - std::string filename = folder + "/" + name + ".j2c"; - - LLPointer raw = new LLImageRaw(mWidth, mHeight, mComponent); - U8* data = raw->allocateData(); - llassert_always(mData.size() == raw->getDataSize()); - memcpy(data, mData.data(), mData.size()); - - LLViewerTextureList::createUploadFile(raw, filename, 4096); + auto bitmapmgr = LLLocalBitmapMgr::getInstance(); + if (bitmapmgr->isLocal(mTexture->getID())) + { + LLUUID tracking_id = bitmapmgr->getTrackingID(mTexture->getID()); + if (tracking_id.notNull()) + { // copy original file to destination folder + std::string source = bitmapmgr->getFilename(tracking_id); + if (gDirUtilp->fileExists(source)) + { + std::string filename = gDirUtilp->getBaseFileName(source); + std::string dest = folder + delim + filename; - mData.clear(); + LLFile::copy(source, dest); + mUri = filename; + } + else + { + error = "File not found: " + source; + } + } + else + { + error = "Local image missing."; + } + } + else if (!mUri.empty()) + { + std::string from_dir = gDirUtilp->getDirName(asset.mFilename); + std::string base_filename = gDirUtilp->getBaseFileName(mUri); + std::string filename = from_dir + delim + base_filename; + if (gDirUtilp->fileExists(filename)) + { + std::string dest = folder + delim + base_filename; + LLFile::copy(filename, dest); + mUri = base_filename; + } + else + { + error = "Original image file not found: " + filename; + } + } + else + { + error = "Image is not a local image and has no uri, cannot save."; + } } -#endif + if (!error.empty()) + { + LL_WARNS("GLTF") << "Failed to save " << name << ": " << error << LL_ENDL; + return false; + } clearData(asset); + + return true; } void Material::TextureInfo::serialize(object& dst) const @@ -1143,13 +988,6 @@ bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const return !(*this == rhs); } -const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src) -{ - mIndex = src.index; - mTexCoord = src.texCoord; - return *this; -} - void Material::OcclusionTextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); @@ -1169,14 +1007,6 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( return *this; } -const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src) -{ - mIndex = src.index; - mTexCoord = src.texCoord; - mStrength = src.strength; - return *this; -} - void Material::NormalTextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); @@ -1195,13 +1025,6 @@ const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const 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 Value& src) { @@ -1240,21 +1063,6 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough return !(*this == rhs); } -const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const tinygltf::PbrMetallicRoughness& src) -{ - if (src.baseColorFactor.size() == 4) - { - mBaseColorFactor = vec4(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; -} - static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback) { if (info.mIndex != INVALID_INDEX) @@ -1312,10 +1120,10 @@ void Material::bind(Asset& asset) if (!LLPipeline::sShadowRender) { - bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); + bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); - + // NOTE: base color factor is baked into vertex stream shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor); @@ -1370,35 +1178,6 @@ const Material& Material::operator=(const Value& src) } -const Material& Material::operator=(const tinygltf::Material& src) -{ - mName = src.name; - - if (src.emissiveFactor.size() == 3) - { - mEmissiveFactor = vec3(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); - } - - mPbrMetallicRoughness = src.pbrMetallicRoughness; - mNormalTexture = src.normalTexture; - mOcclusionTexture = src.occlusionTexture; - mEmissiveTexture = src.emissiveTexture; - - mAlphaMode = gltf_alpha_mode_to_enum(src.alphaMode); - mAlphaCutoff = src.alphaCutoff; - mDoubleSided = src.doubleSided; - - return *this; -} - -void Material::allocateGLResources(Asset& asset) -{ - // HACK: allocate an LLFetchedGLTFMaterial for now - // later we'll render directly from the GLTF Images - // and BufferViews - mMaterial = new LLFetchedGLTFMaterial(); -} - void Mesh::serialize(object& dst) const { write(mPrimitives, "primitives", dst); @@ -1418,26 +1197,18 @@ const Mesh& Mesh::operator=(const Value& src) return *this; } -const Mesh& Mesh::operator=(const tinygltf::Mesh& src) -{ - mPrimitives.resize(src.primitives.size()); - for (U32 i = 0; i < src.primitives.size(); ++i) - { - mPrimitives[i] = src.primitives[i]; - } - - mWeights = src.weights; - mName = src.name; - return *this; -} - -void Mesh::allocateGLResources(Asset& asset) +bool Mesh::prep(Asset& asset) { for (auto& primitive : mPrimitives) { - primitive.allocateGLResources(asset); + if (!primitive.prep(asset)) + { + return false; + } } + + return true; } void Scene::serialize(object& dst) const @@ -1450,14 +1221,6 @@ const Scene& Scene::operator=(const Value& src) { copy(src, "nodes", mNodes); copy(src, "name", mName); - - return *this; -} - -const Scene& Scene::operator=(const tinygltf::Scene& src) -{ - mNodes = src.nodes; - mName = src.name; return *this; } @@ -1481,16 +1244,6 @@ const Texture& Texture::operator=(const Value& src) return *this; } -const Texture& Texture::operator=(const tinygltf::Texture& src) -{ - mSampler = src.sampler; - mSource = src.source; - mName = src.name; - - return *this; -} - - void Sampler::serialize(object& dst) const { write(mMagFilter, "magFilter", dst, LINEAR); @@ -1511,17 +1264,6 @@ const Sampler& Sampler::operator=(const Value& src) return *this; } -const Sampler& Sampler::operator=(const tinygltf::Sampler& src) -{ - mMagFilter = src.magFilter; - mMinFilter = src.minFilter; - mWrapS = src.wrapS; - mWrapT = src.wrapT; - mName = src.name; - - return *this; -} - void Skin::uploadMatrixPalette(Asset& asset, Node& node) { // prepare matrix palette diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index 990e1e41a9..761e746aa1 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -28,12 +28,12 @@ #include "llvertexbuffer.h" #include "llvolumeoctree.h" -#include "../lltinygltfhelper.h" #include "accessor.h" #include "primitive.h" #include "animation.h" #include "boost/json.hpp" #include "common.h" +#include "../llviewertexture.h" extern F32SecondsImplicit gFrameTimeSeconds; @@ -69,7 +69,6 @@ namespace LL 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); void serialize(boost::json::object& dst) const; }; @@ -79,7 +78,6 @@ namespace LL public: F32 mScale = 1.0f; - const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src); const NormalTextureInfo& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -89,7 +87,6 @@ namespace LL public: F32 mStrength = 1.0f; - const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src); const OcclusionTextureInfo& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -105,22 +102,16 @@ namespace LL 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); 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 mMaterial; PbrMetallicRoughness mPbrMetallicRoughness; NormalTextureInfo mNormalTexture; OcclusionTextureInfo mOcclusionTexture; TextureInfo mEmissiveTexture; - std::string mName; vec3 mEmissiveFactor = vec3(0.f, 0.f, 0.f); AlphaMode mAlphaMode = AlphaMode::OPAQUE; @@ -129,11 +120,8 @@ namespace LL // bind for rendering void bind(Asset& asset); - const Material& operator=(const tinygltf::Material& src); const Material& operator=(const Value& src); void serialize(boost::json::object& dst) const; - - void allocateGLResources(Asset& asset); }; class Mesh @@ -143,11 +131,10 @@ namespace LL std::vector mWeights; std::string mName; - const Mesh& operator=(const tinygltf::Mesh& src); const Mesh& operator=(const Value& src); void serialize(boost::json::object& dst) const; - void allocateGLResources(Asset& asset); + bool prep(Asset& asset); }; class Node @@ -178,7 +165,6 @@ namespace LL std::string mName; - const Node& operator=(const tinygltf::Node& src); const Node& operator=(const Value& src); void serialize(boost::json::object& dst) const; @@ -217,10 +203,9 @@ namespace LL std::string mName; std::vector mInverseBindMatricesData; - void allocateGLResources(Asset& asset); + bool prep(Asset& asset); void uploadMatrixPalette(Asset& asset, Node& node); - const Skin& operator=(const tinygltf::Skin& src); const Skin& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -231,7 +216,6 @@ namespace LL std::vector mNodes; std::string mName; - const Scene& operator=(const tinygltf::Scene& src); const Scene& operator=(const Value& src); void serialize(boost::json::object& dst) const; @@ -246,7 +230,6 @@ namespace LL S32 mSource = INVALID_INDEX; std::string mName; - const Texture& operator=(const tinygltf::Texture& src); const Texture& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -260,7 +243,6 @@ namespace LL S32 mWrapT = REPEAT; std::string mName; - const Sampler& operator=(const tinygltf::Sampler& src); const Sampler& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -274,7 +256,6 @@ namespace LL S32 mBufferView = INVALID_INDEX; - std::vector mData; S32 mWidth = -1; S32 mHeight = -1; S32 mComponent = -1; @@ -283,19 +264,20 @@ namespace LL LLPointer mTexture; - const Image& operator=(const tinygltf::Image& src); const Image& operator=(const Value& src); void serialize(boost::json::object& dst) const; - // save image clear local data, and set uri - void decompose(Asset& asset, const std::string& filename); + // save image to disk + // 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 - // free any associated resources + // free any associated GLTF resources // preserve only uri and name void clearData(Asset& asset); - void allocateGLResources(); + bool prep(Asset& asset); }; // C++ representation of a GLTF Asset @@ -322,16 +304,20 @@ namespace LL std::string mMinVersion; std::string mCopyright; - S32 mDefaultScene = INVALID_INDEX; + S32 mScene = INVALID_INDEX; Value mExtras; U32 mPendingBuffers = 0; + // local file this asset was loaded from (if any) + std::string mFilename; + // the last time update() was called according to gFrameTimeSeconds F32 mLastUpdateTime = gFrameTimeSeconds; - // prepare the asset for rendering - void allocateGLResources(const std::string& filename = "", const tinygltf::Model& model = tinygltf::Model()); + + // prepare for first time use + bool prep(); // Called periodically (typically once per frame) // Any ongoing work (such as animations) should be handled here @@ -361,18 +347,25 @@ namespace LL ); Asset() = default; - Asset(const tinygltf::Model& 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); void serialize(boost::json::object& dst) const; - // 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); + // save the asset to the given .gltf file + // saves images and bins alongside the gltf file + bool save(const std::string& filename); // remove the bufferview at the given index // updates all bufferview indices in this Asset as needed diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index b0fbc8524d..72e69c9599 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -31,7 +31,7 @@ // whenever we add support for more types #ifdef _MSC_VER -#define LL_FUNCSIG __FUNCSIG__ +#define LL_FUNCSIG __FUNCSIG__ #else #define LL_FUNCSIG __PRETTY_FUNCTION__ #endif @@ -353,37 +353,29 @@ namespace LL const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; - if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT) - { - LL::GLTF::copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) - { - LL::GLTF::copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) - { - LL::GLTF::copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) - { - LL::GLTF::copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT) - { - LL::GLTF::copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE) - { - LL::GLTF::copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) - { - LL::GLTF::copy(asset, accessor, (const F64*)src, dst, bufferView.mByteStride); - } - else - { - LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL; + switch (accessor.mComponentType) + { + case Accessor::ComponentType::FLOAT: + copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); + break; + case Accessor::ComponentType::UNSIGNED_INT: + copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); + break; + case Accessor::ComponentType::SHORT: + copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); + break; + case Accessor::ComponentType::UNSIGNED_SHORT: + copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); + break; + case Accessor::ComponentType::BYTE: + copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); + break; + case Accessor::ComponentType::UNSIGNED_BYTE: + copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); + break; + default: + LL_ERRS("GLTF") << "Invalid component type" << LL_ENDL; + break; } } @@ -400,7 +392,7 @@ namespace LL //========================================================================================================= // boost::json copying utilities // ======================================================================================================== - + //====================== unspecialized base template, single value =========================== // to/from Value @@ -528,7 +520,7 @@ namespace LL } return false; } - + template inline bool write(const std::unordered_map& src, string_view member, boost::json::object& dst, const std::unordered_map& default_value = std::unordered_map()) { @@ -571,6 +563,44 @@ namespace LL 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 template<> inline bool copy(const Value& src, vec4& dst) @@ -881,7 +911,7 @@ namespace LL return true; } - // + // // ======================================================================================================== } diff --git a/indra/newview/gltf/common.h b/indra/newview/gltf/common.h index 859e202738..59f2ba38db 100644 --- a/indra/newview/gltf/common.h +++ b/indra/newview/gltf/common.h @@ -60,6 +60,7 @@ namespace LL constexpr S32 MIRRORED_REPEAT = 33648; constexpr S32 REPEAT = 10497; + class Asset; } } diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index 1bde7327e6..886b8f79c9 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -9,7 +9,7 @@ * 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. + * 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 @@ -30,12 +30,10 @@ #include "buffer_util.h" #include "../llviewershadermgr.h" -#include "../lltinygltfhelper.h" - using namespace LL::GLTF; using namespace boost::json; -void Primitive::allocateGLResources(Asset& asset) +bool Primitive::prep(Asset& asset) { // allocate vertex buffer // We diverge from the intent of the GLTF format here to work with our existing render pipeline @@ -85,10 +83,19 @@ void Primitive::allocateGLResources(Asset& asset) { Accessor& accessor = asset.mAccessors[mIndices]; 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; - + if (!mWeights.empty()) { mask |= LLVertexBuffer::MAP_WEIGHT4; @@ -130,7 +137,7 @@ void Primitive::allocateGLResources(Asset& asset) { mColors.resize(mPositions.size(), LLColor4U::white); } - + // bake material basecolor into color array if (mMaterial != INVALID_INDEX) { @@ -148,7 +155,7 @@ void Primitive::allocateGLResources(Asset& asset) { mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0)); } - + mVertexBuffer->setNormalData(mNormals.data()); if (mTangents.empty()) @@ -175,10 +182,12 @@ void Primitive::allocateGLResources(Asset& asset) mVertexBuffer->setWeight4Data(weight_data.data()); } - + createOctree(); - + mVertexBuffer->unbind(); + + return true; } void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2) @@ -224,7 +233,7 @@ void Primitive::createOctree() F32 scaler = 0.25f; - if (mMode == TINYGLTF_MODE_TRIANGLES) + if (mMode == Mode::TRIANGLES) { const U32 num_triangles = mVertexBuffer->getNumIndices() / 3; // Initialize all the triangles we need @@ -241,14 +250,14 @@ void Primitive::createOctree() const LLVector4a& v0 = mPositions[i0]; const LLVector4a& v1 = mPositions[i1]; const LLVector4a& v2 = mPositions[i2]; - + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); - + //insert mOctree->insert(tri); } } - else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP) + else if (mMode == Mode::TRIANGLE_STRIP) { const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; // Initialize all the triangles we need @@ -272,7 +281,7 @@ void Primitive::createOctree() mOctree->insert(tri); } } - else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN) + else if (mMode == Mode::TRIANGLE_FAN) { const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; // Initialize all the triangles we need @@ -296,14 +305,14 @@ void Primitive::createOctree() mOctree->insert(tri); } } - else if (mMode == TINYGLTF_MODE_POINTS || - mMode == TINYGLTF_MODE_LINE || - mMode == TINYGLTF_MODE_LINE_LOOP || - mMode == TINYGLTF_MODE_LINE_STRIP) + else if (mMode == Mode::POINTS || + mMode == Mode::LINES || + mMode == Mode::LINE_LOOP || + mMode == Mode::LINE_STRIP) { // nothing to do, no volume... maybe add some collision geometry around these primitive types? } - + else { LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL; @@ -357,23 +366,23 @@ Primitive::~Primitive() mOctree = nullptr; } -U32 gltf_mode_to_gl_mode(U32 mode) +LLRender::eGeomModes gltf_mode_to_gl_mode(Primitive::Mode mode) { switch (mode) { - case TINYGLTF_MODE_POINTS: + case Primitive::Mode::POINTS: return LLRender::POINTS; - case TINYGLTF_MODE_LINE: + case Primitive::Mode::LINES: return LLRender::LINES; - case TINYGLTF_MODE_LINE_LOOP: + case Primitive::Mode::LINE_LOOP: return LLRender::LINE_LOOP; - case TINYGLTF_MODE_LINE_STRIP: + case Primitive::Mode::LINE_STRIP: return LLRender::LINE_STRIP; - case TINYGLTF_MODE_TRIANGLES: + case Primitive::Mode::TRIANGLES: return LLRender::TRIANGLES; - case TINYGLTF_MODE_TRIANGLE_STRIP: + case Primitive::Mode::TRIANGLE_STRIP: return LLRender::TRIANGLE_STRIP; - case TINYGLTF_MODE_TRIANGLE_FAN: + case Primitive::Mode::TRIANGLE_FAN: return LLRender::TRIANGLE_FAN; default: return LLRender::TRIANGLES; @@ -383,7 +392,7 @@ U32 gltf_mode_to_gl_mode(U32 mode) void Primitive::serialize(boost::json::object& dst) const { 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(mAttributes, "attributes", dst); } @@ -402,24 +411,3 @@ const Primitive& Primitive::operator=(const Value& src) 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; -} diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index 18aadce808..9914ff3b08 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -48,6 +48,17 @@ namespace LL class Primitive { public: + enum class Mode : U8 + { + POINTS, + LINES, + LINE_LOOP, + LINE_STRIP, + TRIANGLES, + TRIANGLE_STRIP, + TRIANGLE_FAN + }; + ~Primitive(); // GPU copy of mesh data @@ -66,10 +77,10 @@ namespace LL // raycast acceleration structure LLPointer mOctree; std::vector mOctreeTriangles; - + S32 mMaterial = -1; - S32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles - U32 mGLMode = LLRender::TRIANGLES; + Mode mMode = Mode::TRIANGLES; // default to triangles + LLRender::eGeomModes mGLMode = LLRender::TRIANGLES; // for use with LLRender S32 mIndices = -1; std::unordered_map mAttributes; @@ -77,7 +88,7 @@ namespace LL // must be called before buffer is unmapped and after buffer is populated with good data 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. //Line segment must be in the same coordinate frame as this Primitive const LLVolumeTriangle* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, @@ -86,12 +97,11 @@ namespace LL LLVector4a* normal = NULL, // return the surface normal at the intersection point LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); - + void serialize(boost::json::object& obj) const; const Primitive& operator=(const Value& src); - const Primitive& operator=(const tinygltf::Primitive& src); - void allocateGLResources(Asset& asset); + bool prep(Asset& asset); }; } } diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 5413a7d021..eb11c60e43 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -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& 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() { if (mUploadingAsset) @@ -153,77 +127,74 @@ void GLTFSceneManager::uploadSelection() for (auto& image : asset.mImages) { - if (!image.mData.empty()) + if (image.mTexture.notNull()) { mPendingImageUploads++; - LLPointer raw = new LLImageRaw(image.mWidth, image.mHeight, image.mComponent); - 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 - raw->verticalFlip(); - - LLPointer j2c = LLViewerTextureList::convertToUploadFile(raw); + LLPointer raw = image.mTexture->getCachedRawImage(); - std::string buffer; - buffer.assign((const char*)j2c->getData(), j2c->getDataSize()); + if (raw.notNull()) + { + LLPointer j2c = LLViewerTextureList::convertToUploadFile(raw); - LLUUID asset_id = LLUUID::generateNewID(); + std::string buffer; + buffer.assign((const char*)j2c->getData(), j2c->getDataSize()); - std::string name; - S32 idx = (S32)(&image - &asset.mImages[0]); + LLUUID asset_id = LLUUID::generateNewID(); - if (image.mName.empty()) - { + std::string name; + S32 idx = (S32)(&image - &asset.mImages[0]); - name = llformat("Image_%d", idx); - } - else - { - name = image.mName; - } - - LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) + if (image.mName.empty()) { - // TODO: handle failure - mPendingImageUploads--; - return false; - }; - - LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response) + name = llformat("Image_%d", idx); + } + else { - if (mUploadingAsset && mUploadingAsset->mImages.size() > idx) + 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--; - } - }; - - S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c); - - LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared( - 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); - - image.clearData(asset); + return false; + }; + + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response) + { + if (mUploadingAsset && mUploadingAsset->mImages.size() > idx) + { + mUploadingAsset->mImages[idx].mUri = assetId.asString(); + mPendingImageUploads--; + } + }; + + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c); + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared( + 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); + + image.clearData(asset); + } } } @@ -297,62 +268,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) { 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); + if (!asset->save(filename)) + { + LLNotificationsUtil::add("GLTFSaveFailed"); + } } } void GLTFSceneManager::load(const std::string& filename) { - tinygltf::Model model; - LLTinyGLTFHelper::loadModel(filename, model); - std::shared_ptr asset = std::make_shared(); - *asset = model; - gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions - asset->allocateGLResources(filename, model); - asset->updateTransforms(); + if (asset->load(filename)) + { + 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 - LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + // hang the asset off the currently selected object, or off of the avatar if no object is selected + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); - if (obj) - { // assign to self avatar - obj->mGLTFAsset = asset; - obj->markForUpdate(); - if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) - { - mObjects.push_back(obj); + if (obj) + { // assign to self avatar + obj->mGLTFAsset = asset; + obj->markForUpdate(); + if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) + { + mObjects.push_back(obj); + } } } + else + { + LLNotificationsUtil::add("GLTFLoadFailed"); + } } GLTFSceneManager::~GLTFSceneManager() @@ -392,32 +346,19 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp // find the Buffer with the given id in the asset if (obj->mGLTFAsset) { - for (auto& buffer : obj->mGLTFAsset->mBuffers) - { - LLUUID buffer_id; - if (LLUUID::parseUUID(buffer.mUri, &buffer_id) && buffer_id == id) - { - LLFileSystem file(id, asset_type, LLFileSystem::READ); - - buffer.mData.resize(file.getSize()); - file.read((U8*)buffer.mData.data(), buffer.mData.size()); + obj->mGLTFAsset->mPendingBuffers--; - obj->mGLTFAsset->mPendingBuffers--; - if (obj->mGLTFAsset->mPendingBuffers == 0) - { - obj->mGLTFAsset->allocateGLResources(); - GLTFSceneManager& mgr = GLTFSceneManager::instance(); - if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end()) - { - GLTFSceneManager::instance().mObjects.push_back(obj); - } - } + if (obj->mGLTFAsset->mPendingBuffers == 0) + { + obj->mGLTFAsset->prep(); + GLTFSceneManager& mgr = GLTFSceneManager::instance(); + if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end()) + { + GLTFSceneManager::instance().mObjects.push_back(obj); } } } - - } } else @@ -492,30 +433,9 @@ void GLTFSceneManager::update() { 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; mUploadingAsset->serialize(obj); - std::string json = 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(); + std::string buffer = boost::json::serialize(obj, {}); LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) { diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index 5434f6ddb2..53b4ff0e4e 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -52,8 +52,6 @@ namespace LL 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 uploadSelection(); // decompose selected asset and upload to simulator void update(); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 329ac3fc90..0afb275d13 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -515,11 +515,11 @@ bool LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, case FFSAVE_GLTF: 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 = - L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ + L"glTF Asset File (*.gltf)\0*.gltf\0" \ L"\0"; break; case FFSAVE_XML: @@ -790,7 +790,7 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, case LLFilePicker::FFSAVE_GLTF: type = "\?\?\?\?"; creator = "\?\?\?\?"; - extension = "glb,gltf"; + extension = "gltf"; break; case LLFilePicker::FFSAVE_XML: diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 8aadf1f533..27de9aea0d 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -1091,8 +1091,9 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) return false; } - S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); - S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + // allow loading up to 4x max rez but implicitly downrez to max rez before upload + 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)) { @@ -1137,6 +1138,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 world_id = LLUUID::null; diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index e0cd9d172f..e169f96e70 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -135,6 +135,7 @@ public: void delUnit(LLUUID tracking_id); bool checkTextureDimensions(std::string filename); + LLUUID getTrackingID(const LLUUID& world_id) const; LLUUID getWorldID(const LLUUID &tracking_id) const; bool isLocal(const LLUUID& world_id) const; std::string getFilename(const LLUUID &tracking_id) const; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index fd16b07985..6a61c8bac8 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -8102,15 +8102,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 { bool handleEvent(const LLSD& userdata) @@ -9793,7 +9784,6 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview"); 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 LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload"); view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow"); view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index f1fdfc548b..e35375f43c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -507,192 +507,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 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, ""); - -// 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::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 ImageUtility = new LLImageJ2C; -// LLPointer 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 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(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**) { if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 9958526a2b..0ca05b3460 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -228,6 +228,9 @@ LLGLSLShader gDeferredPBRAlphaProgram; LLGLSLShader gDeferredSkinnedPBRAlphaProgram; LLGLSLShader gDeferredPBRTerrainProgram; +LLGLSLShader gGLTFPBRMetallicRoughnessProgram; + + //helper for making a rigged variant of a given shader static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) { @@ -235,6 +238,7 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader riggedShader.mFeatures = shader.mFeatures; riggedShader.mFeatures.hasObjectSkinning = true; riggedShader.mDefines = shader.mDefines; // NOTE: Must come before addPermutation + riggedShader.addPermutation("HAS_SKIN", "1"); riggedShader.mShaderFiles = shader.mShaderFiles; riggedShader.mShaderLevel = shader.mShaderLevel; @@ -244,6 +248,49 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader return riggedShader.createShader(NULL, NULL); } + +static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged) +{ + variant.mName = shader.mName.c_str(); + variant.mFeatures = shader.mFeatures; + variant.mShaderFiles = shader.mShaderFiles; + variant.mShaderLevel = shader.mShaderLevel; + variant.mShaderGroup = shader.mShaderGroup; + + variant.mDefines = shader.mDefines; // NOTE: Must come before addPermutation + + if (alpha_blend) + { + variant.addPermutation("ALPHA_BLEND", "1"); + } + if (rigged) + { + variant.addPermutation("HAS_SKIN", "1"); + variant.mFeatures.hasObjectSkinning = true; + } + + return variant.createShader(NULL, NULL); +} + +static bool make_gltf_variants(LLGLSLShader& shader) +{ + shader.mFeatures.mGLTF = true; + shader.mGLTFVariants.resize(LLGLSLShader::NUM_GLTF_VARIANTS); + + for (U32 i = 0; i < LLGLSLShader::NUM_GLTF_VARIANTS; ++i) + { + bool alpha_blend = i & 1; + bool rigged = i & 2; + + if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged)) + { + return false; + } + } + + return true; +} + #ifdef SHOW_ASSERT // return true if there are no redundant shaders in the given vector // also checks for redundant variants @@ -329,6 +376,7 @@ void LLViewerShaderMgr::finalizeShaderList() mShaderList.push_back(&gDeferredDiffuseProgram); mShaderList.push_back(&gDeferredBumpProgram); mShaderList.push_back(&gDeferredPBROpaqueProgram); + mShaderList.push_back(&gGLTFPBRMetallicRoughnessProgram); mShaderList.push_back(&gDeferredAvatarProgram); mShaderList.push_back(&gDeferredTerrainProgram); mShaderList.push_back(&gDeferredPBRTerrainProgram); @@ -1019,6 +1067,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDPBROpaqueProgram.unload(); gPBRGlowProgram.unload(); gDeferredPBROpaqueProgram.unload(); + gGLTFPBRMetallicRoughnessProgram.unload(); gDeferredSkinnedPBROpaqueProgram.unload(); gDeferredPBRAlphaProgram.unload(); gDeferredSkinnedPBRAlphaProgram.unload(); @@ -1209,6 +1258,22 @@ bool LLViewerShaderMgr::loadShadersDeferred() llassert(success); } + if (success) + { + gGLTFPBRMetallicRoughnessProgram.mName = "GLTF PBR Metallic Roughness Shader"; + gGLTFPBRMetallicRoughnessProgram.mFeatures.hasSrgb = true; + + gGLTFPBRMetallicRoughnessProgram.mShaderFiles.clear(); + gGLTFPBRMetallicRoughnessProgram.mShaderFiles.push_back(make_pair("gltf/pbrmetallicroughnessV.glsl", GL_VERTEX_SHADER)); + gGLTFPBRMetallicRoughnessProgram.mShaderFiles.push_back(make_pair("gltf/pbrmetallicroughnessF.glsl", GL_FRAGMENT_SHADER)); + gGLTFPBRMetallicRoughnessProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gGLTFPBRMetallicRoughnessProgram.clearPermutations(); + + success = make_gltf_variants(gGLTFPBRMetallicRoughnessProgram); + + llassert(success); + } + if (success) { gPBRGlowProgram.mName = " PBR Glow Shader"; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 06c0c62c70..7f913e4153 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -335,6 +335,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } +//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) { return gTextureList.getImageFromHost(image_id, f_type, host); diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index d3d76f38e8..3c4a5c18ac 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -440,8 +440,6 @@ private: bool mForceCallbackFetch; protected: - std::string mLocalFileName; - S32 mOrigWidth; S32 mOrigHeight; @@ -692,6 +690,8 @@ public: static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ; + static LLViewerFetchedTexture* getFetchedTextureFromMemory(const U8* data, U32 size, std::string_view mimetype); + static void init() ; static void cleanup() ; }; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 0016ba6155..37ff5038cd 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -360,7 +360,7 @@ void LLViewerTextureList::shutdown() mImageList.clear(); - mInitialized = false; //prevent loading textures again. + mInitialized = false ; //prevent loading textures again. } void LLViewerTextureList::dump() @@ -518,6 +518,26 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& return imagep; } +LLViewerFetchedTexture* LLViewerTextureList::getImageFromMemory(const U8* data, U32 size, std::string_view mimetype) +{ + LLPointer image = LLImageFormatted::loadFromMemory(data, size, mimetype); + + if (image) + { + LLPointer raw_image = new LLImageRaw(); + image->decode(raw_image, 0.f); + LLPointer 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, FTType f_type, @@ -631,8 +651,8 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, imagep->forceActive() ; } - mFastCacheList.insert(imagep); - imagep->setInFastCacheList(true); + mFastCacheList.insert(imagep); + imagep->setInFastCacheList(true); return imagep ; } @@ -1310,63 +1330,63 @@ bool LLViewerTextureList::createUploadFile(const std::string& filename, LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; try { - // Load the image - LLPointer image = LLImageFormatted::createFromType(codec); - if (image.isNull()) - { - LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL; - return false; - } - if (!image->load(filename)) - { - image->setLastError("Couldn't load the image to be uploaded."); - return false; - } - // Decompress or expand it in a raw image structure - LLPointer raw_image = new LLImageRaw; - if (!image->decode(raw_image, 0.0f)) - { - image->setLastError("Couldn't decode the image to be uploaded."); - return false; - } - // Check the image constraints - if ((image->getComponents() != 3) && (image->getComponents() != 4)) - { - image->setLastError("Image files with less than 3 or more than 4 components are not supported."); - return false; - } - 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", - min_image_dimentions, - min_image_dimentions, - image->getWidth(), - image->getHeight()); - image->setLastError(reason); - return false; - } - // Convert to j2c (JPEG2000) and save the file locally - LLPointer compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square); - if (compressedImage.isNull()) - { - image->setLastError("Couldn't convert the image to jpeg2000."); - LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL; - return false; - } - if (!compressedImage->save(out_filename)) - { - image->setLastError("Couldn't create the jpeg2000 image for upload."); - LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL; - return false; - } - // Test to see if the encode and save worked - LLPointer integrity_test = new LLImageJ2C; - if (!integrity_test->loadAndValidate(out_filename)) - { - image->setLastError("The created jpeg2000 image is corrupt."); - LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL; - return false; - } + // Load the image + LLPointer image = LLImageFormatted::createFromType(codec); + if (image.isNull()) + { + LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL; + return false; + } + if (!image->load(filename)) + { + image->setLastError("Couldn't load the image to be uploaded."); + return false; + } + // Decompress or expand it in a raw image structure + LLPointer raw_image = new LLImageRaw; + if (!image->decode(raw_image, 0.0f)) + { + image->setLastError("Couldn't decode the image to be uploaded."); + return false; + } + // Check the image constraints + if ((image->getComponents() != 3) && (image->getComponents() != 4)) + { + image->setLastError("Image files with less than 3 or more than 4 components are not supported."); + return false; + } + 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", + min_image_dimentions, + min_image_dimentions, + image->getWidth(), + image->getHeight()); + image->setLastError(reason); + return false; + } + // Convert to j2c (JPEG2000) and save the file locally + LLPointer compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square); + if (compressedImage.isNull()) + { + image->setLastError("Couldn't convert the image to jpeg2000."); + LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL; + return false; + } + if (!compressedImage->save(out_filename)) + { + image->setLastError("Couldn't create the jpeg2000 image for upload."); + LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL; + return false; + } + // Test to see if the encode and save worked + LLPointer integrity_test = new LLImageJ2C; + if (!integrity_test->loadAndValidate( out_filename )) + { + image->setLastError("The created jpeg2000 image is corrupt."); + LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL; + return false; + } } catch (...) { diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index da1c013335..ba468bab7e 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -192,6 +192,8 @@ private: const LLUUID& force_id = LLUUID::null ); + LLViewerFetchedTexture* getImageFromMemory(const U8* data, U32 size, std::string_view mimetype); + LLViewerFetchedTexture* createImage(const LLUUID &image_id, FTType f_type, bool usemipmap = true, diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8c9561fe64..daf8dd4208 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2879,14 +2879,6 @@ function="World.EnvPreset" - - - - diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index e3b9f744e9..1584de6880 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12470,6 +12470,28 @@ are wearing now. yestext="OK"/> + + Failed to load GLTF file. See log for details. + fail + + + + + Failed to save GLTF file. See log for details. + fail + + + Date: Wed, 29 May 2024 16:56:39 -0500 Subject: #1530 Increase joint limit for GLTF Assets (#1582) * Migrate GLTF scene rendering to its own shaders * Add support for ambient occlusion map separate from metallic roughness map (or absent) * Use UBO's for GLTF joints * Better error handling of downloading GLTF assets --- indra/llrender/llgl.cpp | 5 + indra/llrender/llgl.h | 1 + indra/llrender/llglslshader.cpp | 25 ++- indra/llrender/llglslshader.h | 28 ++- indra/llrender/llshadermgr.cpp | 4 +- indra/llrender/llshadermgr.h | 4 +- indra/llrender/llvertexbuffer.cpp | 5 +- .../shaders/class1/deferred/deferredUtil.glsl | 37 ++++ .../shaders/class1/deferred/pbralphaV.glsl | 4 +- .../shaders/class1/gltf/pbrmetallicroughnessF.glsl | 185 ++++++++++++++--- .../shaders/class1/gltf/pbrmetallicroughnessV.glsl | 74 ++++++- .../shaders/class2/deferred/pbralphaF.glsl | 58 ++---- .../shaders/class3/deferred/materialF.glsl | 1 - indra/newview/gltf/accessor.cpp | 8 +- indra/newview/gltf/animation.cpp | 66 ++++++ indra/newview/gltf/asset.cpp | 229 +-------------------- indra/newview/gltf/asset.h | 12 +- indra/newview/gltf/common.h | 16 ++ indra/newview/gltfscenemanager.cpp | 201 +++++++++++++++++- indra/newview/gltfscenemanager.h | 19 +- indra/newview/lldrawpoolalpha.cpp | 3 - indra/newview/lldrawpoolavatar.cpp | 4 +- indra/newview/lldrawpoolpbropaque.cpp | 15 +- indra/newview/llenvironment.cpp | 16 +- indra/newview/llreflectionmapmanager.cpp | 50 ++--- indra/newview/llskinningutil.cpp | 6 + indra/newview/llskinningutil.h | 1 + indra/newview/llviewershadermgr.cpp | 48 ++++- indra/newview/llviewershadermgr.h | 3 + indra/newview/pipeline.cpp | 6 +- 30 files changed, 734 insertions(+), 400 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index ac697b72be..0586c34e50 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1238,6 +1238,11 @@ bool LLGLManager::initGL() glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples); glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords); 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) { diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 75a7c5d3b2..2f538d0844 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -87,6 +87,7 @@ public: S32 mGLMaxIndexRange; S32 mGLMaxTextureSize; F32 mMaxAnisotropy = 0.f; + S32 mMaxUniformBlockSize = 0; // GL 4.x capabilities bool mHasCubeMapArray = false; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index ecd0c6908b..8ea134393a 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -983,17 +983,25 @@ bool LLGLSLShader::mapUniforms(const vector* uniforms) } //........................................................................................................................................ - if (mFeatures.hasReflectionProbes) // 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 - static const GLuint BLOCKBINDING = 1; //picked by us - //Get the index, similar to a uniform location - GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, "ReflectionProbes"); + // 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 + const char* ubo_names[] = + { + "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) { - //Set this index to a binding index - glUniformBlockBinding(mProgramObject, UBOBlockIndex, BLOCKBINDING); + glUniformBlockBinding(mProgramObject, UBOBlockIndex, i); } } + unbind(); LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL; @@ -1049,9 +1057,10 @@ void LLGLSLShader::bind() } } -void LLGLSLShader::bind(LLGLSLShader::GLTFVariant variant) +void LLGLSLShader::bind(U32 variant) { llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); + llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS); mGLTFVariants[variant].bind(); } diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index fa01d212e1..8ebea2deca 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -146,6 +146,14 @@ public: SG_COUNT } eGroup; + enum UniformBlock : GLuint + { + UB_REFLECTION_PROBES, + UB_GLTF_JOINTS, + NUM_UNIFORM_BLOCKS + }; + + static std::set sInstances; static bool sProfileEnabled; @@ -320,20 +328,24 @@ public: LLGLSLShader* mRiggedVariant = nullptr; // variants for use by GLTF renderer - // "this" is considered to be OPAQUE - enum GLTFVariant + // bit 0 = alpha mode blend (1) or opaque (0) + // bit 1 = rigged (1) or static (0) + struct GLTFVariant { - STATIC_OPAQUE, - STATIC_BLEND, - RIGGED_OPAQUE, - RIGGED_BLEND, - NUM_GLTF_VARIANTS + constexpr static U32 RIGGED = 2; + constexpr static U32 ALPHA = 1; + constexpr static U32 OPAQUE_STATIC = 0; + constexpr static U32 ALPHA_STATIC = 1; + constexpr static U32 OPAQUE_RIGGED = 2; + constexpr static U32 ALPHA_RIGGED = 3; }; + constexpr static U32 NUM_GLTF_VARIANTS = 4; + std::vector mGLTFVariants; //helper to bind GLTF variant - void bind(GLTFVariant variant); + void bind(U32 variant); // hacky flag used for optimization in LLDrawPoolAlpha bool mCanBindFast = false; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 694bcbeeb9..4e8adb2fb3 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1225,6 +1225,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("diffuseMap"); mReservedUniforms.push_back("altDiffuseMap"); mReservedUniforms.push_back("specularMap"); + mReservedUniforms.push_back("metallicRoughnessMap"); + mReservedUniforms.push_back("normalMap"); + mReservedUniforms.push_back("occlusionMap"); mReservedUniforms.push_back("emissiveMap"); mReservedUniforms.push_back("bumpMap"); mReservedUniforms.push_back("bumpMap2"); @@ -1348,7 +1351,6 @@ void LLShaderMgr::initAttribsAndUniforms() llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1); - mReservedUniforms.push_back("normalMap"); mReservedUniforms.push_back("positionMap"); mReservedUniforms.push_back("diffuseRect"); mReservedUniforms.push_back("specularRect"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index c3e5a2aafd..03803c0e96 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -93,6 +93,9 @@ public: DIFFUSE_MAP, // "diffuseMap" ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap" SPECULAR_MAP, // "specularMap" + METALLIC_ROUGHNESS_MAP, // "metallicRoughnessMap" + NORMAL_MAP, // "normalMap" + OCCLUSION_MAP, // "occlusionMap" EMISSIVE_MAP, // "emissiveMap" BUMP_MAP, // "bumpMap" BUMP_MAP2, // "bumpMap2" @@ -202,7 +205,6 @@ public: DEFERRED_SHADOW3, // "shadowMap3" DEFERRED_SHADOW4, // "shadowMap4" DEFERRED_SHADOW5, // "shadowMap5" - DEFERRED_NORMAL, // "normalMap" DEFERRED_POSITION, // "positionMap" DEFERRED_DIFFUSE, // "diffuseRect" DEFERRED_SPECULAR, // "specularRect" diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 7caf20f40b..8cb124d406 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -687,6 +687,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; for (U32 i = 0; i < count; ++i) { @@ -724,6 +725,7 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of } } } +#endif } return true; @@ -1036,8 +1038,7 @@ bool LLVertexBuffer::updateNumIndices(U32 nindices) bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices) { - if (nverts < 0 || nindices < 0 || - nverts > 65536) + if (nverts < 0 || nindices < 0) { LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl index 385920f622..8b23037934 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -496,6 +496,43 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, 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) { vec3 f0 = vec3(0.04); diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl index d0fc362db9..ae179d3f37 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl @@ -51,8 +51,6 @@ uniform vec4[2] texture_emissive_transform; out vec3 vary_fragcoord; -uniform float near_clip; - in vec3 position; in vec4 diffuse_color; in vec3 normal; @@ -88,7 +86,7 @@ void main() #endif 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); normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0); diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index dbee58b76a..a59127ec77 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -1,24 +1,24 @@ -/** +/** * @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$ */ @@ -33,11 +33,82 @@ uniform sampler2D diffuseMap; //always in sRGB space uniform float metallicFactor; uniform float roughnessFactor; uniform vec3 emissiveColor; -uniform sampler2D bumpMap; +uniform sampler2D normalMap; uniform sampler2D emissiveMap; -uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness +uniform sampler2D metallicRoughnessMap; +uniform sampler2D occlusionMap; + +#ifdef ALPHA_BLEND +out vec4 frag_color; + +in vec3 vary_fragcoord; + +#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; +vec3 srgb_to_linear(vec3 c); +vec3 linear_to_srgb(vec3 c); + +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); + +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 mirrorClip(vec3 pos); +void waterClip(vec3 pos); + +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); + + +#else out vec4 frag_data[4]; +#endif + in vec3 vary_position; in vec4 vertex_color; @@ -50,7 +121,7 @@ in vec2 normal_texcoord; in vec2 metallic_roughness_texcoord; in vec2 emissive_texcoord; -uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() +uniform float minimum_alpha; vec3 linear_to_srgb(vec3 c); vec3 srgb_to_linear(vec3 c); @@ -62,9 +133,11 @@ void mirrorClip(vec3 pos); uniform mat3 normal_matrix; + void main() { - mirrorClip(vary_position); + vec3 pos = vary_position; + mirrorClip(pos); vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; basecolor.rgb = srgb_to_linear(basecolor.rgb); @@ -79,39 +152,97 @@ void main() vec3 col = basecolor.rgb; // from mikktspace.com - vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0; + 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 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); + vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); // RGB = Occlusion, Roughness, Metal // default values, see LLViewerTexture::sDefaultPBRORMImagep // occlusion 1.0 // roughness 0.0 // metal 0.0 - vec3 spec = texture(specularMap, metallic_roughness_texcoord.xy).rgb; - - spec.g *= roughnessFactor; - spec.b *= metallicFactor; + vec3 orm = texture(metallicRoughnessMap, metallic_roughness_texcoord.xy).rgb; + orm.r = texture(occlusionMap, metallic_roughness_texcoord.xy).r; + orm.g *= roughnessFactor; + orm.b *= metallicFactor; vec3 emissive = emissiveColor; emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - tnorm *= gl_FrontFacing ? 1.0 : -1.0; + norm *= gl_FrontFacing ? 1.0 : -1.0; + +#ifdef ALPHA_BLEND + vec3 color = vec3(0,0,0); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + + float scol = 1.0; + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + calcAtmosphericVarsLinear(pos.xyz, norm, light_dir, sunlit, amblit, additive, atten); + + 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; + + // emissiveColor is the emissive color factor from GLTF and is already in linear space + vec3 colorEmissive = emissiveColor; + // emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear + colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); + + // 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(col.rgb, metallic, diffuseColor, specularColor); + + vec3 v = -normalize(pos.xyz); + + color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, 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; - //spec.rgb = vec3(1,1,0); - //col = vec3(0,0,0); - //emissive = vary_tangent.xyz*0.5+0.5; - //emissive = vec3(sign*0.5+0.5); - //emissive = vNt * 0.5 + 0.5; - //emissive = tnorm*0.5+0.5; + frag_color = max(vec4(color.rgb,a), vec4(0)); +#else // See: C++: addDeferredAttachments(), GLSL: softenLightF - frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse - frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. - frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags - frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive + frag_data[0] = max(vec4(col, 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 } diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl index 0add509002..403ca8b2db 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -29,7 +29,6 @@ uniform mat4 modelview_matrix; #ifdef HAS_SKIN uniform mat4 projection_matrix; -mat4 getObjectSkinnedTransform(); #else uniform mat3 normal_matrix; uniform mat4 modelview_projection_matrix; @@ -62,21 +61,85 @@ out vec3 vary_position; vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); + +#ifdef ALPHA_BLEND +out vec3 vary_fragcoord; +#endif + + +#ifdef HAS_SKIN +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 = fract(weight4); + vec4 index = floor(weight4); + + index = min(index, vec4(MAX_JOINTS_PER_GLTF_OBJECT-1)); + index = max(index, vec4( 0.0)); + + w *= 1.0/(w.x+w.y+w.z+w.w); + + int i1 = int(index.x); + int i2 = int(index.y); + int i3 = int(index.z); + int i4 = int(index.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_MESH_OBJECT-1]; +#endif + +} + +#endif + void main() { #ifdef HAS_SKIN - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = getGLTFSkinTransform(); mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; vary_position = pos; - gl_Position = projection_matrix*vec4(pos,1.0); + + vec4 vert = projection_matrix * vec4(pos, 1.0); + gl_Position = vert; #else vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; //transform vertex - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + 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); @@ -99,6 +162,9 @@ void main() vary_normal = n; vertex_color = diffuse_color; +#ifdef ALPHA_BLEND + vary_fragcoord = vert.xyz; +#endif } diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl index 059c2a64ce..f4a8051427 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl @@ -1,24 +1,24 @@ -/** +/** * @file class1\deferred\pbralphaF.glsl * * $LicenseInfo:firstyear=2022&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$ */ @@ -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); float calcLegacyDistanceAttenuation(float distance, float falloff); 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); void mirrorClip(vec3 pos); @@ -111,15 +111,15 @@ vec3 pbrBaseLight(vec3 diffuseColor, vec3 additive, vec3 atten); -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera vec3 l); //surface point to light -vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 p, // pixel position @@ -127,33 +127,7 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, 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; -} + float lightSize, float falloff, float is_pointlight, float ambiance); void main() { @@ -181,7 +155,7 @@ void main() 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 ); @@ -218,7 +192,7 @@ void main() 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(col.rgb, metallic, diffuseColor, specularColor); @@ -230,7 +204,7 @@ void main() vec3 light = vec3(0); // 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(2) @@ -245,7 +219,7 @@ void main() 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)); } @@ -295,7 +269,7 @@ void main() // emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - + float a = basecolor.a*vertex_color.a; color += colorEmissive; diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index d3e19cf4a8..26ab0406f6 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -77,7 +77,6 @@ uniform float is_mirror; uniform vec3 sun_dir; uniform vec3 moon_dir; -in vec2 vary_fragcoord; uniform mat4 proj_mat; uniform mat4 inv_proj; diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 0619c617e2..5f4e3ca3a8 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -132,7 +132,13 @@ bool Buffer::prep(Asset& asset) { // loaded from an asset, fetch the buffer data from the asset store LLFileSystem file(id, LLAssetType::AT_GLTF_BIN, LLFileSystem::READ); - mData.resize(file.getSize()); + 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; diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp index f18bba788c..45e9e1ddef 100644 --- a/indra/newview/gltf/animation.cpp +++ b/indra/newview/gltf/animation.cpp @@ -28,6 +28,7 @@ #include "asset.h" #include "buffer_util.h" +#include "../llskinningutil.h" using namespace LL::GLTF; using namespace boost::json; @@ -362,6 +363,71 @@ const Animation& Animation::operator=(const Value& src) return *this; } +Skin::~Skin() +{ + if (mUBO) + { + glDeleteBuffers(1, &mUBO); + } +} + +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 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 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) diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 485984fac1..7870eb28b0 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -84,7 +84,7 @@ namespace LL void Scene::updateTransforms(Asset& asset) { mat4 identity = glm::identity(); - + for (auto& nodeIndex : mNodes) { Node& node = asset.mNodes[nodeIndex]; @@ -116,7 +116,7 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); mAssetMatrix = parentMatrix * mMatrix; - + mAssetMatrixInv = glm::inverse(mAssetMatrix); S32 my_index = this - &asset.mNodes[0]; @@ -356,94 +356,6 @@ const Image& Image::operator=(const Value& src) return *this; } -void Asset::render(bool opaque, bool rigged) -{ - if (rigged) - { - gGL.loadIdentity(); - } - - for (auto& node : mNodes) - { - if (node.mSkin != INVALID_INDEX) - { - if (rigged) - { - Skin& skin = mSkins[node.mSkin]; - skin.uploadMatrixPalette(*this, node); - } - else - { - //skip static nodes if we're rendering rigged - continue; - } - } - else if (rigged) - { - // skip rigged nodes if we're not rendering rigged - continue; - } - - if (node.mMesh != INVALID_INDEX) - { - Mesh& mesh = mMeshes[node.mMesh]; - for (auto& primitive : mesh.mPrimitives) - { - if (!rigged) - { - gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); - } - bool cull = true; - if (primitive.mMaterial != INVALID_INDEX) - { - Material& material = mMaterials[primitive.mMaterial]; - bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND; - - if (mat_opaque != opaque) - { - continue; - } - - material.bind(*this); - - cull = !material.mDoubleSided; - } - else - { - if (!opaque) - { - continue; - } - LLFetchedGLTFMaterial::sDefault.bind(); - } - - LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0); - - primitive.mVertexBuffer->setBuffer(); - if (primitive.mVertexBuffer->getNumIndices() > 0) - { - primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); - } - else - { - primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); - } - - } - } - } -} - -void Asset::renderOpaque() -{ - render(true); -} - -void Asset::renderTransparent() -{ - render(false); -} - void Asset::update() { F32 dt = gFrameTimeSeconds - mLastUpdateTime; @@ -461,6 +373,11 @@ void Asset::update() } updateTransforms(); + + for (auto& skin : mSkins) + { + skin.uploadMatrixPalette(*this); + } } } @@ -1063,90 +980,6 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough return !(*this == rhs); } -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 Material::bind(Asset& asset) -{ - // 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 || (mAlphaMode == Material::AlphaMode::BLEND)) - { - if (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 (mPbrMetallicRoughness.mBaseColorFactor.a > 0.f) - { - min_alpha = mAlphaCutoff / mPbrMetallicRoughness.mBaseColorFactor.a; - } - else - { - min_alpha = 1024.f; - } - } - shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); - } - - bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, 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::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); - bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); - bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); - - // NOTE: base color factor is baked into vertex stream - - shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor); - shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mPbrMetallicRoughness.mMetallicFactor); - shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(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); - } -} - void Material::serialize(object& dst) const { write(mName, "name", dst); @@ -1264,52 +1097,4 @@ const Sampler& Sampler::operator=(const Value& src) return *this; } -void Skin::uploadMatrixPalette(Asset& asset, Node& node) -{ - // prepare matrix palette - - // modelview will be applied by the shader, so assume matrix palette is in asset space - std::vector t_mp; - - t_mp.resize(mJoints.size()); - - for (U32 i = 0; i < mJoints.size(); ++i) - { - Node& joint = asset.mNodes[mJoints[i]]; - t_mp[i] = joint.mRenderMatrix * mInverseBindMatricesData[i]; - } - - std::vector glmp; - - glmp.resize(mJoints.size() * 12); - - F32* mp = glmp.data(); - - for (U32 i = 0; i < mJoints.size(); ++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]; - } - - LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, - mJoints.size(), - GL_FALSE, - (GLfloat*)glmp.data()); -} diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index 761e746aa1..022fc484c2 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -118,8 +118,6 @@ namespace LL F32 mAlphaCutoff = 0.5f; bool mDoubleSided = false; - // bind for rendering - void bind(Asset& asset); const Material& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -197,14 +195,18 @@ namespace LL class Skin { public: + ~Skin(); + S32 mInverseBindMatrices = INVALID_INDEX; S32 mSkeleton = INVALID_INDEX; + + U32 mUBO = 0; std::vector mJoints; std::string mName; std::vector mInverseBindMatricesData; bool prep(Asset& asset); - void uploadMatrixPalette(Asset& asset, Node& node); + void uploadMatrixPalette(Asset& asset); const Skin& operator=(const Value& src); void serialize(boost::json::object& dst) const; @@ -332,10 +334,6 @@ namespace LL // update node render transforms 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 // input and output values must be in this asset's local coordinate frame S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, diff --git a/indra/newview/gltf/common.h b/indra/newview/gltf/common.h index 59f2ba38db..4f660d7cfc 100644 --- a/indra/newview/gltf/common.h +++ b/indra/newview/gltf/common.h @@ -36,6 +36,7 @@ #include "glm/ext/quaternion_float.hpp" #include "glm/gtx/quaternion.hpp" #include "glm/gtx/matrix_decompose.hpp" +#include // Common types and constants used in the GLTF implementation namespace LL @@ -62,6 +63,21 @@ namespace LL 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; } } diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index eb11c60e43..a20954d7d1 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -351,11 +351,18 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp if (obj->mGLTFAsset->mPendingBuffers == 0) { - obj->mGLTFAsset->prep(); - GLTFSceneManager& mgr = GLTFSceneManager::instance(); - if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end()) + if (obj->mGLTFAsset->prep()) { - 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; } } } @@ -528,7 +535,6 @@ void GLTFSceneManager::render(bool opaque, bool rigged) } Asset* asset = mObjects[i]->mGLTFAsset.get(); - gGL.pushMatrix(); LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform(); @@ -540,12 +546,195 @@ void GLTFSceneManager::render(bool opaque, bool rigged) mat4 mdv = glm::make_mat4(modelview.getF32ptr()); 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, opaque, rigged); gGL.popMatrix(); } } +void GLTFSceneManager::render(Asset& asset, bool opaque, bool rigged) +{ + U32 variant = 0; + if (rigged) + { + variant |= LLGLSLShader::GLTFVariant::RIGGED; + } + if (!opaque) + { + variant |= LLGLSLShader::GLTFVariant::ALPHA; + } + + 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); + } + else + { + //skip static nodes if we're rendering rigged + continue; + } + } + else if (rigged) + { + // skip rigged nodes if we're not rendering rigged + continue; + } + + if (node.mMesh != INVALID_INDEX) + { + Mesh& mesh = asset.mMeshes[node.mMesh]; + for (auto& primitive : mesh.mPrimitives) + { + if (!rigged) + { + gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); + } + bool cull = true; + if (primitive.mMaterial != INVALID_INDEX) + { + Material& material = asset.mMaterials[primitive.mMaterial]; + bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND; + + if (mat_opaque != opaque) + { + continue; + } + + bind(asset, material); + + cull = !material.mDoubleSided; + } + else + { + if (!opaque) + { + continue; + } + LLFetchedGLTFMaterial::sDefault.bind(); + } + + LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0); + + primitive.mVertexBuffer->setBuffer(); + if (primitive.mVertexBuffer->getNumIndices() > 0) + { + primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); + } + else + { + primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); + } + } + } + } +} + +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) { glh::matrix4f m((F32*)mat.mMatrix); diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index 53b4ff0e4e..fcde6cf1f7 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -28,17 +28,11 @@ #include "llsingleton.h" #include "llviewerobject.h" +#include "gltf/common.h" + class LLVOVolume; class LLDrawable; -namespace LL -{ - namespace GLTF - { - class Asset; - } -} - namespace LL { class GLTFSceneManager : public LLSimpleton @@ -56,6 +50,11 @@ namespace LL void update(); void render(bool opaque, bool rigged = false); + void render(LL::GLTF::Asset& asset, bool opaque, bool rigged); + + // bind the given material for rendering + void bind(LL::GLTF::Asset& asset, LL::GLTF::Material& material); + void renderOpaque(); void renderAlpha(); @@ -71,7 +70,7 @@ namespace LL LLVector4a* normal, // return the surface normal 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); void renderDebug(); @@ -88,6 +87,8 @@ namespace LL U32 mPendingImageUploads = 0; U32 mPendingBinaryUploads = 0; U32 mPendingGLTFUploads = 0; + + U32 mJointUBO = 0; }; } diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 201c337b26..2a376a40b2 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -263,10 +263,7 @@ void LLDrawPoolAlpha::forwardRender(bool rigged) if (rigged) { // draw GLTF scene to depth buffer before rigged alpha - gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram); LL::GLTFSceneManager::instance().render(false, false); - - gPipeline.bindDeferredShader(*gDeferredPBRAlphaProgram.mRiggedVariant); LL::GLTFSceneManager::instance().render(false, true); } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 25bce7bced..9afc705d3e 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -555,7 +555,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor() sVertexProgram = &gDeferredImpostorProgram; 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); sVertexProgram->bind(); sVertexProgram->setMinimumAlpha(0.01f); @@ -566,7 +566,7 @@ void LLDrawPoolAvatar::endDeferredImpostor() LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR sShaderLevel = mShaderLevel; - sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); + sVertexProgram->disableTexture(LLViewerShaderMgr::NORMAL_MAP); sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gPipeline.unbindDeferredShader(*sVertexProgram); diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp index a32b6b1687..5eb10fe335 100644 --- a/indra/newview/lldrawpoolpbropaque.cpp +++ b/indra/newview/lldrawpoolpbropaque.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldrawpoolpbropaque.cpp * @brief LLDrawPoolGLTFPBR class implementation * * $LicenseInfo:firstyear=2022&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$ */ @@ -54,11 +54,10 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass) { llassert(!LLPipeline::sRenderingHUDs); - gDeferredPBROpaqueProgram.bind(); - LL::GLTFSceneManager::instance().renderOpaque(); - pushGLTFBatches(mRenderType); + gDeferredPBROpaqueProgram.bind(); + pushGLTFBatches(mRenderType); gDeferredPBROpaqueProgram.bind(true); LL::GLTFSceneManager::instance().render(true, true); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index fabba1972e..e075562e52 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1680,15 +1680,15 @@ void LLEnvironment::update(const LLViewerCamera * cam) end_shaders = LLViewerShaderMgr::instance()->endShaders(); for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) { - if ((shaders_iter->mProgramObject != 0) - && (gPipeline.canUseWindLightShaders() - || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) + shaders_iter->mUniformsDirty = true; + if (shaders_iter->mRiggedVariant) { - shaders_iter->mUniformsDirty = true; - if (shaders_iter->mRiggedVariant) - { - shaders_iter->mRiggedVariant->mUniformsDirty = true; - } + shaders_iter->mRiggedVariant->mUniformsDirty = true; + } + + for (auto& variant : shaders_iter->mGLTFVariants) + { + variant.mUniformsDirty = true; } } } diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 2c01495934..f62cac3276 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -67,7 +67,7 @@ void load_exr(const std::string& filename) const char* err = NULL; // or nullptr in C++11 int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err); - if (ret == TINYEXR_SUCCESS) + if (ret == TINYEXR_SUCCESS) { U32 texName = 0; LLImageGL::generateTextures(1, &texName); @@ -87,12 +87,12 @@ void load_exr(const std::string& filename) gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } - else + else { LLSD notif_args; notif_args["WHAT"] = filename; notif_args["REASON"] = "Unknown"; - if (err) + if (err) { notif_args["REASON"] = std::string(err); FreeEXRErrorMessage(err); // release memory of error message. @@ -231,7 +231,7 @@ void LLReflectionMapManager::update() { U32 res = mProbeResolution; U32 count = log2((F32)res) + 0.5f; - + mMipChain.resize(count); for (int i = 0; i < count; ++i) { @@ -241,7 +241,7 @@ void LLReflectionMapManager::update() } llassert(mProbes[0] == mDefaultProbe); - + LLVector4a camera_pos; camera_pos.load3(LLViewerCamera::instance().getOrigin().mV); @@ -256,7 +256,7 @@ void LLReflectionMapManager::update() } mKillList.clear(); - + // process create list for (auto& probe : mCreateList) { @@ -272,12 +272,12 @@ void LLReflectionMapManager::update() bool did_update = false; - + static LLCachedControl sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1); static LLCachedControl sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3); bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; - + LLReflectionMap* closestDynamic = nullptr; LLReflectionMap* oldestProbe = nullptr; @@ -339,7 +339,7 @@ void LLReflectionMapManager::update() --i; continue; } - + if (probe != mDefaultProbe && (!probe->isRelevant() || mPaused)) { // skip irrelevant probes (or all non-default probes if paused) @@ -442,7 +442,7 @@ void LLReflectionMapManager::update() { LLReflectionMap* probe = oldestProbe; llassert(probe->mCubeIndex != -1); - + probe->autoAdjustOrigin(); sUpdateCount++; @@ -636,7 +636,7 @@ void LLReflectionMapManager::doProbeUpdate() llassert(mUpdatingProbe != nullptr); updateProbeFace(mUpdatingProbe, mUpdatingFace); - + bool debug_updates = gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PROBE_UPDATES) && mUpdatingProbe->mViewerObject; if (++mUpdatingFace == 6) @@ -689,11 +689,11 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) touch_default_probe(probe); gPipeline.pushRenderTypeMask(); - + //only render sky, water, terrain, and clouds 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); - + probe->update(mRenderTarget.getWidth(), face); gPipeline.popRenderTypeMask(); @@ -702,7 +702,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) { probe->update(mRenderTarget.getWidth(), face); } - + gPipeline.mRT = &gPipeline.mMainRT; S32 sourceIdx = mReflectionProbeCount; @@ -779,12 +779,12 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1])); } - + gReflectionMipProgram.uniform1f(resScale, 1.f/(mProbeResolution*2)); - + gPipeline.mScreenTriangleVB->setBuffer(); gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - + res /= 2; S32 mip = i - (mMipChain.size() - mips); @@ -874,7 +874,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx); gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD); - + mVertexBuffer->setBuffer(); int start_mip = 0; // 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 { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear"); - + for (auto& other : probe->mNeighbors) { 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(); F32 ambscale = is_ambiance_pass ? 0.f : 1.f; F32 radscale = is_ambiance_pass ? 0.5f : 1.f; - + for (auto* refmap : mReflectionMaps) { if (refmap == nullptr) @@ -1194,7 +1194,7 @@ void LLReflectionMapManager::updateUniforms() { // fill in gaps in refBucket S32 probe_idx = mReflectionProbeCount; - + for (int i = 0; i < 256; ++i) { if (i < count) @@ -1266,7 +1266,7 @@ void LLReflectionMapManager::setUniforms() { 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); LLStrider v; - + buff->getVertexStrider(v); - + v[0] = LLVector3(-1, -1, -1); v[1] = LLVector3(1, -1, -1); v[2] = LLVector3(-1, 1, -1); @@ -1471,7 +1471,7 @@ void LLReflectionMapManager::cleanup() mReflectionMaps.clear(); mUpdatingFace = 0; - + mDefaultProbe = nullptr; mUpdatingProbe = nullptr; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 438b04ff39..4ffbd8a562 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -97,6 +97,12 @@ U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin) 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) { if (skin->mInvalidJointsScrubbed) diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index bd2f8ea04e..aa0c0075af 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -40,6 +40,7 @@ class LLJointRiggingInfoTab; namespace LLSkinningUtil { S32 getMaxJointCount(); + S32 getMaxGLTFJointCount(); U32 getMeshJointCount(const LLMeshSkinInfo *skin); void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 0ca05b3460..e53e90b703 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -249,7 +249,7 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader } -static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged) +static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool use_sun_shadow) { variant.mName = shader.mName.c_str(); variant.mFeatures = shader.mFeatures; @@ -259,20 +259,50 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool variant.mDefines = shader.mDefines; // NOTE: Must come before addPermutation + variant.addPermutation("MAX_JOINTS_PER_GLTF_OBJECT", std::to_string(LLSkinningUtil::getMaxGLTFJointCount())); + + if (rigged) + { + variant.addPermutation("HAS_SKIN", "1"); + } + if (alpha_blend) { variant.addPermutation("ALPHA_BLEND", "1"); + + variant.mFeatures.calculatesLighting = false; + variant.mFeatures.hasLighting = false; + variant.mFeatures.isAlphaLighting = true; + variant.mFeatures.hasSrgb = true; + variant.mFeatures.calculatesAtmospherics = true; + variant.mFeatures.hasAtmospherics = true; + variant.mFeatures.hasGamma = true; + variant.mFeatures.hasShadows = use_sun_shadow; + variant.mFeatures.isDeferred = true; // include deferredUtils + variant.mFeatures.hasReflectionProbes = true; + + if (use_sun_shadow) + { + variant.addPermutation("HAS_SUN_SHADOW", "1"); + } + + bool success = variant.createShader(NULL, NULL); + llassert(success); + + // Alpha Shader Hack + // See: LLRender::syncMatrices() + variant.mFeatures.calculatesLighting = true; + variant.mFeatures.hasLighting = true; + + return success; } - if (rigged) + else { - variant.addPermutation("HAS_SKIN", "1"); - variant.mFeatures.hasObjectSkinning = true; + return variant.createShader(NULL, NULL); } - - return variant.createShader(NULL, NULL); } -static bool make_gltf_variants(LLGLSLShader& shader) +static bool make_gltf_variants(LLGLSLShader& shader, bool use_sun_shadow) { shader.mFeatures.mGLTF = true; shader.mGLTFVariants.resize(LLGLSLShader::NUM_GLTF_VARIANTS); @@ -282,7 +312,7 @@ static bool make_gltf_variants(LLGLSLShader& shader) bool alpha_blend = i & 1; bool rigged = i & 2; - if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged)) + if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, use_sun_shadow)) { return false; } @@ -1269,7 +1299,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gGLTFPBRMetallicRoughnessProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gGLTFPBRMetallicRoughnessProgram.clearPermutations(); - success = make_gltf_variants(gGLTFPBRMetallicRoughnessProgram); + success = make_gltf_variants(gGLTFPBRMetallicRoughnessProgram, use_sun_shadow); llassert(success); } diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index f0de9e9715..60ce8c430b 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -287,6 +287,9 @@ extern LLGLSLShader gDeferredPBROpaqueProgram; extern LLGLSLShader gDeferredPBRAlphaProgram; extern LLGLSLShader gHUDPBRAlphaProgram; +// GLTF shaders +extern LLGLSLShader gGLTFPBRMetallicRoughnessProgram; + // Encodes detail level for dropping textures, in accordance with the GLTF spec where possible // 0 is highest detail, -1 drops emissive, etc // Dropping metallic roughness is off-spec - Reserve for potato machines as needed diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a0d2116eaa..249e66d098 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6825,7 +6825,7 @@ void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) mGlow[1].bindTexture(0, channel); } - channel = gLuminanceProgram.enableTexture(LLShaderMgr::DEFERRED_NORMAL); + channel = gLuminanceProgram.enableTexture(LLShaderMgr::NORMAL_MAP); if (channel > -1) { // bind the normal map to get the environment mask @@ -7632,7 +7632,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } - channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage()); + channel = shader.enableTexture(LLShaderMgr::NORMAL_MAP, deferred_target->getUsage()); if (channel > -1) { deferred_target->bindTexture(2, channel, LLTexUnit::TFO_POINT); // frag_data[2] @@ -8667,7 +8667,7 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) LLRenderTarget* deferred_light_target = &mRT->deferredLight; stop_glerror(); - shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage()); + shader.disableTexture(LLShaderMgr::NORMAL_MAP, deferred_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, deferred_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_EMISSIVE, deferred_target->getUsage()); -- cgit v1.3 From d1a8a9d0c39bff726e8c298c5bad309055726a30 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 30 May 2024 16:28:56 -0500 Subject: #1596 Fix for GLTF uploads failing after loading from .glb file (#1602) --- indra/newview/gltfscenemanager.cpp | 18 +++++++++++++++--- indra/newview/llviewertexture.cpp | 6 ++++++ indra/newview/llviewertexture.h | 6 ++++++ indra/newview/llviewertexturelist.cpp | 19 ++++++++++++++++--- indra/newview/llviewertexturelist.h | 3 ++- 5 files changed, 45 insertions(+), 7 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index a20954d7d1..df922b8f3d 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -131,7 +131,21 @@ void GLTFSceneManager::uploadSelection() { mPendingImageUploads++; - LLPointer raw = image.mTexture->getCachedRawImage(); + LLPointer raw; + + if (image.mBufferView != INVALID_INDEX) + { + BufferView& view = asset.mBufferViews[image.mBufferView]; + Buffer& buffer = asset.mBuffers[view.mBuffer]; + + raw = LLViewerTextureManager::getRawImageFromMemory(buffer.mData.data() + view.mByteOffset, view.mByteLength, image.mMimeType); + + image.clearData(asset); + } + else + { + raw = image.mTexture->getCachedRawImage(); + } if (raw.notNull()) { @@ -192,8 +206,6 @@ void GLTFSceneManager::uploadSelection() failure)); upload_new_resource(uploadInfo); - - image.clearData(asset); } } } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 7f913e4153..545bfeaafa 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -335,6 +335,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s 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) { diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 3c4a5c18ac..dc9182bf1b 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -690,6 +690,12 @@ public: 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() ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 37ff5038cd..930bf4230e 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -518,15 +518,28 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& return imagep; } -LLViewerFetchedTexture* LLViewerTextureList::getImageFromMemory(const U8* data, U32 size, std::string_view mimetype) +LLImageRaw* LLViewerTextureList::getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype) { LLPointer image = LLImageFormatted::loadFromMemory(data, size, mimetype); if (image) { - LLPointer raw_image = new LLImageRaw(); + LLImageRaw* raw_image = new LLImageRaw(); image->decode(raw_image, 0.f); - LLPointer imagep = new LLViewerFetchedTexture(raw_image, FTT_LOCAL_FILE, true); + return raw_image; + } + else + { + return nullptr; + } +} + +LLViewerFetchedTexture* LLViewerTextureList::getImageFromMemory(const U8* data, U32 size, std::string_view mimetype) +{ + LLPointer 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(); diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index ba468bab7e..a2cbc85c60 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -191,7 +191,8 @@ private: LLGLenum primary_format = 0, 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, -- cgit v1.3 From 227e9be06832515fd10eb496d4a2a4528d1ebd92 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 10 Jun 2024 10:43:38 -0500 Subject: #1654 generate normals and tangents according to gltf specification (#1662) * Disable unloading of objects in background. * Add unlit GLTF shader variant --- indra/llmath/llvector4a.h | 33 ++ indra/llrender/llglslshader.cpp | 71 ++--- indra/llrender/llglslshader.h | 25 +- indra/llrender/llshadermgr.cpp | 3 +- indra/llrender/llshadermgr.h | 2 - indra/llrender/llvertexbuffer.cpp | 16 + indra/llrender/llvertexbuffer.h | 3 + indra/newview/app_settings/settings.xml | 2 +- .../shaders/class1/environment/srgbF.glsl | 2 - .../shaders/class1/gltf/pbrmetallicroughnessF.glsl | 176 +++++++---- .../shaders/class1/gltf/pbrmetallicroughnessV.glsl | 43 ++- indra/newview/gltf/buffer_util.h | 10 + indra/newview/gltf/primitive.cpp | 352 ++++++++++++++++++--- indra/newview/gltf/primitive.h | 15 +- indra/newview/gltfscenemanager.cpp | 64 ++-- indra/newview/gltfscenemanager.h | 9 +- indra/newview/lldrawpoolalpha.cpp | 22 +- indra/newview/lldrawpoolsimple.cpp | 57 +--- indra/newview/llglsandbox.cpp | 2 +- indra/newview/llviewershadermgr.cpp | 242 +++++++------- indra/newview/llvocache.cpp | 14 + 21 files changed, 743 insertions(+), 420 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 47f2a095a8..1c3bc74f15 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -127,6 +127,39 @@ public: 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 //////////////////////////////////// diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 8ea134393a..6a60914b80 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -381,13 +381,10 @@ void LLGLSLShader::unloadInternal() stop_glerror(); } -bool LLGLSLShader::createShader(std::vector* attributes, - std::vector* uniforms, - U32 varying_count, - const char** varyings) +bool LLGLSLShader::createShader() { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - + unloadInternal(); sInstances.insert(this); @@ -454,11 +451,11 @@ bool LLGLSLShader::createShader(std::vector* attributes, // Map attributes and uniforms if (success) { - success = mapAttributes(attributes); + success = mapAttributes(); } if (success) { - success = mapUniforms(uniforms); + success = mapUniforms(); } if (!success) { @@ -469,7 +466,7 @@ bool LLGLSLShader::createShader(std::vector* attributes, { LL_SHADER_LOADING_WARNS() << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL; mShaderLevel--; - return createShader(attributes, uniforms); + return createShader(); } else { @@ -602,7 +599,7 @@ void LLGLSLShader::attachObjects(GLuint* objects, S32 count) } } -bool LLGLSLShader::mapAttributes(const std::vector* attributes) +bool LLGLSLShader::mapAttributes() { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -621,11 +618,10 @@ bool LLGLSLShader::mapAttributes(const std::vector* attrib } mAttribute.clear(); - U32 numAttributes = (attributes == NULL) ? 0 : attributes->size(); #if LL_RELEASE_WITH_DEBUG_INFO - mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, { -1, NULL }); + mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size(), { -1, NULL }); #else - mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, -1); + mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size(), -1); #endif if (res) @@ -649,19 +645,6 @@ bool LLGLSLShader::mapAttributes(const std::vector* attrib 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; } @@ -669,7 +652,7 @@ bool LLGLSLShader::mapAttributes(const std::vector* attrib return false; } -void LLGLSLShader::mapUniform(GLint index, const vector* uniforms) +void LLGLSLShader::mapUniform(GLint index) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -756,21 +739,6 @@ void LLGLSLShader::mapUniform(GLint index, const vector* u 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; } -bool LLGLSLShader::mapUniforms(const vector* uniforms) +bool LLGLSLShader::mapUniforms() { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -843,9 +811,8 @@ bool LLGLSLShader::mapUniforms(const vector* uniforms) mTexture.clear(); mValue.clear(); //initialize arrays - U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size(); - mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); - mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); + mUniform.resize(LLShaderMgr::instance()->mReservedUniforms.size(), -1); + mTexture.resize(LLShaderMgr::instance()->mReservedUniforms.size(), -1); bind(); @@ -946,26 +913,26 @@ bool LLGLSLShader::mapUniforms(const vector* uniforms) if (specularDiff || bumpLessDiff || envLessDiff || refLessDiff) { - mapUniform(diffuseMap, uniforms); + mapUniform(diffuseMap); skip_index.insert(diffuseMap); if (-1 != specularMap) { - mapUniform(specularMap, uniforms); + mapUniform(specularMap); skip_index.insert(specularMap); } if (-1 != bumpMap) { - mapUniform(bumpMap, uniforms); + mapUniform(bumpMap); skip_index.insert(bumpMap); } if (-1 != environmentMap) { - mapUniform(environmentMap, uniforms); + mapUniform(environmentMap); skip_index.insert(environmentMap); } if (-1 != reflectionMap) { - mapUniform(reflectionMap, uniforms); + mapUniform(reflectionMap); skip_index.insert(reflectionMap); } } @@ -979,7 +946,7 @@ bool LLGLSLShader::mapUniforms(const vector* uniforms) if (skip_index.end() != skip_index.find(i)) continue; //........................................................................................ - mapUniform(i, uniforms); + mapUniform(i); } //........................................................................................................................................ @@ -1057,7 +1024,7 @@ void LLGLSLShader::bind() } } -void LLGLSLShader::bind(U32 variant) +void LLGLSLShader::bind(U8 variant) { llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 8ebea2deca..f2b5c4881c 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -184,17 +184,14 @@ public: // If force_read is true, will force an immediate readback (severe performance penalty) bool readProfileQuery(bool for_runtime = false, bool force_read = false); - bool createShader(std::vector* attributes, - std::vector* uniforms, - U32 varying_count = 0, - const char** varyings = NULL); + bool createShader(); bool attachFragmentObject(std::string object); bool attachVertexObject(std::string object); void attachObject(GLuint object); void attachObjects(GLuint* objects = NULL, S32 count = 0); - bool mapAttributes(const std::vector* attributes); - bool mapUniforms(const std::vector*); - void mapUniform(GLint index, const std::vector*); + bool mapAttributes(); + bool mapUniforms(); + void mapUniform(GLint index); void uniform1i(U32 index, GLint i); void uniform1f(U32 index, GLfloat v); void fastUniform1f(U32 index, GLfloat v); @@ -330,22 +327,20 @@ public: // 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 U32 RIGGED = 2; - constexpr static U32 ALPHA = 1; - constexpr static U32 OPAQUE_STATIC = 0; - constexpr static U32 ALPHA_STATIC = 1; - constexpr static U32 OPAQUE_RIGGED = 2; - constexpr static U32 ALPHA_RIGGED = 3; + constexpr static U8 ALPHA_BLEND = 1; + constexpr static U8 RIGGED = 2; + constexpr static U8 UNLIT = 4; }; - constexpr static U32 NUM_GLTF_VARIANTS = 4; + constexpr static U8 NUM_GLTF_VARIANTS = 8; std::vector mGLTFVariants; //helper to bind GLTF variant - void bind(U32 variant); + void bind(U8 variant); // hacky flag used for optimization in LLDrawPoolAlpha bool mCanBindFast = false; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 4e8adb2fb3..4d53df5f06 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1157,6 +1157,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedAttribs.push_back("weight"); mReservedAttribs.push_back("weight4"); mReservedAttribs.push_back("clothing"); + mReservedAttribs.push_back("joint"); mReservedAttribs.push_back("texture_index"); //matrix state @@ -1239,7 +1240,6 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("heroProbes"); mReservedUniforms.push_back("cloud_noise_texture"); mReservedUniforms.push_back("cloud_noise_texture_next"); - mReservedUniforms.push_back("fullbright"); mReservedUniforms.push_back("lightnorm"); mReservedUniforms.push_back("sunlight_color"); mReservedUniforms.push_back("ambient_color"); @@ -1363,7 +1363,6 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("bloomMap"); mReservedUniforms.push_back("projectionMap"); mReservedUniforms.push_back("norm_mat"); - mReservedUniforms.push_back("texture_gamma"); mReservedUniforms.push_back("specular_color"); mReservedUniforms.push_back("env_intensity"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 03803c0e96..53e3d010db 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -107,7 +107,6 @@ public: HERO_PROBE, // "heroProbes" CLOUD_NOISE_MAP, // "cloud_noise_texture" CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next" - FULLBRIGHT, // "fullbright" LIGHTNORM, // "lightnorm" SUNLIGHT_COLOR, // "sunlight_color" AMBIENT, // "ambient_color" @@ -217,7 +216,6 @@ public: DEFERRED_BLOOM, // "bloomMap" DEFERRED_PROJECTION, // "projectionMap" DEFERRED_NORM_MATRIX, // "norm_mat" - TEXTURE_GAMMA, // "texture_gamma" SPECULAR_COLOR, // "specular_color" ENVIRONMENT_INTENSITY, // "env_intensity" diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index fa3b2df6e0..a4d33c91df 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -600,6 +600,7 @@ const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = sizeof(F32), // TYPE_WEIGHT, sizeof(LLVector4), // TYPE_WEIGHT4, 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 }; @@ -617,6 +618,7 @@ static const std::string vb_type_name[] = "TYPE_WEIGHT", "TYPE_WEIGHT4", "TYPE_CLOTHWEIGHT", + "TYPE_JOINT" "TYPE_TEXTURE_INDEX", "TYPE_MAX", "TYPE_INDEX", @@ -1598,6 +1600,12 @@ void LLVertexBuffer::setupVertexBuffer() void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]); 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) { AttributeType loc = TYPE_CLOTHWEIGHT; @@ -1667,6 +1675,14 @@ void LLVertexBuffer::setWeight4Data(const LLVector4a* data) 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) { #if !LL_DARWIN diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index f75849c82f..94339191a4 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -110,6 +110,7 @@ public: TYPE_WEIGHT, // "weight" TYPE_WEIGHT4, // "weight4" TYPE_CLOTHWEIGHT, // "clothing" + TYPE_JOINT, // "joint" TYPE_TEXTURE_INDEX, // "texture_index" 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 @@ -129,6 +130,7 @@ public: MAP_WEIGHT = (1<GLTFEnabled Comment - Enable GLTF support. Set by SimulatorFeatures + 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. Persist 0 Type diff --git a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl index 7e1d906878..d7f6d20547 100644 --- a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl @@ -23,8 +23,6 @@ * $/LicenseInfo$ */ - uniform sampler2D exposureMap; - vec3 srgb_to_linear(vec3 cs) { vec3 low_range = cs / vec3(12.92); diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index a59127ec77..d71a3fad99 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -28,20 +28,61 @@ // GLTF pbrMetallicRoughness implementation -uniform sampler2D diffuseMap; //always in sRGB space -uniform float metallicFactor; -uniform float roughnessFactor; +// ================================== +// 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 emissiveMap; 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 +// ================================== -#ifdef ALPHA_BLEND -out vec4 frag_color; +// ================================== +// 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; @@ -60,21 +101,12 @@ uniform int sun_up_factor; uniform vec3 sun_dir; uniform vec3 moon_dir; -vec3 srgb_to_linear(vec3 c); -vec3 linear_to_srgb(vec3 c); - -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); - 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 mirrorClip(vec3 pos); -void waterClip(vec3 pos); - void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor); vec3 pbrBaseLight(vec3 diffuseColor, @@ -104,44 +136,36 @@ vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, 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 - - -in vec3 vary_position; -in vec4 vertex_color; -in vec3 vary_normal; -in vec3 vary_tangent; -flat in float vary_sign; - -in vec2 base_color_texcoord; -in vec2 normal_texcoord; -in vec2 metallic_roughness_texcoord; -in vec2 emissive_texcoord; - -uniform float minimum_alpha; - -vec3 linear_to_srgb(vec3 c); -vec3 srgb_to_linear(vec3 c); - -uniform vec4 clipPlane; -uniform float clipSign; - -void mirrorClip(vec3 pos); - -uniform mat3 normal_matrix; +// ================================== 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) @@ -149,8 +173,16 @@ void main() discard; } - vec3 col = basecolor.rgb; - + 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; @@ -159,6 +191,7 @@ void main() 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 @@ -169,24 +202,49 @@ void main() 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 - vec3 emissive = emissiveColor; - emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - - norm *= gl_FrontFacing ? 1.0 : -1.0; +// ================================== +// alpha implementation +// ================================== #ifdef ALPHA_BLEND - vec3 color = vec3(0,0,0); - - vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; 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; @@ -198,11 +256,6 @@ void main() float perceptualRoughness = orm.g * roughnessFactor; float metallic = orm.b * metallicFactor; - // emissiveColor is the emissive color factor from GLTF and is already in linear space - vec3 colorEmissive = emissiveColor; - // emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear - colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - // PBR IBL float gloss = 1.0 - perceptualRoughness; vec3 irradiance = vec3(0); @@ -211,11 +264,11 @@ void main() vec3 diffuseColor; vec3 specularColor; - calcDiffuseSpecular(col.rgb, metallic, diffuseColor, specularColor); + calcDiffuseSpecular(basecolor.rgb, metallic, diffuseColor, specularColor); vec3 v = -normalize(pos.xyz); - color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, orm.r, additive, atten); + 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); @@ -237,12 +290,11 @@ void main() float a = basecolor.a*vertex_color.a; frag_color = max(vec4(color.rgb,a), vec4(0)); -#else - // See: C++: addDeferredAttachments(), GLSL: softenLightF - frag_data[0] = max(vec4(col, 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)); +#else // UNLIT + vec4 color = basecolor; + color.rgb += emissive.rgb; + frag_color = color; #endif +#endif // ALPHA_BLEND } diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl index 0ed1c5d315..f123c29101 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -42,32 +42,32 @@ uniform vec4[2] texture_emissive_transform; in vec3 position; in vec4 diffuse_color; -in vec3 normal; -in vec4 tangent; in vec2 texcoord0; - out vec2 base_color_texcoord; -out vec2 normal_texcoord; -out vec2 metallic_roughness_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; -out vec3 vary_position; +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); -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, 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 @@ -80,18 +80,12 @@ mat4 getGLTFSkinTransform() { int i; - vec4 w = fract(weight4); - vec4 index = floor(weight4); - - index = min(index, vec4(MAX_JOINTS_PER_GLTF_OBJECT-1)); - index = max(index, vec4( 0.0)); - - w *= 1.0/(w.x+w.y+w.z+w.w); + vec4 w = weight4; - int i1 = int(index.x); - int i2 = int(index.y); - int i3 = int(index.z); - int i4 = int(index.w); + 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; @@ -143,10 +137,15 @@ void main() #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); - emissive_texcoord = texture_transform(texcoord0, texture_emissive_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; @@ -156,10 +155,10 @@ void main() #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 diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index 548d4ec5d6..bd43f60d19 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -170,6 +170,16 @@ namespace LL dst.set(src[0], src[1], src[2], src[3]); } + template<> + inline void copyVec4(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<> inline void copyVec4(U16* src, LLColor4U& dst) { diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index 886b8f79c9..8d9880951b 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -30,9 +30,204 @@ #include "buffer_util.h" #include "../llviewershadermgr.h" +#include "mikktspace/mikktspace.hh" + +#include "meshoptimizer/meshoptimizer.h" + + using namespace LL::GLTF; using namespace boost::json; + +// Mesh data useful for Mikktspace tangent generation (and flat normal generation) +struct MikktMesh +{ + std::vector p; + std::vector n; + std::vector tc; + std::vector w; + std::vector t; + std::vector c; + std::vector 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 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 @@ -94,26 +289,12 @@ bool Primitive::prep(Asset& asset) } } - U32 mask = ATTRIBUTE_MASK; + U32 mask = LLVertexBuffer::MAP_VERTEX; if (!mWeights.empty()) { mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - 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()); + mask |= LLVertexBuffer::MAP_JOINT; } if (mTexCoords.empty()) @@ -121,23 +302,17 @@ bool Primitive::prep(Asset& asset) mTexCoords.resize(mPositions.size()); } - // flip texcoord y, upload, then flip back (keep the off-spec data in vram only) - for (auto& tc : mTexCoords) - { - tc[1] = 1.f - tc[1]; - } - mVertexBuffer->setTexCoordData(mTexCoords.data()); - - for (auto& tc : mTexCoords) - { - tc[1] = 1.f - tc[1]; - } + // TODO: support more than one texcoord set (or no texcoords) + mask |= LLVertexBuffer::MAP_TEXCOORD0; if (mColors.empty()) { mColors.resize(mPositions.size(), LLColor4U::white); } + // TODO: support colorless vertex buffers + mask |= LLVertexBuffer::MAP_COLOR; + // bake material basecolor into color array if (mMaterial != INVALID_INDEX) { @@ -149,44 +324,131 @@ bool Primitive::prep(Asset& asset) } } - mVertexBuffer->setColorData(mColors.data()); + mShaderVariant = 0; if (mNormals.empty()) { - mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0)); + 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; + } + 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); + } + } + + bool unlit = (mShaderVariant & LLGLSLShader::GLTFVariant::UNLIT) != 0; + + 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); + } } - mVertexBuffer->setNormalData(mNormals.data()); - if (mTangents.empty()) + if (!unlit) { - // TODO: generate tangents if needed - mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1)); + mask |= LLVertexBuffer::MAP_NORMAL; + mask |= LLVertexBuffer::MAP_TANGENT; + } + + if (LLGLSLShader::sCurBoundShaderPtr == nullptr) + { // make sure a shader is bound to satisfy mVertexBuffer->setBuffer + gDebugProgram.bind(); } - mVertexBuffer->setTangentData(mTangents.data()); + 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()); + + if (!mNormals.empty()) + { + mVertexBuffer->setNormalData(mNormals.data()); + } + if (!mTangents.empty()) + { + mVertexBuffer->setTangentData(mTangents.data()); + } if (!mWeights.empty()) { - std::vector weight_data; - weight_data.resize(mWeights.size()); + mShaderVariant |= LLGLSLShader::GLTFVariant::RIGGED; + 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]); - }; + // 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]; + } - mVertexBuffer->setWeight4Data(weight_data.data()); + if (!mIndexArray.empty()) + { + mVertexBuffer->setIndexData(mIndexArray.data()); } createOctree(); mVertexBuffer->unbind(); + Material& material = asset.mMaterials[mMaterial]; + if (material.mAlphaMode == Material::AlphaMode::BLEND) + { + mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; + } + return true; } diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index 9914ff3b08..f9d7c63c65 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -38,13 +38,6 @@ namespace LL using Value = boost::json::value; class Asset; - constexpr U32 ATTRIBUTE_MASK = - LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_TANGENT | - LLVertexBuffer::MAP_COLOR; - class Primitive { public: @@ -64,12 +57,12 @@ namespace LL // GPU copy of mesh data LLPointer mVertexBuffer; - // CPU copy of mesh data + // CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code std::vector mTexCoords; std::vector mNormals; std::vector mTangents; std::vector mPositions; - std::vector mJoints; + std::vector mJoints; std::vector mWeights; std::vector mColors; std::vector mIndexArray; @@ -82,6 +75,10 @@ namespace LL Mode mMode = Mode::TRIANGLES; // default to triangles LLRender::eGeomModes mGLMode = LLRender::TRIANGLES; // for use with LLRender S32 mIndices = -1; + + // shader variant according to LLGLSLShader::GLTFVariant flags + U8 mShaderVariant = 0; + std::unordered_map mAttributes; // create octree based on vertex buffer diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index df922b8f3d..d7eb605489 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -528,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 // by traversing the whole scenegraph @@ -537,6 +556,8 @@ void GLTFSceneManager::render(bool opaque, bool rigged) gGL.matrixMode(LLRender::MM_MODELVIEW); + bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; + for (U32 i = 0; i < mObjects.size(); ++i) { if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr) @@ -564,23 +585,16 @@ void GLTFSceneManager::render(bool opaque, bool rigged) // (matrix palettes are in asset space) gGL.loadMatrix(glm::value_ptr(mdv)); } - render(*asset, opaque, rigged); + render(*asset, variant); gGL.popMatrix(); } } -void GLTFSceneManager::render(Asset& asset, bool opaque, bool rigged) +void GLTFSceneManager::render(Asset& asset, U8 variant) { - U32 variant = 0; - if (rigged) - { - variant |= LLGLSLShader::GLTFVariant::RIGGED; - } - if (!opaque) - { - variant |= LLGLSLShader::GLTFVariant::ALPHA; - } + bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND); + bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; if (opaque) { @@ -600,16 +614,6 @@ void GLTFSceneManager::render(Asset& asset, bool opaque, bool rigged) Skin& skin = asset.mSkins[node.mSkin]; glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO); } - else - { - //skip static nodes if we're rendering rigged - continue; - } - } - else if (rigged) - { - // skip rigged nodes if we're not rendering rigged - continue; } if (node.mMesh != INVALID_INDEX) @@ -617,6 +621,11 @@ void GLTFSceneManager::render(Asset& asset, bool opaque, bool rigged) 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)); @@ -625,23 +634,12 @@ void GLTFSceneManager::render(Asset& asset, bool opaque, bool rigged) if (primitive.mMaterial != INVALID_INDEX) { Material& material = asset.mMaterials[primitive.mMaterial]; - bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND; - - if (mat_opaque != opaque) - { - continue; - } - bind(asset, material); cull = !material.mDoubleSided; } else { - if (!opaque) - { - continue; - } LLFetchedGLTFMaterial::sDefault.bind(); } diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index fcde6cf1f7..7da413e8b2 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -49,8 +49,13 @@ namespace LL void uploadSelection(); // decompose selected asset and upload to simulator void update(); - void render(bool opaque, bool rigged = false); - void render(LL::GLTF::Asset& asset, bool opaque, bool rigged); + 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); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 2a376a40b2..686e9aef24 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -93,7 +93,7 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses() } // 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 displayGamma(gSavedSettings, "RenderDeferredDisplayGamma"); F32 gamma = displayGamma; @@ -132,15 +132,11 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d { shader->setMinimumAlpha(MINIMUM_ALPHA); } - if (textureGamma) - { - shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - } //also prepare rigged variant if (shader->mRiggedVariant && shader->mRiggedVariant != shader) { - prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign); + prepare_alpha_shader(shader->mRiggedVariant, deferredEnvironment, water_sign); } } @@ -171,36 +167,36 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) llassert(LLPipeline::sRenderDeferred); emissive_shader = &gDeferredEmissiveProgram; - prepare_alpha_shader(emissive_shader, true, false, water_sign); + prepare_alpha_shader(emissive_shader, false, water_sign); 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 = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram : (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram : &gDeferredFullbrightAlphaMaskAlphaProgram; - prepare_alpha_shader(fullbright_shader, true, true, water_sign); + prepare_alpha_shader(fullbright_shader, true, water_sign); simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram : &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; 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 = (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : &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 // already being setup for rendering @@ -265,6 +261,8 @@ void LLDrawPoolAlpha::forwardRender(bool rigged) { // draw GLTF scene to depth buffer before rigged alpha LL::GLTFSceneManager::instance().render(false, false); 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 diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 2b0ae260dc..836a90adab 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -36,43 +36,12 @@ #include "llspatialpartition.h" #include "llviewershadermgr.h" #include "llrender.h" +#include "gltfscenemanager.h" static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple"); 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) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -89,12 +58,12 @@ void LLDrawPoolGlow::renderPostDeferred(S32 pass) gGL.setColorMask(false, true); //first pass -- static objects - setup_glow_shader(shader); + shader->bind(); pushBatches(LLRenderPass::PASS_GLOW, true, true); // second pass -- rigged objects shader = shader->mRiggedVariant; - setup_glow_shader(shader); + shader->bind(); pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, true, true); gGL.setColorMask(true, false); @@ -133,11 +102,11 @@ void LLDrawPoolSimple::renderDeferred(S32 pass) LLGLDisable blend(GL_BLEND); //render static - setup_simple_shader(&gDeferredDiffuseProgram); + gDeferredDiffuseProgram.bind(); pushBatches(LLRenderPass::PASS_SIMPLE, true, true); //render rigged - setup_simple_shader(gDeferredDiffuseProgram.mRiggedVariant); + gDeferredDiffuseProgram.bind(true); pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, true, true); } @@ -150,11 +119,11 @@ void LLDrawPoolAlphaMask::renderDeferred(S32 pass) LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram; //render static - setup_simple_shader(shader); + shader->bind(); pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, true, true); //render rigged - setup_simple_shader(shader->mRiggedVariant); + shader->bind(true); pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, true, true); } @@ -201,13 +170,13 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass) gGL.setSceneBlendType(LLRender::BT_ALPHA); // render static - setup_fullbright_shader(shader); + shader->bind(); pushBatches(LLRenderPass::PASS_FULLBRIGHT, true, true); if (!LLPipeline::sRenderingHUDs) { // render rigged - setup_fullbright_shader(shader->mRiggedVariant); + shader->bind(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); + // render unrigged unlit GLTF + LL::GLTFSceneManager::instance().render(true, false, true); + LL::GLTFSceneManager::instance().render(true, true, true); + LLGLSLShader* shader = nullptr; if (LLPipeline::sRenderingHUDs) { @@ -229,13 +202,13 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass) LLGLDisable blend(GL_BLEND); // render static - setup_fullbright_shader(shader); + shader->bind(); pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true); if (!LLPipeline::sRenderingHUDs) { // render rigged - setup_fullbright_shader(shader->mRiggedVariant); + shader->bind(true); pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, true, true); } } diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 505d7b1dea..c878c8cf63 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -1009,7 +1009,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/benchmarkF.glsl", GL_FRAGMENT_SHADER)); gBenchmarkProgram.mShaderLevel = 1; - if (!gBenchmarkProgram.createShader(NULL, NULL)) + if (!gBenchmarkProgram.createShader()) { return -1.f; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index e53e90b703..d43d6fea37 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -245,11 +245,11 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader riggedShader.mShaderGroup = shader.mShaderGroup; shader.mRiggedVariant = &riggedShader; - return riggedShader.createShader(NULL, NULL); + return riggedShader.createShader(); } -static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool use_sun_shadow) +static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool unlit, bool use_sun_shadow) { variant.mName = shader.mName.c_str(); variant.mFeatures = shader.mFeatures; @@ -266,6 +266,11 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool variant.addPermutation("HAS_SKIN", "1"); } + if (unlit) + { + variant.addPermutation("UNLIT", "1"); + } + if (alpha_blend) { variant.addPermutation("ALPHA_BLEND", "1"); @@ -286,7 +291,7 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool variant.addPermutation("HAS_SUN_SHADOW", "1"); } - bool success = variant.createShader(NULL, NULL); + bool success = variant.createShader(); llassert(success); // Alpha Shader Hack @@ -298,7 +303,7 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool } else { - return variant.createShader(NULL, NULL); + return variant.createShader(); } } @@ -309,10 +314,11 @@ static bool make_gltf_variants(LLGLSLShader& shader, bool use_sun_shadow) for (U32 i = 0; i < LLGLSLShader::NUM_GLTF_VARIANTS; ++i) { - bool alpha_blend = i & 1; - bool rigged = i & 2; + bool alpha_blend = i & LLGLSLShader::GLTFVariant::ALPHA_BLEND; + bool rigged = i & LLGLSLShader::GLTFVariant::RIGGED; + bool unlit = i & LLGLSLShader::GLTFVariant::UNLIT; - if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, use_sun_shadow)) + if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, use_sun_shadow)) { return false; } @@ -870,7 +876,7 @@ bool LLViewerShaderMgr::loadShadersWater() gWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; gWaterProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; - success = gWaterProgram.createShader(NULL, NULL); + success = gWaterProgram.createShader(); llassert(success); } @@ -900,7 +906,7 @@ bool LLViewerShaderMgr::loadShadersWater() } gWaterEdgeProgram.mShaderGroup = LLGLSLShader::SG_WATER; gWaterEdgeProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; - success = gWaterEdgeProgram.createShader(NULL, NULL); + success = gWaterEdgeProgram.createShader(); llassert(success); } @@ -920,7 +926,7 @@ bool LLViewerShaderMgr::loadShadersWater() { gUnderWaterProgram.addPermutation("TRANSPARENT_WATER", "1"); } - success = gUnderWaterProgram.createShader(NULL, NULL); + success = gUnderWaterProgram.createShader(); llassert(success); } @@ -969,7 +975,7 @@ bool LLViewerShaderMgr::loadShadersEffects() gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowV.glsl", GL_VERTEX_SHADER)); gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowF.glsl", GL_FRAGMENT_SHADER)); gGlowProgram.mShaderLevel = mShaderLevel[SHADER_EFFECT]; - success = gGlowProgram.createShader(NULL, NULL); + success = gGlowProgram.createShader(); if (!success) { LLPipeline::sRenderGlow = false; @@ -992,7 +998,7 @@ bool LLViewerShaderMgr::loadShadersEffects() gGlowExtractProgram.addPermutation("HAS_NOISE", "1"); } - success = gGlowExtractProgram.createShader(NULL, NULL); + success = gGlowExtractProgram.createShader(); if (!success) { LLPipeline::sRenderGlow = false; @@ -1115,7 +1121,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER)); gDeferredHighlightProgram.mShaderFiles.push_back(make_pair("deferred/highlightF.glsl", GL_FRAGMENT_SHADER)); gDeferredHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gDeferredHighlightProgram.createShader(NULL, NULL); + success = gDeferredHighlightProgram.createShader(); } if (success) @@ -1128,7 +1134,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredDiffuseProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredDiffuseProgram, gDeferredSkinnedDiffuseProgram); - success = success && gDeferredDiffuseProgram.createShader(NULL, NULL); + success = success && gDeferredDiffuseProgram.createShader(); } if (success) @@ -1140,7 +1146,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredDiffuseAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredDiffuseAlphaMaskProgram, gDeferredSkinnedDiffuseAlphaMaskProgram); - success = success && gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL); + success = success && gDeferredDiffuseAlphaMaskProgram.createShader(); } if (success) @@ -1150,7 +1156,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredNonIndexedDiffuseAlphaMaskProgram.createShader(NULL, NULL); + success = gDeferredNonIndexedDiffuseAlphaMaskProgram.createShader(); llassert(success); } @@ -1161,7 +1167,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseNoColorV.glsl", GL_VERTEX_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskNoColorF.glsl", GL_FRAGMENT_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.createShader(NULL, NULL); + success = gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.createShader(); llassert(success); } @@ -1173,7 +1179,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER)); gDeferredBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredBumpProgram, gDeferredSkinnedBumpProgram); - success = success && gDeferredBumpProgram.createShader(NULL, NULL); + success = success && gDeferredBumpProgram.createShader(); llassert(success); } @@ -1255,7 +1261,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[i].mRiggedVariant = &gDeferredMaterialProgram[i + 0x10]; } - success = gDeferredMaterialProgram[i].createShader(NULL, NULL); + success = gDeferredMaterialProgram[i].createShader(); llassert(success); } } @@ -1283,7 +1289,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() success = make_rigged_variant(gDeferredPBROpaqueProgram, gDeferredSkinnedPBROpaqueProgram); if (success) { - success = gDeferredPBROpaqueProgram.createShader(NULL, NULL); + success = gDeferredPBROpaqueProgram.createShader(); } llassert(success); } @@ -1316,7 +1322,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() success = make_rigged_variant(gPBRGlowProgram, gPBRGlowSkinnedProgram); if (success) { - success = gPBRGlowProgram.createShader(NULL, NULL); + success = gPBRGlowProgram.createShader(); } llassert(success); } @@ -1332,7 +1338,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDPBROpaqueProgram.clearPermutations(); gHUDPBROpaqueProgram.addPermutation("IS_HUD", "1"); - success = gHUDPBROpaqueProgram.createShader(NULL, NULL); + success = gHUDPBROpaqueProgram.createShader(); llassert(success); } @@ -1377,7 +1383,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() success = make_rigged_variant(*shader, gDeferredSkinnedPBRAlphaProgram); if (success) { - success = shader->createShader(NULL, NULL); + success = shader->createShader(); } llassert(success); @@ -1406,7 +1412,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() shader->addPermutation("IS_HUD", "1"); shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = shader->createShader(NULL, NULL); + success = shader->createShader(); llassert(success); } @@ -1433,7 +1439,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredPBRTerrainProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PBR_DETAIL", llformat("%d", detail)); gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT", llformat("%d", mapping)); - success = gDeferredPBRTerrainProgram.createShader(NULL, NULL); + success = gDeferredPBRTerrainProgram.createShader(); llassert(success); } @@ -1444,7 +1450,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER)); gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER)); gDeferredTreeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredTreeProgram.createShader(NULL, NULL); + success = gDeferredTreeProgram.createShader(); } if (success) @@ -1455,7 +1461,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredTreeShadowProgram.mRiggedVariant = &gDeferredSkinnedTreeShadowProgram; - success = gDeferredTreeShadowProgram.createShader(NULL, NULL); + success = gDeferredTreeShadowProgram.createShader(); llassert(success); } @@ -1467,7 +1473,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowSkinnedV.glsl", GL_VERTEX_SHADER)); gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredSkinnedTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredSkinnedTreeShadowProgram.createShader(NULL, NULL); + success = gDeferredSkinnedTreeShadowProgram.createShader(); llassert(success); } @@ -1479,7 +1485,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER)); gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER)); gDeferredImpostorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredImpostorProgram.createShader(NULL, NULL); + success = gDeferredImpostorProgram.createShader(); llassert(success); } @@ -1497,7 +1503,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredLightProgram.clearPermutations(); - success = gDeferredLightProgram.createShader(NULL, NULL); + success = gDeferredLightProgram.createShader(); llassert(success); } @@ -1517,7 +1523,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredMultiLightProgram[i].mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredMultiLightProgram[i].addPermutation("LIGHT_COUNT", llformat("%d", i+1)); - success = gDeferredMultiLightProgram[i].createShader(NULL, NULL); + success = gDeferredMultiLightProgram[i].createShader(); llassert(success); } } @@ -1535,7 +1541,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER)); gDeferredSpotLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredSpotLightProgram.createShader(NULL, NULL); + success = gDeferredSpotLightProgram.createShader(); llassert(success); } @@ -1553,7 +1559,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER)); gDeferredMultiSpotLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL); + success = gDeferredMultiSpotLightProgram.createShader(); llassert(success); } @@ -1587,7 +1593,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredSunProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER)); gDeferredSunProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredSunProgram.createShader(NULL, NULL); + success = gDeferredSunProgram.createShader(); llassert(success); } @@ -1601,7 +1607,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightF.glsl", GL_FRAGMENT_SHADER)); gDeferredBlurLightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredBlurLightProgram.createShader(NULL, NULL); + success = gDeferredBlurLightProgram.createShader(); llassert(success); } @@ -1668,7 +1674,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = shader->createShader(NULL, NULL); + success = shader->createShader(); llassert(success); // Hack @@ -1727,7 +1733,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() { shader->mRiggedVariant = shaders[1]; } - success = shader->createShader(NULL, NULL); + success = shader->createShader(); llassert(success); // End Hack @@ -1750,7 +1756,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarEyesProgram.mShaderFiles.push_back(make_pair("deferred/avatarEyesV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarEyesProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER)); gDeferredAvatarEyesProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarEyesProgram.createShader(NULL, NULL); + success = gDeferredAvatarEyesProgram.createShader(); llassert(success); } @@ -1767,7 +1773,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER)); gDeferredFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredFullbrightProgram, gDeferredSkinnedFullbrightProgram); - success = gDeferredFullbrightProgram.createShader(NULL, NULL); + success = gDeferredFullbrightProgram.createShader(); llassert(success); } @@ -1785,7 +1791,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gHUDFullbrightProgram.clearPermutations(); gHUDFullbrightProgram.addPermutation("IS_HUD", "1"); - success = gHUDFullbrightProgram.createShader(NULL, NULL); + success = gHUDFullbrightProgram.createShader(); llassert(success); } @@ -1804,7 +1810,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1"); gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredFullbrightAlphaMaskProgram, gDeferredSkinnedFullbrightAlphaMaskProgram); - success = success && gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL); + success = success && gDeferredFullbrightAlphaMaskProgram.createShader(); llassert(success); } @@ -1823,7 +1829,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK", "1"); gHUDFullbrightAlphaMaskProgram.addPermutation("IS_HUD", "1"); gHUDFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gHUDFullbrightAlphaMaskProgram.createShader(NULL, NULL); + success = gHUDFullbrightAlphaMaskProgram.createShader(); llassert(success); } @@ -1844,7 +1850,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskAlphaProgram.addPermutation("IS_ALPHA", "1"); gDeferredFullbrightAlphaMaskAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredFullbrightAlphaMaskAlphaProgram, gDeferredSkinnedFullbrightAlphaMaskAlphaProgram); - success = success && gDeferredFullbrightAlphaMaskAlphaProgram.createShader(NULL, NULL); + success = success && gDeferredFullbrightAlphaMaskAlphaProgram.createShader(); llassert(success); } @@ -1865,7 +1871,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDFullbrightAlphaMaskAlphaProgram.addPermutation("IS_ALPHA", "1"); gHUDFullbrightAlphaMaskAlphaProgram.addPermutation("IS_HUD", "1"); gHUDFullbrightAlphaMaskAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = success && gHUDFullbrightAlphaMaskAlphaProgram.createShader(NULL, NULL); + success = success && gHUDFullbrightAlphaMaskAlphaProgram.createShader(); llassert(success); } @@ -1883,7 +1889,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredFullbrightShinyProgram.mFeatures.hasReflectionProbes = true; success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram); - success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL); + success = success && gDeferredFullbrightShinyProgram.createShader(); llassert(success); } @@ -1902,7 +1908,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDFullbrightShinyProgram.mFeatures.hasReflectionProbes = true; gHUDFullbrightShinyProgram.clearPermutations(); gHUDFullbrightShinyProgram.addPermutation("IS_HUD", "1"); - success = gHUDFullbrightShinyProgram.createShader(NULL, NULL); + success = gHUDFullbrightShinyProgram.createShader(); llassert(success); } @@ -1918,7 +1924,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveF.glsl", GL_FRAGMENT_SHADER)); gDeferredEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredEmissiveProgram, gDeferredSkinnedEmissiveProgram); - success = success && gDeferredEmissiveProgram.createShader(NULL, NULL); + success = success && gDeferredEmissiveProgram.createShader(); llassert(success); } @@ -1951,7 +1957,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenProgram.addPermutation("HAS_SSAO", "1"); } - success = gDeferredSoftenProgram.createShader(NULL, NULL); + success = gDeferredSoftenProgram.createShader(); llassert(success); } @@ -1973,7 +1979,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHazeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gHazeProgram.createShader(NULL, NULL); + success = gHazeProgram.createShader(); llassert(success); } @@ -1997,7 +2003,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHazeWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gHazeWaterProgram.createShader(NULL, NULL); + success = gHazeWaterProgram.createShader(); llassert(success); } @@ -2010,7 +2016,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredShadowProgram.mRiggedVariant = &gDeferredSkinnedShadowProgram; - success = gDeferredShadowProgram.createShader(NULL, NULL); + success = gDeferredShadowProgram.createShader(); llassert(success); } @@ -2025,7 +2031,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredSkinnedShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; // gDeferredSkinnedShadowProgram.addPermutation("DEPTH_CLAMP", "1"); // disable depth clamp for now - success = gDeferredSkinnedShadowProgram.createShader(NULL, NULL); + success = gDeferredSkinnedShadowProgram.createShader(); llassert(success); } @@ -2039,7 +2045,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER)); // gDeferredShadowCubeProgram.addPermutation("DEPTH_CLAMP", "1"); gDeferredShadowCubeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredShadowCubeProgram.createShader(NULL, NULL); + success = gDeferredShadowCubeProgram.createShader(); llassert(success); } @@ -2057,7 +2063,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1"); gDeferredShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredShadowFullbrightAlphaMaskProgram, gDeferredSkinnedShadowFullbrightAlphaMaskProgram); - success = success && gDeferredShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL); + success = success && gDeferredShadowFullbrightAlphaMaskProgram.createShader(); llassert(success); } @@ -2071,7 +2077,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); gDeferredShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = make_rigged_variant(gDeferredShadowAlphaMaskProgram, gDeferredSkinnedShadowAlphaMaskProgram); - success = success && gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL); + success = success && gDeferredShadowAlphaMaskProgram.createShader(); llassert(success); } @@ -2085,7 +2091,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowGLTFAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredShadowGLTFAlphaMaskProgram.clearPermutations(); success = make_rigged_variant(gDeferredShadowGLTFAlphaMaskProgram, gDeferredSkinnedShadowGLTFAlphaMaskProgram); - success = success && gDeferredShadowGLTFAlphaMaskProgram.createShader(NULL, NULL); + success = success && gDeferredShadowGLTFAlphaMaskProgram.createShader(); llassert(success); } @@ -2098,7 +2104,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowGLTFAlphaBlendProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredShadowGLTFAlphaBlendProgram.clearPermutations(); success = make_rigged_variant(gDeferredShadowGLTFAlphaBlendProgram, gDeferredSkinnedShadowGLTFAlphaBlendProgram); - success = success && gDeferredShadowGLTFAlphaBlendProgram.createShader(NULL, NULL); + success = success && gDeferredShadowGLTFAlphaBlendProgram.createShader(); llassert(success); } @@ -2111,7 +2117,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredAvatarShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarShadowProgram.createShader(NULL, NULL); + success = gDeferredAvatarShadowProgram.createShader(); llassert(success); } @@ -2123,7 +2129,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaShadowV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarAlphaShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaShadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredAvatarAlphaShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarAlphaShadowProgram.createShader(NULL, NULL); + success = gDeferredAvatarAlphaShadowProgram.createShader(); llassert(success); } if (success) @@ -2134,7 +2140,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaMaskShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaShadowV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarAlphaMaskShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaMaskShadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredAvatarAlphaMaskShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarAlphaMaskShadowProgram.createShader(NULL, NULL); + success = gDeferredAvatarAlphaMaskShadowProgram.createShader(); llassert(success); } @@ -2152,7 +2158,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER)); gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER)); gDeferredTerrainProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredTerrainProgram.createShader(NULL, NULL); + success = gDeferredTerrainProgram.createShader(); llassert(success); } @@ -2164,7 +2170,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER)); gDeferredAvatarProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarProgram.createShader(NULL, NULL); + success = gDeferredAvatarProgram.createShader(); llassert(success); } @@ -2198,7 +2204,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarAlphaProgram.createShader(NULL, NULL); + success = gDeferredAvatarAlphaProgram.createShader(); llassert(success); gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true; @@ -2216,7 +2222,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gExposureProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gExposureProgram.mShaderFiles.push_back(make_pair("deferred/exposureF.glsl", GL_FRAGMENT_SHADER)); gExposureProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gExposureProgram.createShader(NULL, NULL); + success = gExposureProgram.createShader(); llassert(success); } @@ -2230,7 +2236,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gExposureProgramNoFade.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gExposureProgramNoFade.mShaderFiles.push_back(make_pair("deferred/exposureF.glsl", GL_FRAGMENT_SHADER)); gExposureProgramNoFade.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gExposureProgramNoFade.createShader(NULL, NULL); + success = gExposureProgramNoFade.createShader(); llassert(success); } @@ -2242,7 +2248,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gLuminanceProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gLuminanceProgram.mShaderFiles.push_back(make_pair("deferred/luminanceF.glsl", GL_FRAGMENT_SHADER)); gLuminanceProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gLuminanceProgram.createShader(NULL, NULL); + success = gLuminanceProgram.createShader(); llassert(success); } @@ -2256,7 +2262,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER)); gDeferredPostGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredPostGammaCorrectProgram.createShader(NULL, NULL); + success = gDeferredPostGammaCorrectProgram.createShader(); llassert(success); } @@ -2271,7 +2277,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gNoPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gNoPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER)); gNoPostGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gNoPostGammaCorrectProgram.createShader(NULL, NULL); + success = gNoPostGammaCorrectProgram.createShader(); llassert(success); } @@ -2286,7 +2292,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gLegacyPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gLegacyPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER)); gLegacyPostGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gLegacyPostGammaCorrectProgram.createShader(NULL, NULL); + success = gLegacyPostGammaCorrectProgram.createShader(); llassert(success); } @@ -2299,7 +2305,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER)); gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/fxaaF.glsl", GL_FRAGMENT_SHADER)); gFXAAProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gFXAAProgram.createShader(NULL, NULL); + success = gFXAAProgram.createShader(); llassert(success); } @@ -2311,7 +2317,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredF.glsl", GL_FRAGMENT_SHADER)); gDeferredPostProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredPostProgram.createShader(NULL, NULL); + success = gDeferredPostProgram.createShader(); llassert(success); } @@ -2323,7 +2329,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredCoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gDeferredCoFProgram.mShaderFiles.push_back(make_pair("deferred/cofF.glsl", GL_FRAGMENT_SHADER)); gDeferredCoFProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredCoFProgram.createShader(NULL, NULL); + success = gDeferredCoFProgram.createShader(); llassert(success); } @@ -2335,7 +2341,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredDoFCombineProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gDeferredDoFCombineProgram.mShaderFiles.push_back(make_pair("deferred/dofCombineF.glsl", GL_FRAGMENT_SHADER)); gDeferredDoFCombineProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredDoFCombineProgram.createShader(NULL, NULL); + success = gDeferredDoFCombineProgram.createShader(); llassert(success); } @@ -2347,7 +2353,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredPostNoDoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gDeferredPostNoDoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoDoFF.glsl", GL_FRAGMENT_SHADER)); gDeferredPostNoDoFProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredPostNoDoFProgram.createShader(NULL, NULL); + success = gDeferredPostNoDoFProgram.createShader(); llassert(success); } @@ -2367,7 +2373,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gEnvironmentMapProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gEnvironmentMapProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gEnvironmentMapProgram.createShader(NULL, NULL); + success = gEnvironmentMapProgram.createShader(); llassert(success); } @@ -2385,7 +2391,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredWLSkyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gDeferredWLSkyProgram.createShader(NULL, NULL); + success = gDeferredWLSkyProgram.createShader(); llassert(success); } @@ -2403,7 +2409,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredWLCloudProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY; gDeferredWLCloudProgram.addConstant( LLGLSLShader::SHADER_CONST_CLOUD_MOON_DEPTH ); // SL-14113 - success = gDeferredWLCloudProgram.createShader(NULL, NULL); + success = gDeferredWLCloudProgram.createShader(); llassert(success); } @@ -2421,7 +2427,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredWLSunProgram.mShaderFiles.push_back(make_pair("deferred/sunDiscF.glsl", GL_FRAGMENT_SHADER)); gDeferredWLSunProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredWLSunProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gDeferredWLSunProgram.createShader(NULL, NULL); + success = gDeferredWLSunProgram.createShader(); llassert(success); } @@ -2441,7 +2447,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredWLMoonProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredWLMoonProgram.mShaderGroup = LLGLSLShader::SG_SKY; gDeferredWLMoonProgram.addConstant( LLGLSLShader::SHADER_CONST_CLOUD_MOON_DEPTH ); // SL-14113 - success = gDeferredWLMoonProgram.createShader(NULL, NULL); + success = gDeferredWLMoonProgram.createShader(); llassert(success); } @@ -2454,7 +2460,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredStarProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredStarProgram.mShaderGroup = LLGLSLShader::SG_SKY; gDeferredStarProgram.addConstant( LLGLSLShader::SHADER_CONST_STAR_DEPTH ); // SL-14113 - success = gDeferredStarProgram.createShader(NULL, NULL); + success = gDeferredStarProgram.createShader(); llassert(success); } @@ -2466,7 +2472,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gNormalMapGenProgram.mShaderFiles.push_back(make_pair("deferred/normgenF.glsl", GL_FRAGMENT_SHADER)); gNormalMapGenProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gNormalMapGenProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gNormalMapGenProgram.createShader(NULL, NULL); + success = gNormalMapGenProgram.createShader(); } if (success) @@ -2476,7 +2482,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredGenBrdfLutProgram.mShaderFiles.push_back(make_pair("deferred/genbrdflutV.glsl", GL_VERTEX_SHADER)); gDeferredGenBrdfLutProgram.mShaderFiles.push_back(make_pair("deferred/genbrdflutF.glsl", GL_FRAGMENT_SHADER)); gDeferredGenBrdfLutProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredGenBrdfLutProgram.createShader(NULL, NULL); + success = gDeferredGenBrdfLutProgram.createShader(); } if (success) { @@ -2487,7 +2493,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gPostScreenSpaceReflectionProgram.mFeatures.hasScreenSpaceReflections = true; gPostScreenSpaceReflectionProgram.mFeatures.isDeferred = true; gPostScreenSpaceReflectionProgram.mShaderLevel = 3; - success = gPostScreenSpaceReflectionProgram.createShader(NULL, NULL); + success = gPostScreenSpaceReflectionProgram.createShader(); } if (success) { @@ -2496,7 +2502,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredBufferVisualProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gDeferredBufferVisualProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredVisualizeBuffers.glsl", GL_FRAGMENT_SHADER)); gDeferredBufferVisualProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredBufferVisualProgram.createShader(NULL, NULL); + success = gDeferredBufferVisualProgram.createShader(); } return success; @@ -2515,7 +2521,7 @@ bool LLViewerShaderMgr::loadShadersObject() gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER)); gObjectBumpProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = make_rigged_variant(gObjectBumpProgram, gSkinnedObjectBumpProgram); - success = success && gObjectBumpProgram.createShader(NULL, NULL); + success = success && gObjectBumpProgram.createShader(); if (success) { //lldrawpoolbump assumes "texture0" has channel 0 and "texture1" has channel 1 LLGLSLShader* shader[] = { &gObjectBumpProgram, &gSkinnedObjectBumpProgram }; @@ -2543,7 +2549,7 @@ bool LLViewerShaderMgr::loadShadersObject() gObjectAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("objects/simpleNoColorV.glsl", GL_VERTEX_SHADER)); gObjectAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER)); gObjectAlphaMaskNoColorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectAlphaMaskNoColorProgram.createShader(NULL, NULL); + success = gObjectAlphaMaskNoColorProgram.createShader(); } if (success) @@ -2555,7 +2561,7 @@ bool LLViewerShaderMgr::loadShadersObject() gImpostorProgram.mShaderFiles.push_back(make_pair("objects/impostorV.glsl", GL_VERTEX_SHADER)); gImpostorProgram.mShaderFiles.push_back(make_pair("objects/impostorF.glsl", GL_FRAGMENT_SHADER)); gImpostorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gImpostorProgram.createShader(NULL, NULL); + success = gImpostorProgram.createShader(); } if (success) @@ -2567,7 +2573,7 @@ bool LLViewerShaderMgr::loadShadersObject() gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewF.glsl", GL_FRAGMENT_SHADER)); gObjectPreviewProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; success = make_rigged_variant(gObjectPreviewProgram, gSkinnedObjectPreviewProgram); - success = gObjectPreviewProgram.createShader(NULL, NULL); + success = gObjectPreviewProgram.createShader(); gObjectPreviewProgram.mFeatures.hasLighting = true; gSkinnedObjectPreviewProgram.mFeatures.hasLighting = true; } @@ -2586,7 +2592,7 @@ bool LLViewerShaderMgr::loadShadersObject() gPhysicsPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewPhysicsV.glsl", GL_VERTEX_SHADER)); gPhysicsPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewPhysicsF.glsl", GL_FRAGMENT_SHADER)); gPhysicsPreviewProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gPhysicsPreviewProgram.createShader(NULL, NULL); + success = gPhysicsPreviewProgram.createShader(); gPhysicsPreviewProgram.mFeatures.hasLighting = false; } @@ -2627,7 +2633,7 @@ bool LLViewerShaderMgr::loadShadersAvatar() gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER)); gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarF.glsl", GL_FRAGMENT_SHADER)); gAvatarProgram.mShaderLevel = mShaderLevel[SHADER_AVATAR]; - success = gAvatarProgram.createShader(NULL, NULL); + success = gAvatarProgram.createShader(); /// Keep track of avatar levels if (gAvatarProgram.mShaderLevel != mShaderLevel[SHADER_AVATAR]) @@ -2651,7 +2657,7 @@ bool LLViewerShaderMgr::loadShadersAvatar() gAvatarEyeballProgram.mShaderFiles.push_back(make_pair("avatar/eyeballV.glsl", GL_VERTEX_SHADER)); gAvatarEyeballProgram.mShaderFiles.push_back(make_pair("avatar/eyeballF.glsl", GL_FRAGMENT_SHADER)); gAvatarEyeballProgram.mShaderLevel = mShaderLevel[SHADER_AVATAR]; - success = gAvatarEyeballProgram.createShader(NULL, NULL); + success = gAvatarEyeballProgram.createShader(); } if( !success ) @@ -2677,7 +2683,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER)); gHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = make_rigged_variant(gHighlightProgram, gSkinnedHighlightProgram); - success = success && gHighlightProgram.createShader(NULL, NULL); + success = success && gHighlightProgram.createShader(); } if (success) @@ -2687,7 +2693,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightNormV.glsl", GL_VERTEX_SHADER)); gHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER)); gHighlightNormalProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gHighlightNormalProgram.createShader(NULL, NULL); + success = gHighlightNormalProgram.createShader(); } if (success) @@ -2697,7 +2703,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightSpecV.glsl", GL_VERTEX_SHADER)); gHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER)); gHighlightSpecularProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gHighlightSpecularProgram.createShader(NULL, NULL); + success = gHighlightSpecularProgram.createShader(); } if (success) @@ -2707,7 +2713,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gUIProgram.mShaderFiles.push_back(make_pair("interface/uiV.glsl", GL_VERTEX_SHADER)); gUIProgram.mShaderFiles.push_back(make_pair("interface/uiF.glsl", GL_FRAGMENT_SHADER)); gUIProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gUIProgram.createShader(NULL, NULL); + success = gUIProgram.createShader(); } if (success) @@ -2717,7 +2723,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gPathfindingProgram.mShaderFiles.push_back(make_pair("interface/pathfindingV.glsl", GL_VERTEX_SHADER)); gPathfindingProgram.mShaderFiles.push_back(make_pair("interface/pathfindingF.glsl", GL_FRAGMENT_SHADER)); gPathfindingProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gPathfindingProgram.createShader(NULL, NULL); + success = gPathfindingProgram.createShader(); } if (success) @@ -2727,7 +2733,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gPathfindingNoNormalsProgram.mShaderFiles.push_back(make_pair("interface/pathfindingNoNormalV.glsl", GL_VERTEX_SHADER)); gPathfindingNoNormalsProgram.mShaderFiles.push_back(make_pair("interface/pathfindingF.glsl", GL_FRAGMENT_SHADER)); gPathfindingNoNormalsProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gPathfindingNoNormalsProgram.createShader(NULL, NULL); + success = gPathfindingNoNormalsProgram.createShader(); } if (success) @@ -2737,7 +2743,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gGlowCombineProgram.mShaderFiles.push_back(make_pair("interface/glowcombineV.glsl", GL_VERTEX_SHADER)); gGlowCombineProgram.mShaderFiles.push_back(make_pair("interface/glowcombineF.glsl", GL_FRAGMENT_SHADER)); gGlowCombineProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gGlowCombineProgram.createShader(NULL, NULL); + success = gGlowCombineProgram.createShader(); if (success) { gGlowCombineProgram.bind(); @@ -2754,7 +2760,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gGlowCombineFXAAProgram.mShaderFiles.push_back(make_pair("interface/glowcombineFXAAV.glsl", GL_VERTEX_SHADER)); gGlowCombineFXAAProgram.mShaderFiles.push_back(make_pair("interface/glowcombineFXAAF.glsl", GL_FRAGMENT_SHADER)); gGlowCombineFXAAProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gGlowCombineFXAAProgram.createShader(NULL, NULL); + success = gGlowCombineFXAAProgram.createShader(); if (success) { gGlowCombineFXAAProgram.bind(); @@ -2772,7 +2778,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareV.glsl", GL_VERTEX_SHADER)); gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareF.glsl", GL_FRAGMENT_SHADER)); gTwoTextureCompareProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gTwoTextureCompareProgram.createShader(NULL, NULL); + success = gTwoTextureCompareProgram.createShader(); if (success) { gTwoTextureCompareProgram.bind(); @@ -2789,7 +2795,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterV.glsl", GL_VERTEX_SHADER)); gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterF.glsl", GL_FRAGMENT_SHADER)); gOneTextureFilterProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gOneTextureFilterProgram.createShader(NULL, NULL); + success = gOneTextureFilterProgram.createShader(); if (success) { gOneTextureFilterProgram.bind(); @@ -2805,7 +2811,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gSolidColorProgram.mShaderFiles.push_back(make_pair("interface/solidcolorV.glsl", GL_VERTEX_SHADER)); gSolidColorProgram.mShaderFiles.push_back(make_pair("interface/solidcolorF.glsl", GL_FRAGMENT_SHADER)); gSolidColorProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gSolidColorProgram.createShader(NULL, NULL); + success = gSolidColorProgram.createShader(); if (success) { gSolidColorProgram.bind(); @@ -2822,7 +2828,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER)); gOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; gOcclusionProgram.mRiggedVariant = &gSkinnedOcclusionProgram; - success = gOcclusionProgram.createShader(NULL, NULL); + success = gOcclusionProgram.createShader(); } if (success) @@ -2833,7 +2839,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionSkinnedV.glsl", GL_VERTEX_SHADER)); gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER)); gSkinnedOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gSkinnedOcclusionProgram.createShader(NULL, NULL); + success = gSkinnedOcclusionProgram.createShader(); } if (success) @@ -2843,7 +2849,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionCubeV.glsl", GL_VERTEX_SHADER)); gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER)); gOcclusionCubeProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gOcclusionCubeProgram.createShader(NULL, NULL); + success = gOcclusionCubeProgram.createShader(); } if (success) @@ -2855,7 +2861,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gDebugProgram.mRiggedVariant = &gSkinnedDebugProgram; gDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; success = make_rigged_variant(gDebugProgram, gSkinnedDebugProgram); - success = success && gDebugProgram.createShader(NULL, NULL); + success = success && gDebugProgram.createShader(); } if (success) @@ -2881,7 +2887,7 @@ bool LLViewerShaderMgr::loadShadersInterface() shader.addPermutation("HAS_ATTRIBUTE_TANGENT", "1"); } success = make_rigged_variant(shader, skinned_shader); - success = success && shader.createShader(NULL, NULL); + success = success && shader.createShader(); } } @@ -2892,7 +2898,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gClipProgram.mShaderFiles.push_back(make_pair("interface/clipV.glsl", GL_VERTEX_SHADER)); gClipProgram.mShaderFiles.push_back(make_pair("interface/clipF.glsl", GL_FRAGMENT_SHADER)); gClipProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gClipProgram.createShader(NULL, NULL); + success = gClipProgram.createShader(); } if (success) @@ -2902,7 +2908,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gBenchmarkProgram.mShaderFiles.push_back(make_pair("interface/benchmarkV.glsl", GL_VERTEX_SHADER)); gBenchmarkProgram.mShaderFiles.push_back(make_pair("interface/benchmarkF.glsl", GL_FRAGMENT_SHADER)); gBenchmarkProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gBenchmarkProgram.createShader(NULL, NULL); + success = gBenchmarkProgram.createShader(); } if (success) @@ -2918,7 +2924,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gReflectionProbeDisplayProgram.mShaderFiles.push_back(make_pair("interface/reflectionprobeV.glsl", GL_VERTEX_SHADER)); gReflectionProbeDisplayProgram.mShaderFiles.push_back(make_pair("interface/reflectionprobeF.glsl", GL_FRAGMENT_SHADER)); gReflectionProbeDisplayProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gReflectionProbeDisplayProgram.createShader(NULL, NULL); + success = gReflectionProbeDisplayProgram.createShader(); } if (success) @@ -2928,7 +2934,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gCopyProgram.mShaderFiles.push_back(make_pair("interface/copyV.glsl", GL_VERTEX_SHADER)); gCopyProgram.mShaderFiles.push_back(make_pair("interface/copyF.glsl", GL_FRAGMENT_SHADER)); gCopyProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gCopyProgram.createShader(NULL, NULL); + success = gCopyProgram.createShader(); } if (success) @@ -2940,7 +2946,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gCopyDepthProgram.clearPermutations(); gCopyDepthProgram.addPermutation("COPY_DEPTH", "1"); gCopyDepthProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gCopyDepthProgram.createShader(NULL, NULL); + success = gCopyDepthProgram.createShader(); } if (success) @@ -2950,7 +2956,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskV.glsl", GL_VERTEX_SHADER)); gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskF.glsl", GL_FRAGMENT_SHADER)); gAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gAlphaMaskProgram.createShader(NULL, NULL); + success = gAlphaMaskProgram.createShader(); } if (success) @@ -2964,7 +2970,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER)); gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/reflectionmipF.glsl", GL_FRAGMENT_SHADER)); gReflectionMipProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gReflectionMipProgram.createShader(NULL, NULL); + success = gReflectionMipProgram.createShader(); } if (success) @@ -2978,7 +2984,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gGaussianProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER)); gGaussianProgram.mShaderFiles.push_back(make_pair("interface/gaussianF.glsl", GL_FRAGMENT_SHADER)); gGaussianProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gGaussianProgram.createShader(NULL, NULL); + success = gGaussianProgram.createShader(); } if (success && gGLManager.mHasCubeMapArray) @@ -2989,7 +2995,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenF.glsl", GL_FRAGMENT_SHADER)); gRadianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; gRadianceGenProgram.addPermutation("PROBE_FILTER_SAMPLES", "32"); - success = gRadianceGenProgram.createShader(NULL, NULL); + success = gRadianceGenProgram.createShader(); } if (success && gGLManager.mHasCubeMapArray) @@ -3001,7 +3007,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gHeroRadianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; gHeroRadianceGenProgram.addPermutation("HERO_PROBES", "1"); gHeroRadianceGenProgram.addPermutation("PROBE_FILTER_SAMPLES", "4"); - success = gHeroRadianceGenProgram.createShader(NULL, NULL); + success = gHeroRadianceGenProgram.createShader(); } if (success && gGLManager.mHasCubeMapArray) @@ -3011,7 +3017,7 @@ bool LLViewerShaderMgr::loadShadersInterface() gIrradianceGenProgram.mShaderFiles.push_back(make_pair("interface/irradianceGenV.glsl", GL_VERTEX_SHADER)); gIrradianceGenProgram.mShaderFiles.push_back(make_pair("interface/irradianceGenF.glsl", GL_FRAGMENT_SHADER)); gIrradianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gIrradianceGenProgram.createShader(NULL, NULL); + success = gIrradianceGenProgram.createShader(); } if( !success ) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index b136ec55d8..4074abf893 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -527,8 +527,19 @@ F32 LLVOCacheEntry::getSquaredPixelThreshold(bool is_front) return projection_threshold; } +extern bool gCubeSnapshot; + 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 LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)getGroup(); if(!group) { @@ -565,6 +576,9 @@ bool LLVOCacheEntry::isAnyVisible(const LLVector4a& camera_origin, const LLVecto } return vis; +#else + return true; +#endif } void LLVOCacheEntry::calcSceneContribution(const LLVector4a& camera_origin, bool needs_update, U32 last_update, F32 max_dist) -- cgit v1.3 From 429c92ad75fd3b3f7b9dfc52ed034b25004a3b9c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 11 Jun 2024 13:27:54 -0500 Subject: #1687 Add support for KHR_texture_transform (#1717) --- indra/llrender/llshadermgr.cpp | 1 + indra/llrender/llshadermgr.h | 1 + .../shaders/class1/gltf/pbrmetallicroughnessF.glsl | 3 +- .../shaders/class1/gltf/pbrmetallicroughnessV.glsl | 37 +++++++++++++--- indra/newview/gltf/asset.cpp | 51 +++++++++++++++++++--- indra/newview/gltf/asset.h | 17 ++++++++ indra/newview/gltf/buffer_util.h | 37 +++++++++++++++- indra/newview/gltfscenemanager.cpp | 51 ++++++++++++++-------- 8 files changed, 164 insertions(+), 34 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 4d53df5f06..5f30fc3879 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1178,6 +1178,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("texture_base_color_transform"); // (GLTF) mReservedUniforms.push_back("texture_normal_transform"); // (GLTF) mReservedUniforms.push_back("texture_metallic_roughness_transform"); // (GLTF) + mReservedUniforms.push_back("texture_occlusion_transform"); // (GLTF) mReservedUniforms.push_back("texture_emissive_transform"); // (GLTF) mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF) diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 53e3d010db..244fc41de6 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -56,6 +56,7 @@ public: TEXTURE_BASE_COLOR_TRANSFORM, // "texture_base_color_transform" (GLTF) TEXTURE_NORMAL_TRANSFORM, // "texture_normal_transform" (GLTF) TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, // "texture_metallic_roughness_transform" (GLTF) + TEXTURE_OCCLUSION_TRANSFORM, // "texture_occlusion_transform" (GLTF) TEXTURE_EMISSIVE_TRANSFORM, // "texture_emissive_transform" (GLTF) TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF) diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index d71a3fad99..99bfcf70fa 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -61,6 +61,7 @@ in vec3 vary_tangent; flat in float vary_sign; in vec2 normal_texcoord; in vec2 metallic_roughness_texcoord; +in vec2 occlusion_texcoord; #endif // ================================== @@ -199,7 +200,7 @@ void main() // 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.r = texture(occlusionMap, occlusion_texcoord.xy).r; orm.g *= roughnessFactor; orm.b *= metallicFactor; #endif diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl index f123c29101..bc9a47d41e 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -39,6 +39,7 @@ 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; +uniform vec4[2] texture_occlusion_transform; in vec3 position; in vec4 diffuse_color; @@ -53,13 +54,37 @@ in vec3 normal; in vec4 tangent; out vec2 normal_texcoord; out vec2 metallic_roughness_texcoord; +out vec2 occlusion_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); +vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p) +{ + texcoord.y = 1.0 - texcoord.y; + + vec2 Scale = p[0].xy; + float Rotation = -p[0].z; + vec2 Offset = vec2(p[0].w, p[1].x); + + mat3 translation = mat3(1,0,0, 0,1,0, Offset.x, Offset.y, 1); + mat3 rotation = mat3( + cos(Rotation), sin(Rotation), 0, + -sin(Rotation), cos(Rotation), 0, + 0, 0, 1); + + mat3 scale = mat3(Scale.x,0,0, 0,Scale.y,0, 0,0,1); + + mat3 matrix = translation * rotation * scale; + + vec2 uvTransformed = ( matrix * vec3(texcoord.xy, 1) ).xy; + + uvTransformed.y = 1.0 - uvTransformed.y; + + return uvTransformed; +} #ifdef ALPHA_BLEND @@ -136,14 +161,14 @@ void main() 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); + base_color_texcoord = gltf_texture_transform(texcoord0, texture_base_color_transform); + emissive_texcoord = gltf_texture_transform(texcoord0, texture_emissive_transform); #ifndef UNLIT - normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0); - metallic_roughness_texcoord = texture_transform(texcoord0, texture_metallic_roughness_transform, texture_matrix0); + normal_texcoord = gltf_texture_transform(texcoord0, texture_normal_transform); + metallic_roughness_texcoord = gltf_texture_transform(texcoord0, texture_metallic_roughness_transform); + occlusion_texcoord = gltf_texture_transform(texcoord0, texture_occlusion_transform); #endif - #ifndef UNLIT #ifdef HAS_SKIN diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index a4efb25860..4c1da3e645 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -45,7 +45,8 @@ namespace LL namespace GLTF { static std::unordered_set ExtensionsSupported = { - "KHR_materials_unlit" + "KHR_materials_unlit", + "KHR_texture_transform" }; Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode) @@ -906,6 +907,7 @@ void Material::TextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); write(mTexCoord, "texCoord", dst, 0); + write_extensions(dst, &mTextureTransform, "KHR_texture_transform"); } const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) @@ -914,6 +916,7 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) { copy(src, "index", mIndex); copy(src, "texCoord", mTexCoord); + copy_extensions(src, "KHR_texture_transform", &mTextureTransform); } return *this; @@ -931,17 +934,16 @@ bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const void Material::OcclusionTextureInfo::serialize(object& dst) const { - write(mIndex, "index", dst, INVALID_INDEX); - write(mTexCoord, "texCoord", dst, 0); + TextureInfo::serialize(dst); write(mStrength, "strength", dst, 1.f); } const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src) { + TextureInfo::operator=(src); + if (src.is_object()) { - copy(src, "index", mIndex); - copy(src, "texCoord", mTexCoord); copy(src, "strength", mStrength); } @@ -950,13 +952,13 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( void Material::NormalTextureInfo::serialize(object& dst) const { - write(mIndex, "index", dst, INVALID_INDEX); - write(mTexCoord, "texCoord", dst, 0); + TextureInfo::serialize(dst); write(mScale, "scale", dst, 1.f); } const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src) { + TextureInfo::operator=(src); if (src.is_object()) { copy(src, "index", mIndex); @@ -1015,6 +1017,41 @@ void Material::Unlit::serialize(object& dst) const // no members and object has already been created, nothing to do } +void TextureTransform::getPacked(F32* packed) const +{ + packed[0] = mScale.x; + packed[1] = mScale.y; + packed[2] = mRotation; + packed[3] = mOffset.x; + packed[4] = mOffset.y; + + packed[5] = packed[6] = packed[7] = 0.f; +} + + +const TextureTransform& TextureTransform::operator=(const Value& src) +{ + mPresent = true; + if (src.is_object()) + { + copy(src, "offset", mOffset); + copy(src, "rotation", mRotation); + copy(src, "scale", mScale); + copy(src, "texCoord", mTexCoord); + } + + return *this; +} + +void TextureTransform::serialize(object& dst) const +{ + write(mOffset, "offset", dst, vec2(0.f, 0.f)); + write(mRotation, "rotation", dst, 0.f); + write(mScale, "scale", dst, vec2(1.f, 1.f)); + write(mTexCoord, "texCoord", dst, 0); +} + + void Material::serialize(object& dst) const { write(mName, "name", dst); diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index 8f28e5905f..bca269d5dc 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -57,6 +57,21 @@ namespace LL bool mPresent = false; }; + class TextureTransform : public Extension // KHR_texture_transform implementation + { + public: + vec2 mOffset = vec2(0.f, 0.f); + F32 mRotation = 0.f; + vec2 mScale = vec2(1.f, 1.f); + S32 mTexCoord = INVALID_INDEX; + + // get the texture transform as a packed array of floats + // dst MUST point to at least 8 floats + void getPacked(F32* dst) const; + + const TextureTransform& operator=(const Value& src); + void serialize(boost::json::object& dst) const; + }; class Material { @@ -82,6 +97,8 @@ namespace LL S32 mIndex = INVALID_INDEX; S32 mTexCoord = 0; + TextureTransform mTextureTransform; + bool operator==(const TextureInfo& rhs) const; bool operator!=(const TextureInfo& rhs) const; diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index c26752a6b6..943a1748f9 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -590,8 +590,8 @@ namespace LL // Write all extensions to dst.extensions // Usage: // write_extensions(dst, - // "KHR_materials_unlit", mUnlit, - // "KHR_materials_pbrSpecularGlossiness", mPbrSpecularGlossiness); + // mUnlit, "KHR_materials_unlit", + // mPbrSpecularGlossiness, "KHR_materials_pbrSpecularGlossiness"); // returns true if any of the extensions are written template inline bool write_extensions(boost::json::object& dst, Types... args) @@ -816,6 +816,39 @@ namespace LL return true; } + // vec2 + template<> + inline bool copy(const Value& src, vec2& dst) + { + if (src.is_array()) + { + const boost::json::array& arr = src.as_array(); + if (arr.size() == 2) + { + std::error_code ec; + vec3 t; + t.x = arr[0].to_number(ec); if (ec) return false; + t.y = arr[1].to_number(ec); if (ec) return false; + + dst = t; + return true; + } + } + return false; + } + + template<> + inline bool write(const vec2& src, Value& dst) + { + dst = boost::json::array(); + boost::json::array& arr = dst.as_array(); + arr.resize(2); + arr[0] = src.x; + arr[1] = src.y; + + return true; + } + // bool template<> inline bool copy(const Value& src, bool& dst) diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index d7eb605489..b390afee37 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -663,11 +663,30 @@ static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, { if (info.mIndex != INVALID_INDEX) { - LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture; + Texture& texture = asset.mTextures[info.mIndex]; + + LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture; if (tex) { tex->addTextureStats(2048.f * 2048.f); - LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex); + S32 channel = LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex); + + if (channel != -1 && texture.mSampler != -1) + { // set sampler state + Sampler& sampler = asset.mSamplers[texture.mSampler]; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter); + + // NOTE: do not set min filter. Always respect client preference for min filter + } + else + { + // set default sampler state + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } } else { @@ -710,10 +729,9 @@ void GLTFSceneManager::bind(Asset& asset, Material& material) 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); + F32 tf[8]; + material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(tf); + shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, tf); if (!LLPipeline::sShadowRender) { @@ -728,20 +746,17 @@ void GLTFSceneManager::bind(Asset& asset, Material& material) 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); + material.mNormalTexture.mTextureTransform.getPacked(tf); + shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, tf); + + material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(tf); + shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, tf); - 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); + material.mOcclusionTexture.mTextureTransform.getPacked(tf); + shader->uniform4fv(LLShaderMgr::TEXTURE_OCCLUSION_TRANSFORM, 2, tf); - 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); + material.mEmissiveTexture.mTextureTransform.getPacked(tf); + shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, tf); } } -- cgit v1.3 From f40fbdf4ad27a547e30781cd44cd6847d68d3300 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 11 Jun 2024 17:10:13 -0500 Subject: #1718 Add GLTF support for multiple texcoords (#1720) * Fix for GLTF MeshPrimitiveModes test --- indra/llrender/llglslshader.h | 4 +- indra/llrender/llrender.cpp | 2 +- indra/llrender/llshadermgr.cpp | 5 + indra/llrender/llshadermgr.h | 5 + indra/llrender/llvertexbuffer.cpp | 10 +- indra/llrender/llvertexbuffer.h | 3 +- .../shaders/class1/gltf/pbrmetallicroughnessF.glsl | 20 +- .../shaders/class1/gltf/pbrmetallicroughnessV.glsl | 92 ++++++++-- indra/newview/gltf/asset.cpp | 20 +- indra/newview/gltf/asset.h | 6 + indra/newview/gltf/buffer_util.h | 2 +- indra/newview/gltf/primitive.cpp | 201 ++++++++++++++++----- indra/newview/gltf/primitive.h | 3 +- indra/newview/gltfscenemanager.cpp | 19 +- indra/newview/llviewershadermgr.cpp | 10 +- 15 files changed, 318 insertions(+), 84 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index f2b5c4881c..d42df28809 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -328,14 +328,16 @@ public: // bit 0 = alpha mode blend (1) or opaque (0) // bit 1 = rigged (1) or static (0) // bit 2 = unlit (1) or lit (0) + // bit 3 = single (0) or multi (1) uv coordinates struct GLTFVariant { constexpr static U8 ALPHA_BLEND = 1; constexpr static U8 RIGGED = 2; constexpr static U8 UNLIT = 4; + constexpr static U8 MULTI_UV = 8; }; - constexpr static U8 NUM_GLTF_VARIANTS = 8; + constexpr static U8 NUM_GLTF_VARIANTS = 16; std::vector mGLTFVariants; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 51028e5667..cfefde3acc 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1686,7 +1686,7 @@ void LLRender::flush() if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0) { - vb->setTexCoordData(mTexcoordsp.get()); + vb->setTexCoord0Data(mTexcoordsp.get()); } if (attribute_mask & LLVertexBuffer::MAP_COLOR) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 5f30fc3879..6f4454f07a 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1180,6 +1180,11 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("texture_metallic_roughness_transform"); // (GLTF) mReservedUniforms.push_back("texture_occlusion_transform"); // (GLTF) mReservedUniforms.push_back("texture_emissive_transform"); // (GLTF) + mReservedUniforms.push_back("base_color_texcoord"); // (GLTF) + mReservedUniforms.push_back("emissive_texcoord"); // (GLTF) + mReservedUniforms.push_back("normal_texcoord"); // (GLTF) + mReservedUniforms.push_back("metallic_roughness_texcoord"); // (GLTF) + mReservedUniforms.push_back("occlusion_texcoord"); // (GLTF) mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF) diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 244fc41de6..c00aff3a9a 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -58,6 +58,11 @@ public: TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, // "texture_metallic_roughness_transform" (GLTF) TEXTURE_OCCLUSION_TRANSFORM, // "texture_occlusion_transform" (GLTF) TEXTURE_EMISSIVE_TRANSFORM, // "texture_emissive_transform" (GLTF) + BASE_COLOR_TEXCOORD, // "base_color_texcoord" (GLTF) + EMISSIVE_TEXCOORD, // "emissive_texcoord" (GLTF) + NORMAL_TEXCOORD, // "normal_texcoord" (GLTF) + METALLIC_ROUGHNESS_TEXCOORD, // "metallic_roughness_texcoord" (GLTF) + OCCLUSION_TEXCOORD, // "occlusion_texcoord" (GLTF) TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index a4d33c91df..33f7a6527f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1635,7 +1635,7 @@ void LLVertexBuffer::setPositionData(const LLVector4a* data) flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData); } -void LLVertexBuffer::setTexCoordData(const LLVector2* data) +void LLVertexBuffer::setTexCoord0Data(const LLVector2* data) { #if !LL_DARWIN llassert(sGLRenderBuffer == mGLBuffer); @@ -1643,6 +1643,14 @@ void LLVertexBuffer::setTexCoordData(const LLVector2* data) flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData); } +void LLVertexBuffer::setTexCoord1Data(const LLVector2* data) +{ +#if !LL_DARWIN + llassert(sGLRenderBuffer == mGLBuffer); +#endif + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + sTypeSize[TYPE_TEXCOORD1] * getNumVerts() - 1, (U8*)data, mMappedData); +} + void LLVertexBuffer::setColorData(const LLColor4U* data) { #if !LL_DARWIN diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 94339191a4..66a7f2bf26 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -196,7 +196,8 @@ public: void setTangentData(const LLVector4a* data); void setWeight4Data(const LLVector4a* data); void setJointData(const U64* data); - void setTexCoordData(const LLVector2* data); + void setTexCoord0Data(const LLVector2* data); + void setTexCoord1Data(const LLVector2* data); void setColorData(const LLColor4U* data); void setIndexData(const U16* data); void setIndexData(const U32* data); diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index 99bfcf70fa..789c00259b 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -37,8 +37,8 @@ uniform sampler2D emissiveMap; uniform vec3 emissiveColor; in vec3 vary_position; in vec4 vertex_color; -in vec2 base_color_texcoord; -in vec2 emissive_texcoord; +in vec2 base_color_uv; +in vec2 emissive_uv; uniform float minimum_alpha; void mirrorClip(vec3 pos); @@ -59,9 +59,9 @@ 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; -in vec2 occlusion_texcoord; +in vec2 normal_uv; +in vec2 metallic_roughness_uv; +in vec2 occlusion_uv; #endif // ================================== @@ -165,7 +165,7 @@ void main() vec3 pos = vary_position; mirrorClip(pos); - vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; + vec4 basecolor = texture(diffuseMap, base_color_uv.xy).rgba; basecolor.rgb = srgb_to_linear(basecolor.rgb); basecolor *= vertex_color; @@ -175,7 +175,7 @@ void main() } vec3 emissive = emissiveColor; - emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); + emissive *= srgb_to_linear(texture(emissiveMap, emissive_uv.xy).rgb); // ================================== // ================================== @@ -185,7 +185,7 @@ void main() // ================================== #ifndef UNLIT // from mikktspace.com - vec3 vNt = texture(normalMap, normal_texcoord.xy).xyz*2.0-1.0; + vec3 vNt = texture(normalMap, normal_uv.xy).xyz*2.0-1.0; float sign = vary_sign; vec3 vN = vary_normal; vec3 vT = vary_tangent.xyz; @@ -199,8 +199,8 @@ void main() // occlusion 1.0 // roughness 0.0 // metal 0.0 - vec3 orm = texture(metallicRoughnessMap, metallic_roughness_texcoord.xy).rgb; - orm.r = texture(occlusionMap, occlusion_texcoord.xy).r; + vec3 orm = texture(metallicRoughnessMap, metallic_roughness_uv.xy).rgb; + orm.r = texture(occlusionMap, occlusion_uv.xy).r; orm.g *= roughnessFactor; orm.b *= metallicFactor; #endif diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl index bc9a47d41e..aac3dc917f 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -33,7 +33,6 @@ uniform mat4 projection_matrix; 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; @@ -44,21 +43,31 @@ uniform vec4[2] texture_occlusion_transform; in vec3 position; in vec4 diffuse_color; in vec2 texcoord0; -out vec2 base_color_texcoord; -out vec2 emissive_texcoord; +out vec2 base_color_uv; +out vec2 emissive_uv; 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 vec2 occlusion_texcoord; +out vec2 normal_uv; +out vec2 metallic_roughness_uv; +out vec2 occlusion_uv; 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 + +#ifdef MULTI_UV +in vec2 texcoord1; +uniform int base_color_texcoord; +uniform int emissive_texcoord; +#ifndef UNLIT +uniform int normal_texcoord; +uniform int metallic_roughness_texcoord; +uniform int occlusion_texcoord; +#endif #endif vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p) @@ -86,6 +95,36 @@ vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p) return uvTransformed; } +#ifndef UNLIT +vec3 gltf_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) +{ //derived from tangent_space_transform in textureUtilV.glsl + vec2 weights = vec2(0, 1); + + // Convert to left-handed coordinate system + weights.y = -weights.y; + + // Apply KHR_texture_transform (rotation only) + float khr_rotation = khr_gltf_transform[0].z; + mat2 khr_rotation_mat = mat2( + cos(khr_rotation),-sin(khr_rotation), + sin(khr_rotation), cos(khr_rotation) + ); + weights = khr_rotation_mat * weights; + + // Convert back to right-handed coordinate system + weights.y = -weights.y; + + // Similar to the MikkTSpace-compatible method of extracting the binormal + // from the normal and tangent, as seen in the fragment shader + vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); + + return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); + + return vertex_tangent.xyz; +} +#endif + + #ifdef ALPHA_BLEND out vec3 vary_fragcoord; @@ -161,13 +200,40 @@ void main() gl_Position = vert; #endif - base_color_texcoord = gltf_texture_transform(texcoord0, texture_base_color_transform); - emissive_texcoord = gltf_texture_transform(texcoord0, texture_emissive_transform); + vec2 bcuv; + vec2 emuv; + +#ifdef MULTI_UV + vec2 uv[2]; + uv[0] = texcoord0; + uv[1] = texcoord1; + + bcuv = uv[base_color_texcoord]; + emuv = uv[emissive_texcoord]; +#else + bcuv = texcoord0; + emuv = texcoord0; +#endif + + base_color_uv = gltf_texture_transform(bcuv, texture_base_color_transform); + emissive_uv = gltf_texture_transform(emuv, texture_emissive_transform); #ifndef UNLIT - normal_texcoord = gltf_texture_transform(texcoord0, texture_normal_transform); - metallic_roughness_texcoord = gltf_texture_transform(texcoord0, texture_metallic_roughness_transform); - occlusion_texcoord = gltf_texture_transform(texcoord0, texture_occlusion_transform); + vec2 normuv; + vec2 rmuv; + vec2 ouv; +#ifdef MULTI_UV + normuv = uv[normal_texcoord]; + rmuv = uv[metallic_roughness_texcoord]; + ouv = uv[occlusion_texcoord]; +#else + normuv = texcoord0; + rmuv = texcoord0; + ouv = texcoord0; +#endif + normal_uv = gltf_texture_transform(normuv, texture_normal_transform); + metallic_roughness_uv = gltf_texture_transform(rmuv, texture_metallic_roughness_transform); + occlusion_uv = gltf_texture_transform(ouv, texture_occlusion_transform); #endif #ifndef UNLIT @@ -180,7 +246,7 @@ void main() #endif n = normalize(n); - vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0)); + vary_tangent = normalize(gltf_tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform)); vary_sign = tangent.w; vary_normal = n; #endif diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 4c1da3e645..21be69aae2 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -910,6 +910,24 @@ void Material::TextureInfo::serialize(object& dst) const write_extensions(dst, &mTextureTransform, "KHR_texture_transform"); } +S32 Material::TextureInfo::getTexCoord() const +{ + if (mTextureTransform.mPresent && mTextureTransform.mTexCoord != INVALID_INDEX) + { + return mTextureTransform.mTexCoord; + } + return mTexCoord; +} + +bool Material::isMultiUV() const +{ + return mPbrMetallicRoughness.mBaseColorTexture.getTexCoord() != 0 || + mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord() != 0 || + mNormalTexture.getTexCoord() != 0 || + mOcclusionTexture.getTexCoord() != 0 || + mEmissiveTexture.getTexCoord() != 0; +} + const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) { if (src.is_object()) @@ -1048,7 +1066,7 @@ void TextureTransform::serialize(object& dst) const write(mOffset, "offset", dst, vec2(0.f, 0.f)); write(mRotation, "rotation", dst, 0.f); write(mScale, "scale", dst, vec2(1.f, 1.f)); - write(mTexCoord, "texCoord", dst, 0); + write(mTexCoord, "texCoord", dst, -1); } diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index bca269d5dc..ea3f7d480a 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -102,6 +102,10 @@ namespace LL bool operator==(const TextureInfo& rhs) const; bool operator!=(const TextureInfo& rhs) const; + // get the UV channel that should be used for sampling this texture + // returns mTextureTransform.mTexCoord if present and valid, otherwise mTexCoord + S32 getTexCoord() const; + const TextureInfo& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -152,6 +156,8 @@ namespace LL bool mDoubleSided = false; Unlit mUnlit; + bool isMultiUV() const; + const Material& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index 943a1748f9..c1101818b7 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -826,7 +826,7 @@ namespace LL if (arr.size() == 2) { std::error_code ec; - vec3 t; + vec2 t; t.x = arr[0].to_number(ec); if (ec) return false; t.y = arr[1].to_number(ec); if (ec) return false; diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index bc333aff69..4cff0622b3 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -42,13 +42,14 @@ using namespace boost::json; // Mesh data useful for Mikktspace tangent generation (and flat normal generation) struct MikktMesh { - std::vector p; - std::vector n; - std::vector tc; - std::vector w; - std::vector t; - std::vector c; - std::vector j; + std::vector p; //positions + std::vector n; //normals + std::vector t; //tangents + std::vector tc0; //texcoords 0 + std::vector tc1; //texcoords 1 + std::vector c; //colors + std::vector w; //weights + std::vector j; //joints // initialize from src primitive and make an unrolled triangle list // returns false if the Primitive cannot be converted to a triangle list @@ -57,15 +58,28 @@ struct MikktMesh bool indexed = !prim->mIndexArray.empty(); U32 vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size(); - if (prim->mMode != Primitive::Mode::TRIANGLES) + U32 triangle_count = 0; + + if (prim->mMode == Primitive::Mode::TRIANGLE_STRIP || + prim->mMode == Primitive::Mode::TRIANGLE_FAN) + { + triangle_count = vert_count - 2; + } + else if (prim->mMode == Primitive::Mode::TRIANGLES) { - LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32) prim->mMode << LL_ENDL; + triangle_count = vert_count / 3; + } + else + { + LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32)prim->mMode << LL_ENDL; return false; } + vert_count = triangle_count * 3; + p.resize(vert_count); n.resize(vert_count); - tc.resize(vert_count); + tc0.resize(vert_count); c.resize(vert_count); bool has_normals = !prim->mNormals.empty(); @@ -78,6 +92,7 @@ struct MikktMesh { t.resize(vert_count); } + bool rigged = !prim->mWeights.empty(); if (rigged) { @@ -85,23 +100,69 @@ struct MikktMesh j.resize(vert_count); } - for (int i = 0; i < vert_count; ++i) + bool multi_uv = !prim->mTexCoords1.empty(); + if (multi_uv) { - U32 idx = indexed ? prim->mIndexArray[i] : i; + tc1.resize(vert_count); + } - p[i].set(prim->mPositions[idx].getF32ptr()); - tc[i].set(prim->mTexCoords[idx]); - c[i] = prim->mColors[idx]; + for (int tri_idx = 0; tri_idx < triangle_count; ++tri_idx) + { + U32 idx[3]; + + if (prim->mMode == Primitive::Mode::TRIANGLES) + { + idx[0] = tri_idx * 3; + idx[1] = tri_idx * 3 + 1; + idx[2] = tri_idx * 3 + 2; + } + else if (prim->mMode == Primitive::Mode::TRIANGLE_STRIP) + { + idx[0] = tri_idx; + idx[1] = tri_idx + 1; + idx[2] = tri_idx + 2; - if (has_normals) + if (tri_idx % 2 != 0) + { + std::swap(idx[1], idx[2]); + } + } + else if (prim->mMode == Primitive::Mode::TRIANGLE_FAN) { - n[i].set(prim->mNormals[idx].getF32ptr()); + idx[0] = 0; + idx[1] = tri_idx + 1; + idx[2] = tri_idx + 2; } - if (rigged) + if (indexed) { - w[i].set(prim->mWeights[idx].getF32ptr()); - j[i] = prim->mJoints[idx]; + idx[0] = prim->mIndexArray[idx[0]]; + idx[1] = prim->mIndexArray[idx[1]]; + idx[2] = prim->mIndexArray[idx[2]]; + } + + for (U32 v = 0; v < 3; ++v) + { + U32 i = tri_idx * 3 + v; + p[i].set(prim->mPositions[idx[v]].getF32ptr()); + tc0[i].set(prim->mTexCoords0[idx[v]]); + c[i] = prim->mColors[idx[v]]; + + if (multi_uv) + { + tc1[i].set(prim->mTexCoords1[idx[v]]); + } + + if (has_normals) + { + n[i].set(prim->mNormals[idx[v]].getF32ptr()); + } + + if (rigged) + { + w[i].set(prim->mWeights[idx[v]].getF32ptr()); + j[i] = prim->mJoints[idx[v]]; + } } } @@ -138,25 +199,34 @@ struct MikktMesh void write(Primitive* prim) const { //re-weld - meshopt_Stream mos[] = + std::vector 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) } + { &tc0[0], sizeof(LLVector2), sizeof(LLVector2) }, + { &c[0], sizeof(LLColor4U), sizeof(LLColor4U) } }; + if (!w.empty()) + { + mos.push_back({ &w[0], sizeof(LLVector4), sizeof(LLVector4) }); + mos.push_back({ &j[0], sizeof(U64), sizeof(U64) }); + } + + if (!tc1.empty()) + { + mos.push_back({ &tc1[0], sizeof(LLVector2), sizeof(LLVector2) }); + } + std::vector remap; remap.resize(p.size()); - U32 stream_count = w.empty() ? 5 : 7; + U32 stream_count = mos.size(); - size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos, stream_count); + size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos.data(), stream_count); - prim->mTexCoords.resize(vert_count); + prim->mTexCoords0.resize(vert_count); prim->mNormals.resize(vert_count); prim->mTangents.resize(vert_count); prim->mPositions.resize(vert_count); @@ -166,6 +236,10 @@ struct MikktMesh prim->mWeights.resize(vert_count); prim->mJoints.resize(vert_count); } + if (!tc1.empty()) + { + prim->mTexCoords1.resize(vert_count); + } prim->mIndexArray.resize(remap.size()); @@ -178,7 +252,7 @@ struct MikktMesh 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->mTexCoords0[dst_idx] = tc0[src_idx]; prim->mTangents[dst_idx].loadua(t[src_idx].mV); prim->mColors[dst_idx] = c[src_idx]; @@ -187,6 +261,11 @@ struct MikktMesh prim->mWeights[dst_idx].loadua(w[src_idx].mV); prim->mJoints[dst_idx] = j[src_idx]; } + + if (!tc1.empty()) + { + prim->mTexCoords1[dst_idx] = tc1[src_idx]; + } } prim->mGLMode = LLRender::TRIANGLES; @@ -210,8 +289,8 @@ struct MikktMesh 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); + F32* uv = tc0[face_num * 3 + vert_num].mV; + return mikk::float3(uv[0], 1.f-uv[1], 1.0f); } mikk::float3 GetNormal(const uint32_t face_num, const uint32_t vert_num) @@ -228,6 +307,14 @@ struct MikktMesh }; +static void vertical_flip(std::vector& texcoords) +{ + for (auto& tc : texcoords) + { + tc[1] = 1.f - tc[1]; + } +} + bool Primitive::prep(Asset& asset) { // allocate vertex buffer @@ -261,7 +348,11 @@ bool Primitive::prep(Asset& asset) } else if (attribName == "TEXCOORD_0") { - copy(asset, accessor, mTexCoords); + copy(asset, accessor, mTexCoords0); + } + else if (attribName == "TEXCOORD_1") + { + copy(asset, accessor, mTexCoords1); } else if (attribName == "JOINTS_0") { @@ -297,24 +388,28 @@ bool Primitive::prep(Asset& asset) mask |= LLVertexBuffer::MAP_JOINT; } - if (mTexCoords.empty()) + if (mTexCoords0.empty()) { - mTexCoords.resize(mPositions.size()); + mTexCoords0.resize(mPositions.size()); } - // TODO: support more than one texcoord set (or no texcoords) mask |= LLVertexBuffer::MAP_TEXCOORD0; + if (!mTexCoords1.empty()) + { + mask |= LLVertexBuffer::MAP_TEXCOORD1; + } + if (mColors.empty()) { mColors.resize(mPositions.size(), LLColor4U::white); } + mShaderVariant = 0; + // TODO: support colorless vertex buffers mask |= LLVertexBuffer::MAP_COLOR; - mShaderVariant = 0; - bool unlit = false; // bake material basecolor into color array @@ -332,6 +427,11 @@ bool Primitive::prep(Asset& asset) mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT; unlit = true; } + + if (material.isMultiUV()) + { + mShaderVariant |= LLGLSLShader::GLTFVariant::MULTI_UV; + } } if (mNormals.empty() && !unlit) @@ -434,15 +534,17 @@ bool Primitive::prep(Asset& asset) } // 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) + vertical_flip(mTexCoords0); + mVertexBuffer->setTexCoord0Data(mTexCoords0.data()); + vertical_flip(mTexCoords0); + + if (!mTexCoords1.empty()) { - tc[1] = 1.f - tc[1]; + vertical_flip(mTexCoords1); + mVertexBuffer->setTexCoord1Data(mTexCoords1.data()); + vertical_flip(mTexCoords1); } + if (!mIndexArray.empty()) { @@ -453,10 +555,13 @@ bool Primitive::prep(Asset& asset) mVertexBuffer->unbind(); - Material& material = asset.mMaterials[mMaterial]; - if (material.mAlphaMode == Material::AlphaMode::BLEND) + if (mMaterial != INVALID_INDEX) { - mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; + Material& material = asset.mMaterials[mMaterial]; + if (material.mAlphaMode == Material::AlphaMode::BLEND) + { + mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; + } } return true; @@ -614,7 +719,7 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, //create a proxy LLVolumeFace for the raycast LLVolumeFace face; face.mPositions = mPositions.data(); - face.mTexCoords = mTexCoords.data(); + face.mTexCoords = mTexCoords0.data(); face.mNormals = mNormals.data(); face.mTangents = mTangents.data(); face.mIndices = nullptr; // unreferenced diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index f9d7c63c65..7cc05cf831 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -58,7 +58,8 @@ namespace LL LLPointer mVertexBuffer; // CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code - std::vector mTexCoords; + std::vector mTexCoords0; + std::vector mTexCoords1; std::vector mNormals; std::vector mTangents; std::vector mPositions; diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index b390afee37..16f362b3e4 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -549,10 +549,16 @@ void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit) void GLTFSceneManager::render(U8 variant) { - // for debugging, just render the whole scene as opaque - // by traversing the whole scenegraph - // Assumes camera transform is already set and - // appropriate shader is already boundd + // just render the whole scene by traversing the whole scenegraph + // Assumes camera transform is already set and appropriate shader is already bound. + // Eventually we'll want a smarter render pipe that has pre-sorted the scene graph + // into buckets by material and shader. + + // HACK -- implicitly render multi-uv variant + if (!(variant & LLGLSLShader::GLTFVariant::MULTI_UV)) + { + render((U8) (variant | LLGLSLShader::GLTFVariant::MULTI_UV)); + } gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -732,6 +738,7 @@ void GLTFSceneManager::bind(Asset& asset, Material& material) F32 tf[8]; material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::BASE_COLOR_TEXCOORD, material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord()); if (!LLPipeline::sShadowRender) { @@ -748,15 +755,19 @@ void GLTFSceneManager::bind(Asset& asset, Material& material) material.mNormalTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::NORMAL_TEXCOORD, material.mNormalTexture.getTexCoord()); material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::METALLIC_ROUGHNESS_TEXCOORD, material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord()); material.mOcclusionTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_OCCLUSION_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::OCCLUSION_TEXCOORD, material.mOcclusionTexture.getTexCoord()); material.mEmissiveTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::EMISSIVE_TEXCOORD, material.mEmissiveTexture.getTexCoord()); } } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index d43d6fea37..5913e7ba6f 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -249,7 +249,7 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader } -static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool unlit, bool use_sun_shadow) +static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool unlit, bool multi_uv, bool use_sun_shadow) { variant.mName = shader.mName.c_str(); variant.mFeatures = shader.mFeatures; @@ -271,6 +271,11 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool variant.addPermutation("UNLIT", "1"); } + if (multi_uv) + { + variant.addPermutation("MULTI_UV", "1"); + } + if (alpha_blend) { variant.addPermutation("ALPHA_BLEND", "1"); @@ -317,8 +322,9 @@ static bool make_gltf_variants(LLGLSLShader& shader, bool use_sun_shadow) bool alpha_blend = i & LLGLSLShader::GLTFVariant::ALPHA_BLEND; bool rigged = i & LLGLSLShader::GLTFVariant::RIGGED; bool unlit = i & LLGLSLShader::GLTFVariant::UNLIT; + bool multi_uv = i & LLGLSLShader::GLTFVariant::MULTI_UV; - if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, use_sun_shadow)) + if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, multi_uv, use_sun_shadow)) { return false; } -- cgit v1.3 From a7b0f9391146b42dd5cd5f47f845de81bfdb6820 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Tue, 11 Jun 2024 15:39:48 -0700 Subject: Fixed signed/unsigned warnings after they got enabled in the maint-A merge --- indra/llmath/llvolumeoctree.h | 2 +- indra/newview/gltf/accessor.cpp | 5 +++-- indra/newview/gltf/animation.cpp | 11 +++++------ indra/newview/gltf/primitive.cpp | 19 +++++++++++-------- indra/newview/gltfscenemanager.cpp | 11 +++++++---- indra/newview/lldynamictexture.cpp | 4 ++-- indra/newview/llheroprobemanager.cpp | 10 ++++++---- indra/newview/llvocache.cpp | 3 +-- 8 files changed, 36 insertions(+), 29 deletions(-) (limited to 'indra/newview/gltfscenemanager.cpp') diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index 838e1d3db0..05d45f7b5f 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -186,7 +186,7 @@ public: llassert(!branch->isLeaf()); // Empty leaf } - for (S32 i = 0; i < branch->getChildCount(); ++i) + for (U32 i = 0; i < branch->getChildCount(); ++i) { //stretch by child extents LLVolumeOctreeListener* child = (LLVolumeOctreeListener*)branch->getChild(i)->getListener(0); min.setMin(min, child->mExtents[0]); diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 9f1cb0c1cd..2ef9237f2d 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -108,7 +108,8 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length) mData.erase(mData.begin() + offset, mData.begin() + offset + length); - mByteLength = mData.size(); + llassert(mData.size() <= size_t(INT_MAX)); + mByteLength = S32(mData.size()); for (BufferView& view : asset.mBufferViews) { @@ -141,7 +142,7 @@ bool Buffer::prep(Asset& asset) } mData.resize(mByteLength); - if (!file.read((U8*)mData.data(), mData.size())) + if (!file.read((U8*)mData.data(), mByteLength)) { LL_WARNS("GLTF") << "Failed to load buffer data from asset: " << id << LL_ENDL; return false; diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp index 45e9e1ddef..8f53c28539 100644 --- a/indra/newview/gltf/animation.cpp +++ b/indra/newview/gltf/animation.cpp @@ -189,16 +189,15 @@ void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F if (mFrameTimes.size() > 1) { + llassert(mFrameTimes.size() <= size_t(U32_MAX)); + frameIndex = U32(mFrameTimes.size()) - 2; + t = 1.f; + if (time > mMaxTime) { - frameIndex = mFrameTimes.size() - 2; - t = 1.0f; return; } - frameIndex = mFrameTimes.size() - 2; - t = 1.f; - for (U32 i = 0; i < mFrameTimes.size() - 1; i++) { if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1]) @@ -382,7 +381,7 @@ void Skin::uploadMatrixPalette(Asset& asset) glGenBuffers(1, &mUBO); } - U32 joint_count = llmin(max_joints, mJoints.size()); + size_t joint_count = llmin(max_joints, mJoints.size()); std::vector t_mp; diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index bc333aff69..197ffb68e8 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -55,7 +55,7 @@ struct MikktMesh bool copy(const Primitive* prim) { bool indexed = !prim->mIndexArray.empty(); - U32 vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size(); + auto vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size(); if (prim->mMode != Primitive::Mode::TRIANGLES) { @@ -85,7 +85,7 @@ struct MikktMesh j.resize(vert_count); } - for (int i = 0; i < vert_count; ++i) + for (U32 i = 0; i < vert_count; ++i) { U32 idx = indexed ? prim->mIndexArray[i] : i; @@ -110,8 +110,8 @@ struct MikktMesh void genNormals() { - U32 tri_count = p.size() / 3; - for (U32 i = 0; i < tri_count; ++i) + size_t tri_count = p.size() / 3; + for (size_t i = 0; i < tri_count; ++i) { LLVector3 v0 = p[i * 3]; LLVector3 v1 = p[i * 3 + 1]; @@ -166,7 +166,7 @@ struct MikktMesh prim->mWeights.resize(vert_count); prim->mJoints.resize(vert_count); } - + prim->mIndexArray.resize(remap.size()); for (int i = 0; i < remap.size(); ++i) @@ -411,7 +411,10 @@ bool Primitive::prep(Asset& asset) } mVertexBuffer = new LLVertexBuffer(mask); - mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size() * 2); // double the size of the index buffer for 32-bit indices + // we store these buffer sizes as S32 elsewhere + llassert(mPositions.size() <= size_t(S32_MAX)); + llassert(mIndexArray.size() <= size_t(S32_MAX / 2)); + mVertexBuffer->allocateBuffer(U32(mPositions.size()), U32(mIndexArray.size() * 2)); // double the size of the index buffer for 32-bit indices mVertexBuffer->setBuffer(); mVertexBuffer->setPositionData(mPositions.data()); @@ -619,8 +622,8 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, face.mTangents = mTangents.data(); face.mIndices = nullptr; // unreferenced - face.mNumIndices = mIndexArray.size(); - face.mNumVertices = mPositions.size(); + face.mNumIndices = S32(mIndexArray.size()); + face.mNumVertices = S32(mPositions.size()); LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out); intersect.traverse(mOctree); diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index d7eb605489..b948b2e2d6 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -244,7 +244,8 @@ void GLTFSceneManager::uploadSelection() LLFileSystem cache(assetId, LLAssetType::AT_GLTF_BIN, LLFileSystem::WRITE); auto& data = mUploadingAsset->mBuffers[idx].mData; - cache.write((const U8*)data.data(), data.size()); + llassert(data.size() <= size_t(S32_MAX)); + cache.write((const U8 *) data.data(), S32(data.size())); } }; #if GLTF_SIM_SUPPORT @@ -399,8 +400,9 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a { LLFileSystem file(id, asset_type, LLFileSystem::READ); std::string data; - data.resize(file.getSize()); - file.read((U8*)data.data(), data.size()); + S32 file_size = file.getSize(); + data.resize(file_size); + file.read((U8*)data.data(), file_size); boost::json::value json = boost::json::parse(data); @@ -479,7 +481,8 @@ void GLTFSceneManager::update() LLFileSystem cache(assetId, LLAssetType::AT_GLTF, LLFileSystem::WRITE); LL_INFOS("GLTF") << "Uploaded GLTF json: " << assetId << LL_ENDL; - cache.write((const U8 *) buffer.c_str(), buffer.size()); + llassert(buffer.size() <= size_t(S32_MAX)); + cache.write((const U8 *) buffer.c_str(), S32(buffer.size())); mUploadingAsset = nullptr; } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 739f85d4e6..fe6cd4e37d 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -217,8 +217,8 @@ bool LLViewerDynamicTexture::updateAllInstances() LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) { - llassert(dynamicTexture->getFullWidth() <= LLPipeline::MAX_BAKE_WIDTH); - llassert(dynamicTexture->getFullHeight() <= LLPipeline::MAX_BAKE_WIDTH); + llassert(dynamicTexture->getFullWidth() <= S32(LLPipeline::MAX_BAKE_WIDTH)); + llassert(dynamicTexture->getFullHeight() <= S32(LLPipeline::MAX_BAKE_WIDTH)); glClear(GL_DEPTH_BUFFER_BIT); diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index 83c7b8a354..f544b70329 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -101,7 +101,7 @@ void LLHeroProbeManager::update() U32 count = log2((F32)res) + 0.5f; mMipChain.resize(count); - for (int i = 0; i < count; ++i) + for (U32 i = 0; i < count; ++i) { mMipChain[i].allocate(res, res, GL_RGBA16F); res /= 2; @@ -198,7 +198,7 @@ void LLHeroProbeManager::update() mFaceUpdateList[i] = ceilf(cube_facing * gPipeline.RenderHeroProbeConservativeUpdateMultiplier); } - + mProbes[0]->mOrigin = probe_pos; } else @@ -359,7 +359,8 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, bool res /= 2; - S32 mip = i - (mMipChain.size() - mips); + llassert(mMipChain.size() <= size_t(S32_MAX)); + GLint mip = i - (S32(mMipChain.size()) - mips); if (mip >= 0) { @@ -487,7 +488,8 @@ void LLHeroProbeManager::updateUniforms() mHeroData.heroSphere.mV[3] = mProbes[0]->mRadius; } - mHeroData.heroMipCount = mMipChain.size(); + llassert(mMipChain.size() <= size_t(S32_MAX)); + mHeroData.heroMipCount = S32(mMipChain.size()); } void LLHeroProbeManager::renderDebug() diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 5f68051d10..7bbdd83a7f 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -1937,9 +1937,8 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle); U32 num_entries = 0; - U32 inmem_entries = 0; U32 skipped = 0; - inmem_entries = cache_extras_entry_map.size(); + size_t inmem_entries = cache_extras_entry_map.size(); for (auto [local_id, entry] : cache_extras_entry_map) { // Only write out GLTFOverrides that we can actually apply again on import. -- cgit v1.3