diff options
| author | RunitaiLinden <davep@lindenlab.com> | 2024-04-30 21:57:42 -0500 | 
|---|---|---|
| committer | RunitaiLinden <davep@lindenlab.com> | 2024-04-30 21:57:42 -0500 | 
| commit | 170765fd3505410dced83b342f87030fd9151e35 (patch) | |
| tree | f3665586f2d731a04bf645bc1155bbddc6c5f7e8 | |
| parent | 5e2bac01cb6e8d3de3cc0e496d94a729e4740247 (diff) | |
#1357 Proof of concept on decomposing a GLTF scene into its component parts
| -rw-r--r-- | indra/llmath/llvolumeoctree.h | 6 | ||||
| -rw-r--r-- | indra/newview/gltf/accessor.cpp | 18 | ||||
| -rw-r--r-- | indra/newview/gltf/accessor.h | 4 | ||||
| -rw-r--r-- | indra/newview/gltf/asset.cpp | 102 | ||||
| -rw-r--r-- | indra/newview/gltf/asset.h | 11 | ||||
| -rw-r--r-- | indra/newview/gltfscenemanager.cpp | 45 | ||||
| -rw-r--r-- | indra/newview/gltfscenemanager.h | 4 | ||||
| -rw-r--r-- | indra/newview/llviewermenu.cpp | 11 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/menu_viewer.xml | 6 | 
9 files changed, 199 insertions, 8 deletions
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<LLImageRaw> raw = new LLImageRaw(mWidth, mHeight, mComponent); +        U8* data = raw->allocateData(); +        llassert(mData.size() == raw->getDataSize()); +        memcpy(data, mData.data(), mData.size()); + +        LLViewerTextureList::createUploadFile(raw, filename, 4096); + +        mData.clear(); +    } + +    mWidth = -1; +    mHeight = -1; +    mComponent = -1; +    mBits = -1; +    mPixelType = -1; +    mMimeType = ""; + +}  const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src)  { 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<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) +            { +                if (LLAppViewer::instance()->quitRequested()) +                { +                    return; +                } +                if (filenames.size() > 0) +                { +                    GLTFSceneManager::instance().decomposeSelection(filenames[0]); +                } +            }, +            LLFilePicker::FFSAVE_GLTF, +            "scene.gltf"); +    } +    else +    { +        LLNotificationsUtil::add("GLTFSaveSelection"); +    } +} + +void GLTFSceneManager::decomposeSelection(const std::string& filename) +{ +    LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); +    if (obj && obj->mGLTFAsset.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"            <menu_item_call.on_click             function="Advanced.ClickGLTFSaveAs" />          </menu_item_call> +        <menu_item_call +         label="Decompose..." +         name="Decompose..."> +          <menu_item_call.on_click +           function="Advanced.ClickGLTFDecompose" /> +        </menu_item_call>        </menu>          <menu           create_jump_keys="true"  | 
