diff options
| author | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-05-28 03:15:43 +0300 |
|---|---|---|
| committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-05-28 18:16:43 +0300 |
| commit | 0be27809566c1378fa613aa7c42bfd2406a9f764 (patch) | |
| tree | c2fea1e46237c991a26d8aa763272ea60704865d | |
| parent | a1b68fb8ed6c2589dd13bd9ba1fab7050ba38226 (diff) | |
#5855 Added a way to check triangles for all lods
| -rw-r--r-- | indra/newview/llfloaterobjectweights.cpp | 228 | ||||
| -rw-r--r-- | indra/newview/llfloaterobjectweights.h | 21 | ||||
| -rw-r--r-- | indra/newview/llselectmgr.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llselectmgr.h | 1 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.cpp | 26 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 2 | ||||
| -rw-r--r-- | indra/newview/llvovolume.cpp | 13 | ||||
| -rw-r--r-- | indra/newview/llvovolume.h | 1 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_object_weights.xml | 172 |
9 files changed, 416 insertions, 49 deletions
diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index bd8530abd7..cf89518c03 100644 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -33,8 +33,10 @@ #include "lltextbox.h" #include "llagent.h" +#include "llcallbacklist.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" +#include "llmeshrepository.h" static const std::string lod_strings[4] = { @@ -74,6 +76,14 @@ bool LLCrossParcelFunctor::apply(LLViewerObject* obj) LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key) : LLFloater(key), + mWeightsDirty(false), + mSelectionDirty(true), + mSelectionMeshDirty(true), + mSelectionLastLOD(-1), + mSelectionLastTris(0), + mSelectionLastArea(0), + mLastActiveLODRequests(0), + mSelectionRefreshTime(0.), mSelectedObjects(NULL), mSelectedPrims(NULL), mSelectedDownloadWeight(NULL), @@ -88,6 +98,13 @@ LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key) mTrianglesShown(nullptr), mPixelArea(nullptr) { + mSelectionConnection = LLSelectMgr::getInstance()->mUpdateSignal.connect( + [this]() + { + mSelectionDirty = true; + mSelectionMeshDirty = true; // assume that mesh data will arrive with a delay. + } + ); } LLFloaterObjectWeights::~LLFloaterObjectWeights() @@ -114,6 +131,11 @@ bool LLFloaterObjectWeights::postBuild() mTrianglesShown = getChild<LLTextBox>("triangles_shown"); mPixelArea = getChild<LLTextBox>("pixel_area"); + mHighLodTris = getChild<LLTextBox>("high_lod_tris"); + mMediumLodTris = getChild<LLTextBox>("medium_lod_tris"); + mLowLodTris = getChild<LLTextBox>("low_lod_tris"); + mLowestLodTris = getChild<LLTextBox>("lowest_lod_tris"); + return true; } @@ -122,6 +144,14 @@ void LLFloaterObjectWeights::onOpen(const LLSD& key) { refresh(); updateLandImpacts(LLViewerParcelMgr::getInstance()->getFloatingParcelSelection()->getParcel()); + + onIdleRefresh(this); + gIdleCallbacks.addFunction(onIdleRefresh, this); +} + +void LLFloaterObjectWeights::onClose(bool app_quitting) +{ + gIdleCallbacks.deleteFunction(onIdleRefresh, this); } // virtual @@ -131,8 +161,9 @@ void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost mSelectedPhysicsWeight->setText(llformat("%.1f", selection_cost.mPhysicsCost)); mSelectedServerWeight->setText(llformat("%.1f", selection_cost.mSimulationCost)); - S32 render_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectRenderCost(); - mSelectedDisplayWeight->setText(llformat("%d", render_cost)); + // onWeightsUpdate comes from a coroutine. + // Postpone LLSelectMgr operations as getSelectedObjectRenderCost is not coroutine-safe + mWeightsDirty = true; toggleWeightsLoadingIndicators(false); } @@ -152,20 +183,13 @@ void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reaso void LLFloaterObjectWeights::draw() { - // Normally it's a bad idea to set text and visibility inside draw - // since it can cause rect updates go to different, already drawn elements, - // but floater is very simple and these elements are supposed to be isolated + // This logic might be a bit too expensive for draw(), + // but this floater needs to react fast, even if it's + // detrimental to performance. Having callbacks like + // 'tris changed' in every selected object might be + // more impactful on performance. LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - if (selection->isEmpty()) - { - const std::string text = getString("nothing_selected"); - mLodLevel->setText(text); - mTrianglesShown->setText(text); - mPixelArea->setText(text); - - toggleRenderLoadingIndicators(false); - } - else + if (!selection->isEmpty() && !mSelectionDirty) { S32 object_lod = -1; bool multiple_lods = false; @@ -192,27 +216,71 @@ void LLFloaterObjectWeights::draw() } } - if (multiple_lods) + if (mSelectionLastTris != total_tris) { - mLodLevel->setText(getString("multiple_lods")); - toggleRenderLoadingIndicators(false); + mSelectionDirty = true; } - else if (object_lod < 0) + else if (mSelectionLastArea != pixel_area) { - // nodes are waiting for data - toggleRenderLoadingIndicators(true); + mSelectionDirty = true; } - else + else if (multiple_lods) { - mLodLevel->setText(getString(lod_strings[object_lod])); - toggleRenderLoadingIndicators(false); + mSelectionDirty |= mSelectionLastLOD != -1; + } + else if (mSelectionLastLOD != object_lod) + { + mSelectionDirty = true; } - mTrianglesShown->setText(llformat("%d", total_tris)); - mPixelArea->setText(llformat("%ld", (S64)pixel_area)); // value capped at 10M } LLFloater::draw(); } +void LLFloaterObjectWeights::onIdleRefresh(void* user_data) +{ + LLFloaterObjectWeights* self = (LLFloaterObjectWeights*)user_data; + + F64 current_time = LLTimer::getTotalSeconds(); + S32 current_lod_requests = LLMeshRepoThread::sActiveLODRequests.load(); + // Can't look for a specific mesh (no callback mechanics and we + // need multiple ones), so just update periodically if something loads + self->mSelectionMeshDirty |= (self->mLastActiveLODRequests > current_lod_requests); + bool throttle_elapsed = (current_time - self->mSelectionRefreshTime) >= 2.0; + + if (self->mLastActiveLODRequests < current_lod_requests) + { + // we are interested in finished downloads, + // so don't refresh if more requests are getting added. + self->mLastActiveLODRequests = current_lod_requests; + } + + if (self->mSelectionDirty) + { + // Always refresh on selection changes + self->refreshDataFromSelection(); + self->mSelectionDirty = false; + self->mSelectionRefreshTime = current_time; + // refreshDataFromSelection could have indirectly initiated more requests + self->mLastActiveLODRequests = LLMeshRepoThread::sActiveLODRequests.load(); + } + else if (self->mSelectionMeshDirty && throttle_elapsed) + { + // LOD requests count changed or mesh needs lod data reload + self->refreshDataFromSelection(); + self->mSelectionRefreshTime = current_time; + self->mSelectionMeshDirty = false; + // refreshDataFromSelection could have indirectly initiated more requests + self->mLastActiveLODRequests = LLMeshRepoThread::sActiveLODRequests.load(); + } + else if (self->mWeightsDirty) // also done in refreshDataFromSelection + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + S32 render_cost = selection->getSelectedObjectRenderCost(); + self->mSelectedDisplayWeight->setText(llformat("%d", render_cost)); + self->mWeightsDirty = false; + } +} + void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel) { if (!parcel || LLSelectMgr::getInstance()->getSelection()->isEmpty()) @@ -240,6 +308,101 @@ void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel) } } +void LLFloaterObjectWeights::refreshDataFromSelection() +{ + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + if (selection->isEmpty()) + { + const std::string text = getString("nothing_selected"); + mLodLevel->setText(text); + mTrianglesShown->setText(text); + mPixelArea->setText(text); + + mHighLodTris->setText(text); + mMediumLodTris->setText(text); + mLowLodTris->setText(text); + mLowestLodTris->setText(text); + + toggleRenderLoadingIndicators(false); + toggleLODLoadingIndicators(false); + } + else + { + S32 object_lod = -1; + bool multiple_lods = false; + S32 total_tris = 0; + F32 pixel_area = 0; + S32 high_tris = 0; + S32 medium_tris = 0; + S32 low_tris = 0; + S32 lowest_tris = 0; + for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + iter != selection->valid_root_end(); ++iter) + { + LLViewerObject* object = (*iter)->getObject(); + S32 lod = object->getLOD(); + if (object_lod < 0) + { + object_lod = lod; + } + else if (object_lod != lod) + { + multiple_lods = true; + } + + if (object->isRootEdit()) + { + total_tris += object->recursiveGetTriangleCount(); + pixel_area += object->getPixelArea(); + object->recursiveGetLODTriangleCount(high_tris, medium_tris, low_tris, lowest_tris); + } + } + + mSelectionLastTris = total_tris; + mSelectionLastArea = pixel_area; + if (multiple_lods) + { + mSelectionLastLOD = -1; + } + else + { + mSelectionLastLOD = object_lod; + } + + if (multiple_lods) + { + mLodLevel->setText(getString("multiple_lods")); + toggleRenderLoadingIndicators(false); + toggleLODLoadingIndicators(false); + } + else if (object_lod < 0) + { + // nodes are waiting for data + toggleRenderLoadingIndicators(true); + toggleLODLoadingIndicators(true); + } + else + { + mLodLevel->setText(getString(lod_strings[object_lod])); + toggleRenderLoadingIndicators(false); + toggleLODLoadingIndicators(false); + } + mTrianglesShown->setText(llformat("%d", total_tris)); + mPixelArea->setText(llformat("%ld", (S64)pixel_area)); // value capped at 10M + mHighLodTris->setText(llformat("%d", high_tris)); + mMediumLodTris->setText(llformat("%d", medium_tris)); + mLowLodTris->setText(llformat("%d", low_tris)); + mLowestLodTris->setText(llformat("%d", lowest_tris)); + } + + if (mWeightsDirty) + { + S32 render_cost = selection->getSelectedObjectRenderCost(); + mSelectedDisplayWeight->setText(llformat("%d", render_cost)); + mWeightsDirty = false; + } +} + void LLFloaterObjectWeights::refresh() { LLSelectMgr* sel_mgr = LLSelectMgr::getInstance(); @@ -341,6 +504,19 @@ void LLFloaterObjectWeights::toggleRenderLoadingIndicators(bool visible) mPixelArea->setVisible(!visible); } +void LLFloaterObjectWeights::toggleLODLoadingIndicators(bool visible) +{ + childSetVisible("high_lod_tris_loading_indicator", visible); + childSetVisible("medium_lod_tris_loading_indicator", visible); + childSetVisible("low_lod_tris_loading_indicator", visible); + childSetVisible("lowest_lod_tris_loading_indicator", visible); + + mHighLodTris->setVisible(!visible); + mMediumLodTris->setVisible(!visible); + mLowLodTris->setVisible(!visible); + mLowestLodTris->setVisible(!visible); +} + void LLFloaterObjectWeights::updateIfNothingSelected() { const std::string text = getString("nothing_selected"); diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h index bda625564b..dac87d2a10 100644 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -61,13 +61,17 @@ public: bool postBuild() override; void onOpen(const LLSD& key) override; + void onClose(bool app_quitting) override; void onWeightsUpdate(const SelectionCost& selection_cost) override; void setErrorStatus(S32 status, const std::string& reason) override; void draw() override; + static void onIdleRefresh(void* user_data); + void updateLandImpacts(const LLParcel* parcel); + void refreshDataFromSelection(); void refresh() override; private: @@ -76,9 +80,19 @@ private: void toggleWeightsLoadingIndicators(bool visible); void toggleLandImpactsLoadingIndicators(bool visible); void toggleRenderLoadingIndicators(bool visible); + void toggleLODLoadingIndicators(bool visible); void updateIfNothingSelected(); + bool mWeightsDirty; + bool mSelectionDirty; + bool mSelectionMeshDirty; + F64 mSelectionRefreshTime; + S32 mSelectionLastLOD; + S32 mSelectionLastTris; + F32 mSelectionLastArea; + S32 mLastActiveLODRequests; + LLTextBox *mSelectedObjects; LLTextBox *mSelectedPrims; @@ -95,6 +109,13 @@ private: LLTextBox *mLodLevel; LLTextBox *mTrianglesShown; LLTextBox *mPixelArea; + + LLTextBox *mHighLodTris; + LLTextBox *mMediumLodTris; + LLTextBox *mLowLodTris; + LLTextBox *mLowestLodTris; + + boost::signals2::scoped_connection mSelectionConnection; }; #endif //LL_LLFLOATEROBJECTWEIGHTS_H diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 1b64eab3c0..72f92785fc 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -252,7 +252,6 @@ LLSelectMgr::LLSelectMgr() LLSelectMgr::~LLSelectMgr() { clearSelections(); - mSlectionLodModChangedConnection.disconnect(); } void LLSelectMgr::clearSelections() diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 11aad3b806..792a37297f 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -943,7 +943,6 @@ private: bool mForceSelection; std::vector<LLAnimPauseRequest> mPauseRequests; - boost::signals2::connection mSlectionLodModChangedConnection; }; // *DEPRECATED: For callbacks or observers, use diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 7c26cb3c9f..57915cca85 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -4034,6 +4034,11 @@ U32 LLViewerObject::getTriangleCount(S32* vcount) const return 0; } +U32 LLViewerObject::getLODTriangleCount(S32 lod) +{ + return 0; +} + U32 LLViewerObject::getHighLODTriangleCount() { return 0; @@ -4055,6 +4060,27 @@ U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const return total_tris; } +void LLViewerObject::recursiveGetLODTriangleCount(S32& high_lod, S32& medium_lod, S32& low_lod, S32& lowest_lod) +{ + high_lod = (S32)getLODTriangleCount(LLModel::LOD_HIGH); + medium_lod = (S32)getLODTriangleCount(LLModel::LOD_MEDIUM); + low_lod = (S32)getLODTriangleCount(LLModel::LOD_LOW); + lowest_lod = (S32)getLODTriangleCount(LLModel::LOD_IMPOSTOR); + LLViewerObject::const_child_list_t& child_list = getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + if (childp) + { + high_lod += (S32)childp->getLODTriangleCount(LLModel::LOD_HIGH); + medium_lod += (S32)childp->getLODTriangleCount(LLModel::LOD_MEDIUM); + low_lod += (S32)childp->getLODTriangleCount(LLModel::LOD_LOW); + lowest_lod += (S32)childp->getLODTriangleCount(LLModel::LOD_IMPOSTOR); + } + } +} + // This is using the stored surface area for each volume (which // defaults to 1.0 for the case of everything except a sculpt) and // then scaling it linearly based on the largest dimension in the diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 465e221ae4..54cdf046c7 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -427,10 +427,12 @@ public: virtual F32 getStreamingCost() const; virtual bool getCostData(LLMeshCostData& costs) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; + virtual U32 getLODTriangleCount(S32 lod); virtual U32 getHighLODTriangleCount(); F32 recursiveGetScaledSurfaceArea() const; U32 recursiveGetTriangleCount(S32* vcount = NULL) const; + void recursiveGetLODTriangleCount(S32 &high_lod, S32 &medium_lod, S32 &low_lod, S32 &lowest_lod); void setObjectCost(F32 cost); F32 getObjectCost(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 3b41ccb6fc..076e5eb22e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4445,7 +4445,7 @@ U32 LLVOVolume::getTriangleCount(S32* vcount) const return count; } -U32 LLVOVolume::getHighLODTriangleCount() +U32 LLVOVolume::getLODTriangleCount(S32 lod) { U32 ret = 0; @@ -4453,16 +4453,16 @@ U32 LLVOVolume::getHighLODTriangleCount() if (!isSculpted()) { - LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3); + LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), lod); ret = ref->getNumTriangles(); LLPrimitive::getVolumeManager()->unrefVolume(ref); } else if (isMesh()) { - LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3); + LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), lod); if (!ref->isMeshAssetLoaded() || ref->getNumVolumeFaces() == 0) { - gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH); + gMeshRepo.loadMesh(this, volume->getParams(), lod); } ret = ref->getNumTriangles(); LLPrimitive::getVolumeManager()->unrefVolume(ref); @@ -4475,6 +4475,11 @@ U32 LLVOVolume::getHighLODTriangleCount() return ret; } +U32 LLVOVolume::getHighLODTriangleCount() +{ + return getLODTriangleCount(LLModel::LOD_HIGH); +} + //static void LLVOVolume::preUpdateGeom() { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index b6044bc319..00d6138512 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -155,6 +155,7 @@ public: /*virtual*/ bool getCostData(LLMeshCostData& costs) const override; /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const override; + /*virtual*/ U32 getLODTriangleCount(S32 lod) override; /*virtual*/ U32 getHighLODTriangleCount() override; /*virtual*/ bool lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES diff --git a/indra/newview/skins/default/xui/en/floater_object_weights.xml b/indra/newview/skins/default/xui/en/floater_object_weights.xml index 709fbdd27e..e68c00a8d4 100644 --- a/indra/newview/skins/default/xui/en/floater_object_weights.xml +++ b/indra/newview/skins/default/xui/en/floater_object_weights.xml @@ -2,14 +2,14 @@ <floater can_close="true" can_tear_off="false" - height="372" + height="479" help_topic="object_weights" layout="topleft" name="object_weights" save_rect="true" single_instance="true" title="ADVANCED" - width="200"> + width="205"> <floater.string name="nothing_selected" value="--"/> @@ -48,7 +48,7 @@ name="objects" top_pad="3" value="--" - width="40" /> + width="45" /> <text follows="left|top" height="16" @@ -67,7 +67,7 @@ name="prims" top_pad="3" value="--" - width="40" /> + width="45" /> <text follows="left|top" height="16" @@ -85,7 +85,7 @@ left="10" name="selected_text_border" top_pad="5" - width="180"/> + width="185"/> <text @@ -107,7 +107,7 @@ name="download" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -134,7 +134,7 @@ name="physics" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -161,7 +161,7 @@ name="server" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -188,7 +188,7 @@ name="display" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -214,7 +214,7 @@ left="10" name="weights_text_border" top_pad="5" - width="180"/> + width="185"/> <text @@ -236,7 +236,7 @@ name="selected" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -263,7 +263,7 @@ name="rezzed_on_land" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -290,7 +290,7 @@ name="remaining_capacity" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -317,7 +317,7 @@ name="total_capacity" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -336,6 +336,15 @@ value="Total capacity" width="130" /> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="10" + name="rendering_text_border" + top_pad="5" + width="185"/> <text follows="left|top" @@ -356,7 +365,7 @@ name="lod_level" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -383,7 +392,7 @@ name="triangles_shown" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -410,7 +419,7 @@ name="pixel_area" top_pad="3" value="--" - width="40" /> + width="45" /> <loading_indicator follows="left|top" height="16" @@ -428,4 +437,133 @@ top_delta="0" value="Pixel Area" width="130" /> + + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="10" + name="lods_text_border" + top_pad="5" + width="185"/> + + <text + follows="left|top" + height="16" + layout="topleft" + left="10" + name="lod_info_text" + text_color="EmphasisColor" + top_pad="10" + value="LOD INFO" + width="180" /> + <text + follows="left|top" + halign="right" + height="16" + layout="topleft" + left="10" + name="high_lod_tris" + top_pad="3" + value="--" + width="45" /> + <loading_indicator + follows="left|top" + height="16" + layout="topleft" + left="34" + name="high_lod_tris_loading_indicator" + top_delta="0" + width="16" /> + <text + follows="left|top" + height="16" + layout="topleft" + left_pad="10" + name="high_lod_tris_label" + top_delta="0" + value="High triangles" + width="130" /> + <text + follows="left|top" + halign="right" + height="16" + layout="topleft" + left="10" + name="medium_lod_tris" + top_pad="3" + value="--" + width="45" /> + <loading_indicator + follows="left|top" + height="16" + layout="topleft" + left="34" + name="medium_lod_tris_loading_indicator" + top_delta="0" + width="16" /> + <text + follows="left|top" + height="16" + layout="topleft" + left_pad="10" + name="medium_lod_tris_label" + top_delta="0" + value="Medium triangles" + width="130" /> + <text + follows="left|top" + halign="right" + height="16" + layout="topleft" + left="10" + name="low_lod_tris" + top_pad="3" + value="--" + width="45" /> + <loading_indicator + follows="left|top" + height="16" + layout="topleft" + left="34" + name="low_lod_tris_loading_indicator" + top_delta="0" + width="16" /> + <text + follows="left|top" + height="16" + layout="topleft" + left_pad="10" + name="low_lod_tris_label" + top_delta="0" + value="Low triangles" + width="130" /> + <text + follows="left|top" + halign="right" + height="16" + layout="topleft" + left="10" + name="lowest_lod_tris" + top_pad="3" + value="--" + width="45" /> + <loading_indicator + follows="left|top" + height="16" + layout="topleft" + left="34" + name="lowest_lod_tris_loading_indicator" + top_delta="0" + width="16" /> + <text + follows="left|top" + height="16" + layout="topleft" + left_pad="10" + name="lowest_lod_tris_label" + top_delta="0" + value="Lowest triangles" + width="130" /> </floater> |
