diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/llterrainpaintmap.cpp | 118 | ||||
-rw-r--r-- | indra/newview/llterrainpaintmap.h | 38 | ||||
-rw-r--r-- | indra/newview/llviewermenu.cpp | 46 | ||||
-rw-r--r-- | indra/newview/llvlcomposition.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llvlcomposition.h | 6 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_viewer.xml | 7 |
6 files changed, 221 insertions, 2 deletions
diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 8ccde74c93..6979464cd3 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -38,18 +38,31 @@ #include "llsurface.h" #include "llsurfacepatch.h" #include "llviewercamera.h" +#include "llviewercontrol.h" #include "llviewerregion.h" #include "llviewershadermgr.h" #include "llviewertexture.h" -// static -bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +namespace +{ +#ifdef SHOW_ASSERT +void check_tex(const LLViewerTexture& tex) { llassert(tex.getComponents() == 3); llassert(tex.getWidth() > 0 && tex.getHeight() > 0); llassert(tex.getWidth() == tex.getHeight()); llassert(tex.getPrimaryFormat() == GL_RGB); llassert(tex.getGLTexture()); +} +#endif +} // namespace + +// static +bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif const LLSurface& surface = region.getLand(); const U32 patch_count = surface.getPatchesPerEdge(); @@ -283,3 +296,104 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& return success; } + +// TODO: Decide when to apply the paint queue - ideally once per frame per region +// Applies paints and then clears the paint queue +// *NOTE The paint queue is also cleared when setting the paintmap texture +void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue) +{ + if (queue.empty()) { return; } + +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + + gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); + + const std::vector<LLTerrainPaint::ptr_t>& queue_list = queue.get(); + for (size_t i = 0; i < queue_list.size(); ++i) + { + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + queue.convertBitDepths(i, 8); + const LLTerrainPaint::ptr_t& paint = queue_list[i]; + + if (paint->mData.empty()) { continue; } + constexpr GLint level = 0; + if ((paint->mStartX >= tex.getWidth() - 1) || (paint->mStartY >= tex.getHeight() - 1)) { continue; } + constexpr GLint miplevel = 0; + const S32 x_offset = paint->mStartX; + const S32 y_offset = paint->mStartY; + const S32 width = llmin(paint->mWidthX, tex.getWidth() - x_offset); + const S32 height = llmin(paint->mWidthY, tex.getHeight() - y_offset); + const U8* pixels = paint->mData.data(); + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + glTexSubImage2D(GL_TEXTURE_2D, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, pixels); + stop_glerror(); + } + + // Generating mipmaps at the end... + glGenerateMipmap(GL_TEXTURE_2D); + stop_glerror(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + queue.clear(); +} + +bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) +{ + llassert(paint); + if (!paint) { return false; } + + // The paint struct should be pre-validated before this code is reached. + llassert(!paint->mData.empty()); + // The internal paint map image is currently 8 bits, so that's the maximum + // allowed bit depth. + llassert(paint->mBitDepth > 0 && paint->mBitDepth <= 8); + llassert(paint->mData.size() == (LLTerrainPaint::COMPONENTS * paint->mWidthX * paint->mWidthY)); + llassert(paint->mWidthX > 0); + llassert(paint->mWidthY > 0); +#ifdef SHOW_ASSERT + static LLCachedControl<U32> max_texture_width(gSavedSettings, "RenderMaxTextureResolution", 2048); +#endif + llassert(paint->mWidthX <= max_texture_width); + llassert(paint->mWidthY <= max_texture_width); + llassert(paint->mStartX < max_texture_width); + llassert(paint->mStartY < max_texture_width); + + mList.push_back(paint); + return true; +} + +bool LLTerrainPaintQueue::empty() const +{ + return mList.empty(); +} + +void LLTerrainPaintQueue::clear() +{ + mList.clear(); +} + +void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) +{ + llassert(target_bit_depth > 0 && target_bit_depth <= 8); + llassert(index < mList.size()); + + LLTerrainPaint::ptr_t& paint = mList[index]; + if (paint->mBitDepth == target_bit_depth) { return; } + + const F32 old_bit_max = F32((1 << paint->mBitDepth) - 1); + const F32 new_bit_max = F32((1 << target_bit_depth) - 1); + const F32 bit_conversion_factor = new_bit_max / old_bit_max; + + for (U8& color : paint->mData) + { + color = (U8)llround(F32(color) * bit_conversion_factor); + } + + paint->mBitDepth = target_bit_depth; +} diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h index 66827862c5..9189f12cbd 100644 --- a/indra/newview/llterrainpaintmap.h +++ b/indra/newview/llterrainpaintmap.h @@ -28,6 +28,7 @@ class LLViewerRegion; class LLViewerTexture; +class LLTerrainPaintQueue; class LLTerrainPaintMap { @@ -39,4 +40,41 @@ public: // to type TERRAIN_PAINT_TYPE_PBR_PAINTMAP. // Returns true if successful static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex); + + static void applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue); +}; + +// Enqueued paint operations, in texture coordinates. +// data is always RGB, with each U8 storing one color in the provided bit depth. +class LLTerrainPaint +{ +public: + using ptr_t = std::shared_ptr<LLTerrainPaint>; + + U16 mStartX; + U16 mStartY; + U16 mWidthX; + U16 mWidthY; + U8 mBitDepth; + static const U8 COMPONENTS = 3; + std::vector<U8> mData; +}; + +class LLTerrainPaintQueue +{ +public: + bool enqueue(LLTerrainPaint::ptr_t& paint); + bool empty() const; + void clear(); + + const std::vector<LLTerrainPaint::ptr_t>& get() const { return mList; } + + // Convert mBitDepth for the LLTerrainPaint in the queue at index + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + void convertBitDepths(size_t index, U8 target_bit_depth); + +private: + std::vector<LLTerrainPaint::ptr_t> mList; }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 10506e0e74..fa6e8870b3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -117,6 +117,7 @@ #include "lltoolmgr.h" #include "lltoolpie.h" #include "lltoolselectland.h" +#include "llterrainpaintmap.h" #include "lltrans.h" #include "llviewerdisplay.h" //for gWindowResized #include "llviewergenericmessage.h" @@ -1448,6 +1449,50 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t } }; +class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerTexture* tex = gLocalTerrainMaterials.getPaintMap(); + if (!tex) + { + LL_WARNS() << "No local paint map available to edit" << LL_ENDL; + return false; + } + + LLTerrainPaintQueue& paint_queue = gLocalTerrainMaterials.getPaintQueue(); + + // Enqueue a paint + // Overrides an entire region patch with the material in the last slot + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + LLTerrainPaint::ptr_t paint = std::make_shared<LLTerrainPaint>(); + const U16 width = U16(tex->getWidth() / 16); + paint->mStartX = width - 1; + paint->mStartY = width - 1; + paint->mWidthX = width; + paint->mWidthY = width; + constexpr U8 bit_depth = 5; + paint->mBitDepth = bit_depth; + constexpr U8 max_value = (1 << bit_depth) - 1; + const size_t pixel_count = width * width; + paint->mData.resize(LLTerrainPaint::COMPONENTS * pixel_count); + for (size_t pixel = 0; pixel < pixel_count; ++pixel) + { + paint->mData[(LLTerrainPaint::COMPONENTS*pixel) + LLTerrainPaint::COMPONENTS - 1] = max_value; + } + paint_queue.enqueue(paint); + + // Apply the paint queue ad-hoc right here for now. + // *TODO: Eventually the paint queue should be applied at a predictable + // time in the viewer frame loop. + LLTerrainPaintMap::applyPaintQueue(*tex, paint_queue); + + return true; + } +}; + class LLAdvancedTerrainDeleteLocalPaintMap : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9813,6 +9858,7 @@ void initialize_menus() // Develop > Terrain view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain"); view_listener_t::addMenu(new LLAdvancedTerrainCreateLocalPaintMap(), "Advanced.TerrainCreateLocalPaintMap"); + view_listener_t::addMenu(new LLAdvancedTerrainEditLocalPaintMap(), "Advanced.TerrainEditLocalPaintMap"); view_listener_t::addMenu(new LLAdvancedTerrainDeleteLocalPaintMap(), "Advanced.TerrainDeleteLocalPaintMap"); // Advanced > UI diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index 077e6e6cb1..d87658ba89 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -317,10 +317,18 @@ LLViewerTexture* LLTerrainMaterials::getPaintMap() return mPaintMap.get(); } +LLTerrainPaintQueue& LLTerrainMaterials::getPaintQueue() +{ + return mPaintQueue; +} + void LLTerrainMaterials::setPaintMap(LLViewerTexture* paint_map) { llassert(!paint_map || mPaintType == TERRAIN_PAINT_TYPE_PBR_PAINTMAP); + const bool changed = paint_map != mPaintMap; mPaintMap = paint_map; + // The paint map has changed, so edits are no longer valid + mPaintQueue.clear(); } // Boost the texture loading priority diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index f15f9bff6a..972a46d8db 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -27,10 +27,13 @@ #ifndef LL_LLVLCOMPOSITION_H #define LL_LLVLCOMPOSITION_H +#include <memory> + #include "llviewerlayer.h" #include "llviewershadermgr.h" #include "llviewertexture.h" #include "llpointer.h" +#include "llterrainpaintmap.h" #include "llimage.h" @@ -87,6 +90,8 @@ public: void setPaintType(U32 paint_type) { mPaintType = paint_type; } LLViewerTexture* getPaintMap(); void setPaintMap(LLViewerTexture* paint_map); + // Paint queue for current paint map + LLTerrainPaintQueue& getPaintQueue(); protected: void unboost(); @@ -105,6 +110,7 @@ protected: U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE; LLPointer<LLViewerTexture> mPaintMap; + LLTerrainPaintQueue mPaintQueue; }; // Local materials to override all regions diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index e1d33e5bc3..74ced74178 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3826,6 +3826,13 @@ function="World.EnvPreset" </menu_item_call> <menu_item_call enabled="true" + label="Edit Local Paintmap" + name="Edit Local Paintmap"> + <menu_item_call.on_click + function="Advanced.TerrainEditLocalPaintMap" /> + </menu_item_call> + <menu_item_call + enabled="true" label="Delete Local Paintmap" name="Delete Local Paintmap"> <menu_item_call.on_click |