diff options
author | Dave Parks <davep@lindenlab.com> | 2010-09-29 16:09:21 -0500 |
---|---|---|
committer | Dave Parks <davep@lindenlab.com> | 2010-09-29 16:09:21 -0500 |
commit | 0c93da0501ab1debd6fa11af29a215be81f7b803 (patch) | |
tree | 6000b7d56747ddc210c52f7fea55a99a8aee6414 /indra | |
parent | 91a8d7a2191e670e160e64859792db390b5d1757 (diff) |
SH-224 Add new streaming cost algorithm debug displays to viewer.
Add the ability to clear LOD slots.
Make triangle count UI more responsive to Generate LOD button.
Add triangle count debug display for current selection.
Reviewed by Nyx
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
-rw-r--r-- | indra/newview/llfloatermodelpreview.cpp | 161 | ||||
-rw-r--r-- | indra/newview/llfloatermodelpreview.h | 4 | ||||
-rw-r--r-- | indra/newview/llmeshrepository.cpp | 66 | ||||
-rw-r--r-- | indra/newview/llmeshrepository.h | 3 | ||||
-rw-r--r-- | indra/newview/llselectmgr.cpp | 34 | ||||
-rw-r--r-- | indra/newview/llselectmgr.h | 2 | ||||
-rw-r--r-- | indra/newview/llviewerobject.cpp | 10 | ||||
-rw-r--r-- | indra/newview/llviewerobject.h | 3 | ||||
-rw-r--r-- | indra/newview/llviewerwindow.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llvovolume.cpp | 39 | ||||
-rw-r--r-- | indra/newview/llvovolume.h | 3 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_model_preview.xml | 47 |
13 files changed, 324 insertions, 67 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 5033799e88..24d37c2442 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8581,6 +8581,17 @@ <key>Value</key> <real>1.0</real> </map> + <key>MeshStreamingCostScaler</key> + <map> + <key>Comment</key> + <string>DEBUG</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.25f</real> + </map> <key>MeshThreadCount</key> <map> <key>Comment</key> diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f995ddd6d0..f98a708dae 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -300,6 +300,8 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + childSetCommitCallback("debug scale", onDebugScaleCommit, this); + childDisable("upload_skin"); childDisable("upload_joints"); @@ -354,6 +356,23 @@ void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) { if (mode == 0) { + if (lod != LLModel::LOD_PHYSICS) + { + for (S32 i = lod; i > 0; i--) + { + mModelPreview->clearModel(lod); + } + } + else + { + mModelPreview->clearModel(lod); + } + + mModelPreview->refresh(); + mModelPreview->calcResourceCost(); + } + else if (mode == 1) + { loadModel(lod); } else if (mode != mModelPreview->mLODMode[lod]) @@ -367,7 +386,7 @@ void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) LLSpinCtrl* lim = getChild<LLSpinCtrl>(limit_name[lod], TRUE); - if (mode == 1) //triangle count + if (mode == 2) //triangle count { U32 tri_count = 0; for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); @@ -396,6 +415,19 @@ void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) } //static +void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); +} + +//static void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; @@ -2055,6 +2087,10 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; + F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); + + F32 streaming_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; @@ -2076,18 +2112,35 @@ U32 LLModelPreview::calcResourceCost() mFMP->childGetValue("upload_joints").asBoolean(), true); cost += gMeshRepo.calcResourceCost(ret); - num_hulls += physics_shape.size(); for (U32 i = 0; i < physics_shape.size(); ++i) { num_points += physics_shape[i].size(); } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); } } mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); updateStatusMessages(); @@ -2136,6 +2189,18 @@ void LLModelPreview::rebuildUploadData() } +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + void LLModelPreview::loadModel(std::string filename, S32 lod) { LLMutexLock lock(this); @@ -2639,65 +2704,63 @@ void LLModelPreview::genLODs(S32 which_lod) } - if (which_lod == -1 || mLODMode[which_lod] == 1) - { - //generating LODs for all entries, or this entry has a triangle budget - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - } - else - { - //this entry uses error mode - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - } - - if (which_lod != -1 && mLODMode[which_lod] == 2) - { - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, llmax(limit/100.f, 0.01f)); - stop_gloderror(); - } - else - { - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - } + //generating LODs for all entries, or this entry has a triangle budget + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); } S32 start = LLModel::LOD_HIGH; S32 end = 0; - BOOL error_mode = FALSE; - if (which_lod != -1) { start = end = which_lod; - - if (mLODMode[which_lod] == 2) - { - error_mode = TRUE; - } } + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo" + }; + + std::string limit_name[] = + { + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit" + }; + for (S32 lod = start; lod >= end; --lod) { - if (!error_mode) + if (which_lod == -1) { - if (which_lod == -1) + if (lod < start) { - if (lod < start) - { - triangle_count /= 3; - } - } - else - { - triangle_count = limit; + triangle_count /= 3; } } + else + { + triangle_count = limit; + } + LLComboBox* combo_box = mFMP->findChild<LLComboBox>(combo_name[lod]); + combo_box->setCurrentByIndex(2); + + LLSpinCtrl* lim = mFMP->getChild<LLSpinCtrl>(limit_name[lod], TRUE); + lim->setMaxValue(base_triangle_count); + lim->setVisible(true); + mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); @@ -2712,22 +2775,14 @@ void LLModelPreview::genLODs(S32 which_lod) U32 target_count = U32(mPercentage[base]*triangle_count); - if (error_mode) - { - target_count = base->getNumTriangles(); - } - if (target_count < 4) { target_count = 4; } - if (which_lod == -1 || mLODMode[which_lod] == 1) - { - glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); - stop_gloderror(); - } - + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + stop_gloderror(); + glodAdaptGroup(mGroup[base]); stop_gloderror(); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 08ac3873db..8409249182 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -127,6 +127,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex void pan(F32 right, F32 up); virtual BOOL needsRender() { return mNeedsUpdate; } void setPreviewLOD(S32 lod); + void clearModel(S32 lod); void loadModel(std::string filename, S32 lod); void loadModelCallback(S32 lod); void genLODs(S32 which_lod = -1); @@ -182,7 +183,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex std::set<LLPointer<LLViewerFetchedTexture> > mTextureSet; //map of vertex buffers to models (one vertex buffer in vector per face in model - std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[6]; + std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; }; class LLFloaterModelPreview : public LLFloater @@ -227,6 +228,7 @@ protected: friend class LLPhysicsDecomp; friend class LLPhysicsDecompFloater; + static void onDebugScaleCommit(LLUICtrl*, void*); static void onUploadJointsCommit(LLUICtrl*,void*); static void onUploadSkinCommit(LLUICtrl*,void*); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 508e1a9444..5347b7313e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2121,6 +2121,28 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh return NULL; } +const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) +{ + return mThread->getMeshHeader(mesh_id); +} + +const LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) +{ + static LLSD dummy_ret; + if (mesh_id.notNull()) + { + LLMutexLock lock(mHeaderMutex); + mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); + if (iter != mMeshHeader.end()) + { + return iter->second; + } + } + + return dummy_ret; +} + + void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints) { @@ -2493,6 +2515,50 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } +//static +F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) +{ + F32 dlowest = llmin(radius/0.06f, 256.f); + F32 dlow = llmin(radius/0.24f, 256.f); + F32 dmid = llmin(radius/1.0f, 256.f); + F32 dhigh = 0.f; + + + F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f; + F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f; + F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f; + F32 bytes_high = header["high_lod"]["size"].asReal()/1024.f; + + if (bytes_high == 0.f) + { + return 0.f; + } + + if (bytes_mid == 0.f) + { + bytes_mid = bytes_high; + } + + if (bytes_low == 0.f) + { + bytes_low = bytes_mid; + } + + if (bytes_lowest == 0.f) + { + bytes_lowest = bytes_low; + } + + F32 cost = 0.f; + cost += llmax(256.f-dlowest, 1.f)/32.f*bytes_lowest; + cost += llmax(dlowest-dlow, 1.f)/32.f*bytes_low; + cost += llmax(dlow-dmid, 1.f)/32.f*bytes_mid; + cost += llmax(dmid-dhigh, 1.f)/32.f*bytes_high; + + cost *= gSavedSettings.getF32("MeshStreamingCostScaler"); + return cost; +} + LLPhysicsDecomp::LLPhysicsDecomp() : LLThread("Physics Decomp") diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index f8d2a0590c..736d236e2e 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -300,6 +300,7 @@ public: bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size); bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size); + const LLSD& getMeshHeader(const LLUUID& mesh_id); void notifyLoadedMeshes(); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); @@ -385,6 +386,7 @@ public: static U32 sCacheBytesWritten; static U32 sPeakKbps; + static F32 getStreamingCost(const LLSD& header, F32 radius); LLMeshRepository(); @@ -405,6 +407,7 @@ public: U32 getResourceCost(const LLUUID& mesh_params); const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id); const LLMeshDecomposition* getDecomposition(const LLUUID& mesh_id); + const LLSD& getMeshHeader(const LLUUID& mesh_id); void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index d16685e088..57e04a43a2 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6230,6 +6230,40 @@ F32 LLObjectSelection::getSelectedObjectCost() return cost; } +F32 LLObjectSelection::getSelectedObjectStreamingCost() +{ + F32 cost = 0.f; + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + cost += object->getStreamingCost(); + } + } + + return cost; +} + +U32 LLObjectSelection::getSelectedObjectTriangleCount() +{ + U32 count = 0; + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + count += object->getTriangleCount(); + } + } + + return count; +} + F32 LLObjectSelection::getSelectedLinksetCost() { cleanupNodes(); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index fea619d48f..e598ffd47d 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -288,6 +288,8 @@ public: S32 getObjectCount(BOOL mesh_adjust = FALSE); F32 getSelectedObjectCost(); F32 getSelectedLinksetCost(); + F32 getSelectedObjectStreamingCost(); + U32 getSelectedObjectTriangleCount(); S32 getTECount(); S32 getRootObjectCount(); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index b21597349f..9b3f81e193 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2942,6 +2942,16 @@ F32 LLViewerObject::getObjectCost() return mObjectCost; } +F32 LLViewerObject::getStreamingCost() +{ + return 0.f; +} + +U32 LLViewerObject::getTriangleCount() +{ + return 0; +} + F32 LLViewerObject::getLinksetCost() { if (mCostStale) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index aec920b631..094f01ab3d 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -336,6 +336,9 @@ public: void setObjectCost(F32 cost); F32 getObjectCost(); + virtual F32 getStreamingCost(); + virtual U32 getTriangleCount(); + void setLinksetCost(F32 cost); F32 getLinksetCost(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 90b8e5e0f9..0aaf7f9c12 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -522,6 +522,14 @@ public: ypos += y_inc; + addText(xpos, ypos, llformat("Selection Streaming Cost: %.3f ", LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost())); + + ypos += y_inc; + + addText(xpos, ypos, llformat("Selection Triangle Count: %.3f Ktris ", LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount()/1000.f)); + + ypos += y_inc; + LLVertexBuffer::sBindCount = LLImageGL::sBindCount = LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 30bd981aa6..8eabe8ed90 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3207,6 +3207,45 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const } +F32 LLVOVolume::getStreamingCost() +{ + std::string header_lod[] = + { + "lowest_lod", + "low_lod", + "medium_lod", + "high_lod" + }; + + + if (isMesh()) + { + const LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID()); + + F32 radius = getRadius(); + + return LLMeshRepository::getStreamingCost(header, radius); + } + + + return 0.f; +} + +U32 LLVOVolume::getTriangleCount() +{ + U32 count = 0; + LLVolume* volume = getVolume(); + if (volume) + { + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + count += volume->getVolumeFace(i).mNumIndices/3; + } + } + + return count; +} + //static void LLVOVolume::preUpdateGeom() { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index f058710a27..a64c633ae4 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -136,7 +136,8 @@ public: /*virtual*/ const LLMatrix4 getRenderMatrix() const; typedef std::map<LLUUID, S32> texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; - + /*virtual*/ F32 getStreamingCost(); + /*virtual*/ U32 getTriangleCount(); /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index f505e99c02..e7c2a8bc6f 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -49,10 +49,13 @@ </text> <combo_box bottom_delta="0" left="97" follows="left|top" height="18" name="high detail combo" width="100" tool_tip="Specify mesh for this level of detail"> - <combo_item name="high choose file"> + <combo_item name="high none" value="none"> + None + </combo_item> + <combo_item name="high choose file" value="file"> Choose File... </combo_item> - <combo_item name="high triangle limit"> + <combo_item name="high triangle limit" value="limit"> Triangle Limit </combo_item> </combo_box> @@ -67,10 +70,13 @@ </text> <combo_box bottom_delta="0" left="97" follows="left|top" height="18" name="medium detail combo" width="100" tool_tip="Specify mesh for this level of detail"> - <combo_item name="medium choose file"> + <combo_item name="medium none" value="none"> + None + </combo_item> + <combo_item name="medium choose file" value="file"> Choose File... </combo_item> - <combo_item name="medium triangle limit"> + <combo_item name="medium triangle limit" value="limit"> Triangle Limit </combo_item> </combo_box> @@ -85,10 +91,13 @@ </text> <combo_box bottom_delta="0" left="97" follows="left|top" height="18" name="low detail combo" width="100" tool_tip="Specify mesh for this level of detail"> - <combo_item name="low choose file"> + <combo_item name="low none" value="none"> + None + </combo_item> + <combo_item name="low choose file" value="file"> Choose File... </combo_item> - <combo_item name="low triangle limit"> + <combo_item name="low triangle limit" value="limit"> Triangle Limit </combo_item> </combo_box> @@ -101,12 +110,15 @@ <text bottom_delta="35" follows="top|left" height="15" left="10" name="lowest_lod_label"> Lowest LOD: </text> - <combo_box bottom_delta="0" left="97" folimpostors="left|top" height="18" + <combo_box bottom_delta="0" left="97" follows="left|top" height="18" name="lowest detail combo" width="100" tool_tip="Specify mesh for this level of detail"> - <combo_item name="lowest choose file"> + <combo_item name="lowest none" value="none"> + None + </combo_item> + <combo_item name="lowest choose file" value="file"> Choose File... </combo_item> - <combo_item name="lowest triangle limit"> + <combo_item name="lowest triangle limit" value="limit"> Triangle Limit </combo_item> </combo_box> @@ -121,10 +133,13 @@ </text> <combo_box bottom_delta="0" left="97" follows="left|top" height="18" name="physics detail combo" width="100"> - <combo_item name="physics choose file"> + <combo_item name="physics none" value="none"> + None + </combo_item> + <combo_item name="physics choose file" value="file"> Choose File... </combo_item> - <combo_item name="physics triangle limit"> + <combo_item name="physics triangle limit" value="limit"> Triangle Limit... </combo_item> </combo_box> @@ -163,4 +178,12 @@ <text bottom_delta="20" left="15" follows="top|left" height="15" name="upload_message"> [MESSAGE] </text> - </floater> + <text bottom_delta="45" left="15" follows="top|left" height="15" name="debug section"> + DEBUG: + </text> + <text bottom_delta="20" left="15" follows="top|left" height="15" name="streaming cost"> + Streaming Cost: [COST] + </text> + <spinner bottom_delta="20" label="Scale" left="15" width="120" name="debug scale" decimal_digits="3" increment="1" min_val="0" max_val="64" initial_value="1" tool_tip="Scale to base streaming cost on."/> + +</floater> |