summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llrender/llvertexbuffer.h2
-rwxr-xr-xindra/newview/app_settings/settings.xml33
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl80
-rw-r--r--indra/newview/llfloatermodelpreview.cpp658
-rw-r--r--indra/newview/llfloatermodelpreview.h36
-rw-r--r--indra/newview/llmeshreduction.cpp15
-rw-r--r--indra/newview/pipeline.cpp63
-rw-r--r--indra/newview/skins/default/textures/textures.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_preview.xml260
-rw-r--r--indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml79
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml12
11 files changed, 845 insertions, 397 deletions
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 953b7e6757..f40f013306 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -198,7 +198,7 @@ public:
U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
U32 getTypeMask() const { return mTypeMask; }
- BOOL hasDataType(S32 type) const { return ((1 << type) & getTypeMask()) ? TRUE : FALSE; }
+ bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
S32 getSize() const;
S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
U8* getMappedData() const { return mMappedData; }
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a27492f1c0..0be94ce2d1 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1353,7 +1353,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>11.0</real>
+ <real>9.0</real>
</map>
<key>CameraFocalLength</key>
@@ -1365,21 +1365,32 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>35</real>
+ <real>50</real>
</map>
- <key>CameraCoCRatio</key>
+ <key>CameraFieldOfView</key>
<map>
<key>Comment</key>
- <string>Ratio of circle of confusion to vertical resolution for DoF effect.</string>
+ <string>Vertical camera field of view for DoF effect (in degrees)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>54</real>
+ <real>60.0</real>
</map>
+ <key>CameraAspectRatio</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera aspect ratio for DoF effect</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.5</real>
+ </map>
<key>CertStore</key>
<map>
@@ -6622,9 +6633,9 @@
<string>Vector3</string>
<key>Value</key>
<array>
- <real>-0.35</real>
+ <real>-0.75</real>
<real>1</real>
- <real>0.7</real>
+ <real>1.0</real>
</array>
</map>
@@ -6638,9 +6649,9 @@
<string>Vector3</string>
<key>Value</key>
<array>
- <real>-1</real>
- <real>-1</real>
+ <real>0.5</real>
<real>-0.6</real>
+ <real>0.4</real>
</array>
</map>
@@ -6654,9 +6665,9 @@
<string>Vector3</string>
<key>Value</key>
<array>
- <real>-0.2</real>
+ <real>0.5</real>
<real>-0.8</real>
- <real>-0.2</real>
+ <real>0.3</real>
</array>
</map>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
index 02712e0a5b..7c89c01ea4 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
@@ -17,8 +17,10 @@ uniform sampler2D bloomMap;
uniform float depth_cutoff;
uniform float norm_cutoff;
-uniform float near_focal_distance;
-uniform float far_focal_distance;
+uniform float focal_distance;
+uniform float blur_constant;
+uniform float tan_pixel_angle;
+uniform float magnification;
uniform mat4 inv_proj;
uniform vec2 screen_res;
@@ -39,11 +41,22 @@ void dofSample(inout vec4 diff, inout float w, float fd, float x, float y)
vec2 tc = vary_fragcoord.xy+vec2(x,y);
float d = getDepth(tc);
- if (d < fd)
+ float wg = 1.0;
+ //if (d < fd)
+ //{
+ // diff += texture2DRect(diffuseRect, tc);
+ // w = 1.0;
+ //}
+ if (d > fd)
{
- diff += texture2DRect(diffuseRect, tc);
- w += 1.0;
+ wg = max(d/fd, 0.1);
}
+
+ diff += texture2DRect(diffuseRect, tc+vec2(0.5,0.5))*wg*0.25;
+ diff += texture2DRect(diffuseRect, tc+vec2(-0.5,0.5))*wg*0.25;
+ diff += texture2DRect(diffuseRect, tc+vec2(0.5,-0.5))*wg*0.25;
+ diff += texture2DRect(diffuseRect, tc+vec2(-0.5,-0.5))*wg*0.25;
+ w += wg;
}
void dofSampleNear(inout vec4 diff, inout float w, float x, float y)
@@ -64,22 +77,30 @@ void main()
float sc = 0.75;
- float depth[5];
- depth[0] = getDepth(tc);
+ float depth;
+ depth = getDepth(tc);
vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
- if (depth[0] < far_focal_distance)
{ //pixel is behind far focal plane
float w = 1.0;
- float fd = (depth[0]-far_focal_distance)*0.5+far_focal_distance;
- float sc = far_focal_distance - depth[0];
- sc /= near_focal_distance-far_focal_distance;
+ sc = (abs(depth-focal_distance)/-depth)*blur_constant;
+
+ sc /= magnification;
+
+ // tan_pixel_angle = pixel_length/-depth;
+ float pixel_length = tan_pixel_angle*-focal_distance;
+
+ sc = sc/pixel_length;
+
+ //diff.r = sc;
- sc = sqrt(sc);
+ sc = min(abs(sc), 8.0);
- sc = min(sc, 8.0);
+ //sc = 4.0;
+
+ float fd = depth*0.5f;
while (sc > 1.0)
{
@@ -96,41 +117,10 @@ void main()
dofSample(diff,w, fd, sc2,0);
sc -= 0.5;
}
+
diff /= w;
}
- else
- {
- float fd = near_focal_distance;
- if (depth[0] > fd)
- { //pixel is in front of near focal plane
- //diff.r = 1.0;
- float w = 1.0;
- float sc = near_focal_distance-depth[0];
- sc /= near_focal_distance;
- sc *= 8.0;
- sc = min(sc, 8.0);
-
- fd = depth[0];
- while (sc > 1.0)
- {
- dofSampleNear(diff,w, sc,sc);
- dofSampleNear(diff,w, -sc,sc);
- dofSampleNear(diff,w, sc,-sc);
- dofSampleNear(diff,w, -sc,-sc);
-
- sc -= 0.5;
- float sc2 = sc*1.414;
- dofSampleNear(diff,w, 0,sc2);
- dofSampleNear(diff,w, 0,-sc2);
- dofSampleNear(diff,w, -sc2,0);
- dofSampleNear(diff,w, sc2,0);
- sc -= 0.5;
- }
- diff /= w;
- }
- }
-
vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res);
gl_FragColor = diff + bloom;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 0cfebdb399..e1a974ce13 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -67,7 +67,9 @@
#include "lleconomy.h"
#include "llfocusmgr.h"
#include "llfloaterperms.h"
+#include "lliconctrl.h"
#include "llmatrix4a.h"
+#include "llmenubutton.h"
#include "llmeshrepository.h"
#include "llsdutil_math.h"
#include "lltextbox.h"
@@ -80,17 +82,21 @@
#include "llvoavatarself.h"
#include "pipeline.h"
#include "lluictrlfactory.h"
+#include "llviewermenu.h"
#include "llviewermenufile.h"
#include "llviewerregion.h"
+#include "llviewertexturelist.h"
#include "llstring.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
+#include "lltoggleablemenu.h"
#include "llvfile.h"
#include "llvfs.h"
+
#include "glod/glod.h"
//static
@@ -133,7 +139,7 @@ std::string lod_vertices_name[NUM_LOD+1] =
"high_vertices",
"I went off the end of the lod_vertices_name array. Me so smart."
};
-
+
std::string lod_status_name[NUM_LOD+1] =
{
"lowest_status",
@@ -143,6 +149,23 @@ std::string lod_status_name[NUM_LOD+1] =
"I went off the end of the lod_status_name array. Me so smart."
};
+std::string lod_icon_name[NUM_LOD+1] =
+{
+ "status_icon_lowest",
+ "status_icon_low",
+ "status_icon_medium",
+ "status_icon_high",
+ "I went off the end of the lod_status_name array. Me so smart."
+};
+
+std::string lod_status_image[NUM_LOD+1] =
+{
+ "ModelImport_Status_Good",
+ "ModelImport_Status_Warning",
+ "ModelImport_Status_Error",
+ "I went off the end of the lod_status_image array. Me so smart."
+};
+
std::string lod_label_name[NUM_LOD+1] =
{
"lowest_label",
@@ -153,7 +176,6 @@ std::string lod_label_name[NUM_LOD+1] =
};
-
bool validate_face(const LLVolumeFace& face)
{
for (U32 i = 0; i < face.mNumIndices; ++i)
@@ -248,21 +270,28 @@ BOOL LLFloaterModelPreview::postBuild()
return FALSE;
}
+ setViewOption("show_textures", true);
+
childSetAction("lod_browse", onBrowseLOD, this);
- childSetCommitCallback("lod_triangle_limit", onTriangleLimitCommit, this);
childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this);
childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this);
- childSetCommitCallback("show edges", onShowEdgesCommit, this);
childSetCommitCallback("lod_generate", onAutoFillCommit, this);
+
+ childSetCommitCallback("lod_mode", onLODParamCommit, this);
+ childSetCommitCallback("lod_error_threshold", onLODParamCommit, this);
+ childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this);
+ childSetCommitCallback("build_operator", onLODParamCommit, this);
+ childSetCommitCallback("queue_mode", onLODParamCommit, this);
+ childSetCommitCallback("border_mode", onLODParamCommit, this);
+ childSetCommitCallback("share_tolerance", onLODParamCommit, this);
childSetTextArg("status", "[STATUS]", getString("status_idle"));
//childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount));
childSetAction("ok_btn", onUpload, this);
- childSetAction("consolidate", onConsolidate, this);
childSetAction("clear_materials", onClearMaterials, this);
childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this);
@@ -279,6 +308,17 @@ BOOL LLFloaterModelPreview::postBuild()
childDisable("upload_joints");
childDisable("ok_btn");
+ mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
+
+ mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2));
+ mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2));
+ mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2));
+
+
+
+ mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT);
+
initDecompControls();
LLView* preview_panel = getChild<LLView>("preview_panel");
@@ -340,21 +380,47 @@ LLFloaterModelPreview::~LLFloaterModelPreview()
}
}
-void LLFloaterModelPreview::loadModel(S32 lod)
+void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata)
{
- mModelPreview->mLoading = true;
-
- (new LLMeshFilePicker(mModelPreview, lod))->getFile();
+ mViewOption[userdata.asString()] = !mViewOption[userdata.asString()];
+ mModelPreview->refresh();
}
-void LLFloaterModelPreview::setLimit(S32 lod, S32 limit)
+bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata)
{
- if (limit != mModelPreview->mLimit[lod])
- {
- mModelPreview->mLimit[lod] = limit;
- mModelPreview->genLODs(lod);
- mModelPreview->setPreviewLOD(lod);
- }
+ return mViewOption[userdata.asString()];
+}
+
+bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata)
+{
+ return !mViewOptionDisabled[userdata.asString()];
+}
+
+void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled)
+{
+ mViewOptionDisabled[option] = !enabled;
+}
+
+void LLFloaterModelPreview::enableViewOption(const std::string& option)
+{
+ setViewOptionEnabled(option, true);
+}
+
+void LLFloaterModelPreview::disableViewOption(const std::string& option)
+{
+ setViewOptionEnabled(option, false);
+}
+
+void LLFloaterModelPreview::setViewOption(const std::string& option, bool value)
+{
+ mViewOption[option] = value;
+}
+
+void LLFloaterModelPreview::loadModel(S32 lod)
+{
+ mModelPreview->mLoading = true;
+
+ (new LLMeshFilePicker(this, lod))->getFile();
}
//static
@@ -420,30 +486,6 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata)
fp->mModelPreview->setPreviewLOD(which_mode);
}
-//static
-void LLFloaterModelPreview::setLimit(S32 lod, void* userdata)
-{
- LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
-
- if (!fp->mModelPreview)
- {
- return;
- }
-
- S32 limit = fp->childGetValue("lod_triangle_limit").asInteger();
-
-
- fp->setLimit(lod, limit);
-}
-
-//static
-void LLFloaterModelPreview::onTriangleLimitCommit(LLUICtrl* ctrl, void* userdata)
-{
- LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
-
- LLFloaterModelPreview::setLimit(fp->mModelPreview->mPreviewLOD, userdata);
-}
-
//static
void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata)
{
@@ -453,14 +495,6 @@ void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userda
}
//static
-void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata)
-{
- LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
-
- fp->mModelPreview->refresh();
-}
-
-//static
void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata)
{
LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance;
@@ -476,6 +510,15 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
fp->mModelPreview->genLODs();
}
+//static
+void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+ fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD);
+ fp->mModelPreview->updateStatusMessages();
+ fp->mModelPreview->refresh();
+}
+
//-----------------------------------------------------------------------------
// draw()
@@ -878,7 +921,6 @@ void LLFloaterModelPreview::initDecompControls()
childSetCommitCallback("physics_layer", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance);
childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this);
- childSetCommitCallback("show physics", LLFloaterModelPreview::refresh, this);
}
//-----------------------------------------------------------------------------
@@ -1971,13 +2013,15 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
mTextureName = 0;
mPreviewLOD = 0;
mModelLoader = NULL;
+ mMaxTriangleLimit = 0;
mDirty = false;
+ mGenLOD = false;
mLoading = false;
- for (U32 i = 0; i < LLModel::NUM_LODS; i++)
- {
- mLimit[i] = 0;
- }
+ mBuildShareTolerance = 0.f;
+ mBuildQueueMode = GLOD_QUEUE_GREEDY;
+ mBuildBorderMode = GLOD_BORDER_UNLOCK;
+ mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE;
mFMP = fmp;
@@ -2271,6 +2315,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod)
mVertexBuffer[LLModel::LOD_PHYSICS].clear();
rebuildUploadData();
refresh();
+ updateStatusMessages();
}
}
@@ -2319,16 +2364,20 @@ void LLModelPreview::loadModelCallback(S32 lod)
if (lod == LLModel::LOD_HIGH)
{ //save a copy of the highest LOD for automatic LOD manipulation
+ if (mBaseModel.empty())
+ { //first time we've loaded a model, auto-gen LoD
+ mGenLOD = true;
+ }
+
mBaseModel = mModel[lod];
mBaseScene = mScene[lod];
mVertexBuffer[5].clear();
- //mModel[lod] = NULL;
}
clearIncompatible(lod);
mDirty = true;
-
+
if (lod == LLModel::LOD_HIGH)
{
resetPreviewTarget();
@@ -2631,11 +2680,6 @@ void LLModelPreview::genLODs(S32 which_lod)
S32 limit = -1;
- if (which_lod != -1)
- {
- limit = mLimit[which_lod];
- }
-
U32 triangle_count = 0;
for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
@@ -2659,29 +2703,132 @@ void LLModelPreview::genLODs(S32 which_lod)
mPatch.clear();
}
+ U32 lod_mode = 0;
+
+ LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode");
+ if (iface)
+ {
+ lod_mode = iface->getFirstSelectedIndex();
+ }
+
+ F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal();
+
+ if (lod_mode == 0)
+ {
+ lod_mode = GLOD_TRIANGLE_BUDGET;
+ if (which_lod != -1)
+ {
+ limit = mFMP->childGetValue("lod_triangle_limit").asInteger();
+ }
+ }
+ else
+ {
+ lod_mode = GLOD_ERROR_THRESHOLD;
+ }
+
+ U32 build_operator = 0;
+
+ iface = mFMP->childGetSelectionInterface("build_operator");
+ if (iface)
+ {
+ build_operator = iface->getFirstSelectedIndex();
+ }
+
+ if (build_operator == 0)
+ {
+ build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE;
+ }
+ else
+ {
+ build_operator = GLOD_OPERATOR_EDGE_COLLAPSE;
+ }
+
+ U32 queue_mode;
+ iface = mFMP->childGetSelectionInterface("queue_mode");
+ if (iface)
+ {
+ queue_mode = iface->getFirstSelectedIndex();
+ }
+
+ if (queue_mode == 0)
+ {
+ queue_mode = GLOD_QUEUE_GREEDY;
+ }
+ else if (queue_mode == 1)
+ {
+ queue_mode = GLOD_QUEUE_LAZY;
+ }
+ else
+ {
+ queue_mode = GLOD_QUEUE_INDEPENDENT;
+ }
+
+ U32 border_mode = 0;
+
+ iface = mFMP->childGetSelectionInterface("border_mode");
+ if (iface)
+ {
+ border_mode = iface->getFirstSelectedIndex();
+ }
+
+ if (border_mode == 0)
+ {
+ border_mode = GLOD_BORDER_UNLOCK;
+ }
+ else
+ {
+ border_mode = GLOD_BORDER_LOCK;
+ }
+
+ bool object_dirty = false;
+ if (border_mode != mBuildBorderMode)
+ {
+ mBuildBorderMode = border_mode;
+ object_dirty = true;
+ }
+
+ if (queue_mode != mBuildQueueMode)
+ {
+ mBuildQueueMode = queue_mode;
+ object_dirty = true;
+ }
+
+ if (build_operator != mBuildOperator)
+ {
+ mBuildOperator = build_operator;
+ object_dirty = true;
+ }
+
+ F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal();
+ if (share_tolerance != mBuildShareTolerance)
+ {
+ mBuildShareTolerance = share_tolerance;
+ object_dirty = true;
+ }
+
for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
{ //build GLOD objects for each model in base model list
LLModel* mdl = *iter;
if (mGroup[mdl] == 0)
{
mGroup[mdl] = cur_name++;
+ }
+
+ if (mObject[mdl] == 0 || object_dirty)
+ {
+ if (mObject[mdl] != 0)
+ {
+ glodDeleteObject(mObject[mdl]);
+ }
+
mObject[mdl] = cur_name++;
glodNewGroup(mGroup[mdl]);
stop_gloderror();
- glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET);
- stop_gloderror();
-
- glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
- stop_gloderror();
-
- glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f);
- stop_gloderror();
-
glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE);
stop_gloderror();
-
+
if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty())
{ //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation
mVertexBuffer[5].clear();
@@ -2704,38 +2851,25 @@ void LLModelPreview::genLODs(S32 which_lod)
tri_count += num_indices/3;
stop_gloderror();
}
+
+ glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator);
+ stop_gloderror();
+
+ glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode);
+ stop_gloderror();
+
+ glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode);
+ stop_gloderror();
+
+ glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance);
+ stop_gloderror();
+
+ glodBuildObject(mObject[mdl]);
+ stop_gloderror();
//store what percentage of total model (in terms of triangle count) this model makes up
mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count;
-
- //build glodobject
- glodBuildObject(mObject[mdl]);
- if (stop_gloderror())
- {
- glodDeleteGroup(mGroup[mdl]);
- stop_gloderror();
- glodDeleteObject(mObject[mdl]);
- stop_gloderror();
-
- mGroup[mdl] = 0;
- mObject[mdl] = 0;
-
- if (which_lod == -1)
- {
- mModel[LLModel::LOD_HIGH] = mBaseModel;
- }
-
- return;
- }
-
- }
-
- //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();
+ }
}
@@ -2747,9 +2881,8 @@ void LLModelPreview::genLODs(S32 which_lod)
start = end = which_lod;
}
- LLSpinCtrl* lim = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit", TRUE);
- lim->setMaxValue(base_triangle_count);
-
+ mMaxTriangleLimit = base_triangle_count;
+
for (S32 lod = start; lod >= end; --lod)
{
if (which_lod == -1)
@@ -2783,9 +2916,21 @@ void LLModelPreview::genLODs(S32 which_lod)
target_count = 4;
}
- glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count);
+ glodGroupParameteri(mGroup[base], GLOD_ADAPT_MODE, lod_mode);
+ stop_gloderror();
+
+ glodGroupParameteri(mGroup[base], GLOD_ADAPT_MODE, lod_mode);
+ stop_gloderror();
+
+ glodGroupParameteri(mGroup[base], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
stop_gloderror();
+ glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count);
+ stop_gloderror();
+
+ glodGroupParameterf(mGroup[base], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold);
+ stop_gloderror();
+
glodAdaptGroup(mGroup[base]);
stop_gloderror();
@@ -2953,17 +3098,26 @@ void LLModelPreview::updateStatusMessages()
}
}
+ if (mMaxTriangleLimit == 0)
+ {
+ mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
+ }
+
+
mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
- std::string mesh_status_good = mFMP->getString("mesh_status_good");
- std::string mesh_status_bad = mFMP->getString("mesh_status_bad");
std::string mesh_status_na = mFMP->getString("mesh_status_na");
- std::string mesh_status_none = mFMP->getString("mesh_status_none");
+
+ S32 upload_status[LLModel::LOD_HIGH+1];
bool upload_ok = true;
-
+
for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
{
+ upload_status[lod] = 0;
+
+ std::string message = "mesh_status_good";
+
if (total_tris[lod] > 0)
{
mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod]));
@@ -2971,26 +3125,40 @@ void LLModelPreview::updateStatusMessages()
}
else
{
+ if (lod == LLModel::LOD_HIGH)
+ {
+ upload_status[lod] = 2;
+ message = "mesh_status_missing_lod";
+ }
+ else
+ {
+ for (S32 i = lod-1; i >= 0; --i)
+ {
+ if (total_tris[i] > 0)
+ {
+ upload_status[lod] = 2;
+ message = "mesh_status_missing_lod";
+ }
+ }
+ }
+
mFMP->childSetText(lod_triangles_name[lod], mesh_status_na);
mFMP->childSetText(lod_vertices_name[lod], mesh_status_na);
}
-
- std::string message = mesh_status_good;
-
const U32 lod_high = LLModel::LOD_HIGH;
if (lod != lod_high)
{
if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
{ //number of submeshes is different
- message = mesh_status_bad;
- upload_ok = false;
+ message = "mesh_status_submesh_mismatch";
+ upload_status[lod] = 2;
}
else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())
{ //number of meshes is different
- message = mesh_status_bad;
- upload_ok = false;
+ message = "mesh_status_mesh_mismatch";
+ upload_status[lod] = 2;
}
else if (!verts[lod].empty())
{
@@ -2998,20 +3166,34 @@ void LLModelPreview::updateStatusMessages()
{
S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0;
- if (verts[lod][i] > max_verts)
- { //too many vertices in this lod
- message = mesh_status_bad;
- upload_ok = false;
+ if (max_verts > 0)
+ {
+ if (verts[lod][i] > max_verts)
+ { //too many vertices in this lod
+ message = "mesh_status_too_many_vertices";
+ upload_status[lod] = 2;
+ }
}
}
}
- else
- { //no mesh
- message = mesh_status_none;
- }
}
- mFMP->childSetText(lod_status_name[lod], message);
+ LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]);
+ LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]);
+ icon->setVisible(true);
+ icon->setImage(img);
+
+ if (upload_status[lod] >= 2)
+ {
+ upload_ok = false;
+ }
+
+ if (lod == mPreviewLOD)
+ {
+ mFMP->childSetText("lod_status_message_text", mFMP->getString(message));
+ icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon");
+ icon->setImage(img);
+ }
}
bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false;
@@ -3086,20 +3268,121 @@ void LLModelPreview::updateStatusMessages()
mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na);
}
+ if (phys_tris > 0 || phys_hulls > 0)
+ {
+ if (!mFMP->isViewOptionEnabled("show_physics"))
+ {
+ mFMP->enableViewOption("show_physics");
+ mFMP->setViewOption("show_physics", true);
+ }
+ }
+ else
+ {
+ mFMP->disableViewOption("show_physics");
+ mFMP->setViewOption("show_physics", false);
+ }
+
+ const char* lod_controls[] =
+ {
+ "lod_mode",
+ "lod_triangle_limit",
+ "lod_error_tolerance",
+ "build_operator_text",
+ "queue_mode_text",
+ "border_mode_text",
+ "share_tolerance_text",
+ "build_operator",
+ "queue_mode",
+ "border_mode",
+ "share_tolerance"
+ };
+ const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*);
+
+ const char* file_controls[] =
+ {
+ "lod_browse",
+ "lod_file"
+ };
+ const U32 num_file_controls = sizeof(file_controls)/sizeof(char*);
+
//enable/disable controls based on radio groups
if (mFMP->childGetValue("lod_from_file").asBoolean())
{
- mFMP->childDisable("lod_triangle_limit");
- mFMP->childDisable("lod_generate");
- mFMP->childEnable("lod_file");
- mFMP->childEnable("lod_browse");
+ for (U32 i = 0; i < num_file_controls; ++i)
+ {
+ mFMP->childEnable(file_controls[i]);
+ }
+
+ for (U32 i = 0; i < num_lod_controls; ++i)
+ {
+ mFMP->childDisable(lod_controls[i]);
+ }
+
+
}
- else
+ else if (mFMP->childGetValue("lod_auto_generate").asBoolean())
{
- mFMP->childEnable("lod_triangle_limit");
- mFMP->childEnable("lod_generate");
- mFMP->childDisable("lod_file");
- mFMP->childDisable("lod_browse");
+ for (U32 i = 0; i < num_file_controls; ++i)
+ {
+ mFMP->childDisable(file_controls[i]);
+ }
+
+ for (U32 i = 0; i < num_lod_controls; ++i)
+ {
+ mFMP->childEnable(lod_controls[i]);
+ }
+
+ //if (threshold)
+ {
+ U32 lod_mode = 0;
+ LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode");
+ if (iface)
+ {
+ lod_mode = iface->getFirstSelectedIndex();
+ }
+
+ LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold");
+ LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit");
+
+ limit->setMaxValue(mMaxTriangleLimit);
+ limit->setValue(total_tris[mPreviewLOD]);
+
+ if (lod_mode == 0)
+ {
+ limit->setVisible(true);
+ threshold->setVisible(false);
+
+ limit->setMaxValue(mMaxTriangleLimit);
+ }
+ else
+ {
+ limit->setVisible(false);
+ threshold->setVisible(true);
+ }
+ }
+ }
+ else
+ { // "None" is chosen
+ for (U32 i = 0; i < num_file_controls; ++i)
+ {
+ mFMP->childDisable(file_controls[i]);
+ }
+
+ for (U32 i = 0; i < num_lod_controls; ++i)
+ {
+ mFMP->childDisable(lod_controls[i]);
+ }
+
+ if (!mModel[mPreviewLOD].empty())
+ {
+ mModel[mPreviewLOD].clear();
+ mScene[mPreviewLOD].clear();
+ mVertexBuffer[mPreviewLOD].clear();
+
+ //this can cause phasing issues with the UI, so reenter this function and return
+ updateStatusMessages();
+ return;
+ }
}
if (mFMP->childGetValue("physics_load_from_file").asBoolean())
@@ -3133,7 +3416,7 @@ void LLModelPreview::clearBuffers()
}
}
-void LLModelPreview::genBuffers(S32 lod, bool avatar_preview)
+void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
{
U32 tri_count = 0;
U32 vertex_count = 0;
@@ -3184,7 +3467,7 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview)
LLVertexBuffer* vb = NULL;
- bool skinned = avatar_preview && !mdl->mSkinWeights.empty();
+ bool skinned = include_skin_weights && !mdl->mSkinWeights.empty();
U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
@@ -3266,7 +3549,17 @@ void LLModelPreview::update()
mDirty = false;
mResourceCost = calcResourceCost();
refresh();
+ updateStatusMessages();
}
+
+ if (mGenLOD)
+ {
+ mGenLOD = false;
+ genLODs();
+ refresh();
+ updateStatusMessages();
+ }
+
}
//-----------------------------------------------------------------------------
@@ -3277,6 +3570,12 @@ BOOL LLModelPreview::render()
LLMutexLock lock(this);
mNeedsUpdate = FALSE;
+ bool edges = mFMP->isViewOptionChecked("show_edges");
+ bool joint_positions = mFMP->isViewOptionChecked("show_joint_positions");
+ bool skin_weight = mFMP->isViewOptionChecked("show_skin_weight");
+ bool textures = mFMP->isViewOptionChecked("show_textures");
+ bool physics = mFMP->isViewOptionChecked("show_physics");
+
S32 width = getWidth();
S32 height = getHeight();
@@ -3308,7 +3607,7 @@ BOOL LLModelPreview::render()
gGL.popMatrix();
}
- bool avatar_preview = false;
+ bool has_skin_weights = false;
bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean();
bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean();
@@ -3320,45 +3619,39 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mModel;
if (!model->mSkinWeights.empty())
{
- avatar_preview = true;
+ has_skin_weights = true;
}
}
}
-
- if (upload_skin && !avatar_preview)
+
+ if (has_skin_weights)
+ { //model has skin weights, enable view options for skin weights and joint positions
+ mFMP->enableViewOption("show_skin_weight");
+ mFMP->setViewOptionEnabled("show_joint_positions", skin_weight);
+ mFMP->childEnable("upload_skin");
+ }
+ else
{
+ mFMP->childDisable("upload_skin");
+ mFMP->setViewOption("show_skin_weight", false);
+ mFMP->disableViewOption("show_skin_weight");
+ mFMP->disableViewOption("show_joint_positions");
+ skin_weight = false;
+ }
+
+ if (upload_skin && !has_skin_weights)
+ { //can't upload skin weights if model has no skin weights
mFMP->childSetValue("upload_skin", false);
upload_skin = false;
}
if (!upload_skin && upload_joints)
- {
+ { //can't upload joints if not uploading skin weights
mFMP->childSetValue("upload_joints", false);
upload_joints = false;
}
- if (!avatar_preview)
- {
- mFMP->childDisable("upload_skin");
- }
- else
- {
- mFMP->childEnable("upload_skin");
- }
-
- if (!upload_skin)
- {
- mFMP->childDisable("upload_joints");
- }
- else
- {
- mFMP->childEnable("upload_joints");
- }
-
- avatar_preview = avatar_preview && upload_skin;
-
-
- mFMP->childSetEnabled("consolidate", !avatar_preview);
+ mFMP->childSetEnabled("upload_joints", upload_skin);
F32 explode = mFMP->childGetValue("physics_explode").asReal();
@@ -3373,7 +3666,7 @@ BOOL LLModelPreview::render()
F32 z_near = 0.001f;
F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec();
- if (avatar_preview)
+ if (skin_weight)
{
target_pos = gAgentAvatarp->getPositionAgent();
z_near = 0.01f;
@@ -3384,6 +3677,7 @@ BOOL LLModelPreview::render()
refresh();
}
+ glLoadIdentity();
gPipeline.enableLightsPreview();
LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) *
@@ -3408,22 +3702,32 @@ BOOL LLModelPreview::render()
if (!mBaseModel.empty() && mVertexBuffer[5].empty())
{
- genBuffers(-1, avatar_preview);
+ genBuffers(-1, skin_weight);
//genBuffers(3);
//genLODs();
}
- bool physics = mFMP->childGetValue("show physics").asBoolean();
S32 physics_idx = mFMP->childGetValue("physics_layer").asInteger();
if (!mModel[mPreviewLOD].empty())
{
- if (mVertexBuffer[mPreviewLOD].empty())
+ bool regen = mVertexBuffer[mPreviewLOD].empty();
+ if (!regen)
+ {
+ const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second;
+ if (!vb_vec.empty())
+ {
+ const LLVertexBuffer* buff = vb_vec[0];
+ regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight;
+ }
+ }
+
+ if (regen)
{
- genBuffers(mPreviewLOD, avatar_preview);
+ genBuffers(mPreviewLOD, skin_weight);
}
- if (!avatar_preview)
+ if (!skin_weight)
{
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
@@ -3461,7 +3765,7 @@ BOOL LLModelPreview::render()
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
glColor3f(0.4f, 0.4f, 0.4f);
- if (mFMP->childGetValue("show edges").asBoolean())
+ if (edges)
{
glLineWidth(3.f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -3542,7 +3846,7 @@ BOOL LLModelPreview::render()
glColor4ubv(hull_colors[i].mV);
buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
- if (mFMP->childGetValue("show edges").asBoolean())
+ if (edges)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glLineWidth(3.f);
@@ -3587,7 +3891,7 @@ BOOL LLModelPreview::render()
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
glColor3f(0.4f, 0.4f, 0.4f);
- if (mFMP->childGetValue("show edges").asBoolean() || model == physics_model)
+ if (edges || model == physics_model)
{
if (model == physics_model)
{
@@ -3619,7 +3923,10 @@ BOOL LLModelPreview::render()
LLVector3::z_axis, // up
target_pos); // point of interest
- avatar->renderCollisionVolumes();
+ if (joint_positions)
+ {
+ avatar->renderCollisionVolumes();
+ }
for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
{
@@ -3704,7 +4011,7 @@ BOOL LLModelPreview::render()
buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
glColor3f(0.4f, 0.4f, 0.4f);
- if (mFMP->childGetValue("show edges").asBoolean())
+ if (edges)
{
glLineWidth(3.f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -3785,6 +4092,7 @@ void LLModelPreview::setPreviewLOD(S32 lod)
}
}
refresh();
+ updateStatusMessages();
}
//static
@@ -3807,12 +4115,6 @@ void LLFloaterModelPreview::onUpload(void* user_data)
mp->closeFloater(false);
}
-//static
-void LLFloaterModelPreview::onConsolidate(void* user_data)
-{
- LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
- mp->mModelPreview->consolidate();
-}
//static
void LLFloaterModelPreview::onClearMaterials(void* user_data)
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index b0317e3d2d..d6cc9ccec6 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -49,6 +49,8 @@ class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
+class LLMenuButton;
+class LLToggleableMenu;
class LLModelLoader : public LLThread
{
@@ -146,7 +148,6 @@ public:
static void onUpload(void* data);
- static void onConsolidate(void* data);
static void onClearMaterials(void* data);
static void onModelDecompositionComplete(LLModel* model, std::vector<LLPointer<LLVertexBuffer> >& physics_mesh);
@@ -156,6 +157,14 @@ public:
void loadModel(S32 lod);
+ void onViewOptionChecked(const LLSD& userdata);
+ bool isViewOptionChecked(const LLSD& userdata);
+ bool isViewOptionEnabled(const LLSD& userdata);
+ void setViewOptionEnabled(const std::string& option, bool enabled);
+ void enableViewOption(const std::string& option);
+ void disableViewOption(const std::string& option);
+ void setViewOption(const std::string& option, bool value);
+
protected:
friend class LLModelPreview;
friend class LLMeshFilePicker;
@@ -167,12 +176,10 @@ protected:
static void onPreviewLODCommit(LLUICtrl*,void*);
- static void onTriangleLimitCommit(LLUICtrl*,void*);
-
static void onGenerateNormalsCommit(LLUICtrl*,void*);
static void onAutoFillCommit(LLUICtrl*,void*);
- static void onShowEdgesCommit(LLUICtrl*,void*);
+ static void onLODParamCommit(LLUICtrl*,void*);
static void onExplodeCommit(LLUICtrl*, void*);
@@ -190,9 +197,6 @@ protected:
void draw();
- static void setLimit(S32 lod, void* userdata);
- void setLimit(S32 lod, S32 limit);
-
void initDecompControls();
LLModelPreview* mModelPreview;
@@ -207,6 +211,13 @@ protected:
LLPointer<DecompRequest> mCurRequest;
+ std::map<std::string, bool> mViewOption;
+
+ //use "disabled" as false by default
+ std::map<std::string, bool> mViewOptionDisabled;
+
+ LLMenuButton* mViewOptionMenuButton;
+ LLToggleableMenu* mViewOptionMenu;
};
@@ -271,6 +282,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
BOOL mNeedsUpdate;
bool mDirty;
+ bool mGenLOD;
U32 mTextureName;
F32 mCameraDistance;
F32 mCameraYaw;
@@ -281,11 +293,17 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
LLVector3 mPreviewScale;
S32 mPreviewLOD;
U32 mResourceCost;
- S32 mLimit[LLModel::NUM_LODS];
std::string mLODFile[LLModel::NUM_LODS];
F32 mAspect;
bool mLoading;
+ //GLOD object parameters (must rebuild object if these change)
+ F32 mBuildShareTolerance;
+ U32 mBuildQueueMode;
+ U32 mBuildOperator;
+ U32 mBuildBorderMode;
+
+
LLModelLoader* mModelLoader;
@@ -299,7 +317,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
std::map<LLPointer<LLModel>, U32> mObject;
std::map<LLPointer<LLModel>, std::vector<U32> > mPatch;
std::map<LLPointer<LLModel>, F32> mPercentage;
-
+ U32 mMaxTriangleLimit;
std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > > mPhysicsMesh;
LLMeshUploadThread::instance_list mUploadData;
diff --git a/indra/newview/llmeshreduction.cpp b/indra/newview/llmeshreduction.cpp
index b50b4cf063..14e8dd37b4 100644
--- a/indra/newview/llmeshreduction.cpp
+++ b/indra/newview/llmeshreduction.cpp
@@ -32,19 +32,8 @@
#include "glod/glod.h"
-static BOOL stop_gloderror()
-{
- GLuint error = glodGetError();
-
- if (error != GLOD_NO_ERROR)
- {
- llwarns << "GLOD error detected: " << std::hex << error << llendl;
- return TRUE;
- }
-
- return FALSE;
-}
+#if 0 //not used ?
void create_vertex_buffers_from_model(LLModel* model, std::vector<LLPointer <LLVertexBuffer> >& vertex_buffers)
{
@@ -280,4 +269,4 @@ LLPointer<LLModel> LLMeshReduction::reduce(LLModel* in_model, F32 limit, S32 mod
return out_model;
}
-
+#endif
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index f0446b024c..64c24750b7 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -6160,44 +6160,49 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
//convert to mm
subject_distance *= 1000.f;
F32 fnumber = gSavedSettings.getF32("CameraFNumber");
- F32 focal_length = gSavedSettings.getF32("CameraFocalLength");
- F32 coc_ratio = gSavedSettings.getF32("CameraCoCRatio");
-
- F32 coc = coc_ratio/mScreen.getHeight();
-
- F32 hyperfocal_distance = (focal_length*focal_length)/(fnumber*coc);
-
- subject_distance = llmin(hyperfocal_distance, subject_distance);
-
- //adjust focal length for subject distance
- focal_length = llmax(focal_length, 1.f/(1.f/focal_length - 1.f/subject_distance));
-
- //adjust focal length for zoom
+ const F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength");
+
F32 fov = LLViewerCamera::getInstance()->getView();
- focal_length *= 1.f/fov;
-
- F32 near_focal_distance = hyperfocal_distance*subject_distance/(hyperfocal_distance+subject_distance);
- //beyond far clip plane is effectively infinity
- F32 far_focal_distance = 4096.f;
-
- if (subject_distance < hyperfocal_distance)
- {
- far_focal_distance = hyperfocal_distance*subject_distance/(hyperfocal_distance-subject_distance);
- far_focal_distance /= 1000.f;
- }
-
- near_focal_distance /= 1000.f;
+ const F32 default_fov = gSavedSettings.getF32("CameraFieldOfView") * F_PI/180.f;
+ const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio");
+
+ F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight();
+
+ F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f);
+ F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f);
- shader->uniform1f("far_focal_distance", -far_focal_distance);
- shader->uniform1f("near_focal_distance", -near_focal_distance);
+ F32 focal_length = dv/(2*tanf(fov/2.f));
+
+ F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
+
+ // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
+ // where N = fnumber
+ // s2 = dot distance
+ // s1 = subject distance
+ // f = focal length
+ //
+
+ F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length));
+ blur_constant /= 1000.f; //convert to meters for shader
+ F32 magnification = focal_length/(subject_distance-focal_length);
+
+ shader->uniform1f("focal_distance", -subject_distance/1000.f);
+ shader->uniform1f("blur_constant", blur_constant);
+ shader->uniform1f("tan_pixel_angle", tanf(1.f/LLDrawable::sCurPixelAngle));
+ shader->uniform1f("magnification", magnification);
S32 channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
if (channel > -1)
{
mScreen.bindTexture(0, channel);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
}
+ //channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+ //if (channel > -1)
+ //{
+ //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ //}
gGL.begin(LLRender::TRIANGLE_STRIP);
gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index b8030bfa91..e522159181 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -256,6 +256,10 @@ with the same filename but different name
<texture name="menu_separator" file_name="navbar/FileMenu_Divider.png" scale.left="4" scale.top="166" scale.right="0" scale.bottom="0" />
+ <texture name="ModelImport_Status_Good" file_name="lag_status_good.tga" preload="false"/>
+ <texture name="ModelImport_Status_Warning" file_name="lag_status_warning.tga" preload="false"/>
+ <texture name="ModelImport_Status_Error" file_name="lag_status_critical.tga" preload="false"/>
+
<texture name="MouseLook_View_Off" file_name="bottomtray/MouseLook_view_off.png" preload="false" />
<texture name="MouseLook_View_On" file_name="bottomtray/MouseLook_view_on.png" preload="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 c17c52bb09..952deb26f9 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater can_close="true" can_drag_on_left="false" can_minimize="false"
- can_resize="true" height="520" min_height="520" min_width="630"
- name="Model Preview" title="Upload Model" width="630">
+ can_resize="true" height="550" min_height="550" min_width="620"
+ name="Model Preview" title="Upload Model" width="620">
<string name="status_idle">Idle</string>
<string name="status_reading_file">Loading...</string>
@@ -10,103 +10,89 @@
<string name="medium">Medium</string>
<string name="low">Low</string>
<string name="lowest">Lowest</string>
- <string name="mesh_status_good">Good</string>
- <string name="mesh_status_bad">Bad</string>"
+ <string name="mesh_status_good">Ship it!</string>
<string name="mesh_status_na">N/A</string>
<string name="mesh_status_none">None</string>
+ <string name="mesh_status_submesh_mismatch">Levels of detail have a different number of textureable faces.</string>
+ <string name="mesh_status_mesh_mismatch">Levels of detail have a different number of mesh instances.</string>
+ <string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
+ <string name="mesh_status_missing_lod">Missing required level of detail.</string>
<string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
<text left="15" bottom="25" follows="top|left" height="15" name="name_label">
Name:
</text>
- <line_editor bottom_delta="20" follows="top|left|right" height="19" max_length="254"
- name="description_form" width="310" />
- <text bottom_delta="24" follows="top|left" height="15" name="preview_label">
+ <line_editor bottom_delta="20" follows="top|left|right" height="19"
+ name="description_form" width="290" />
+
+ <text bottom_delta="20" left="15" follows="left|top" height="15" name="lod_label">
Preview:
</text>
+ <combo_box bottom_delta="20" follows="left|top" height="18"
+ name="preview_lod_combo" width="240" tool_tip="LOD to view in preview render">
+ <combo_item name="lowest">
+ Level of Detail: Lowest
+ </combo_item>
+ <combo_item name="low">
+ Level of Detail: Low
+ </combo_item>
+ <combo_item name="medium">
+ Level of Detail: Medium
+ </combo_item>
+ <combo_item name="high">
+ Level of Detail: High
+ </combo_item>
+ </combo_box>
+ <menu_button follows="top|left"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left_pad="5"
+ name="options_gear_btn"
+ width="31"
+ height="25"/>
<!-- Placeholder panel for 3D preview render -->
<panel
name="preview_panel"
left="15"
- width="310"
- height="310"
+ width="290"
+ height="290"
follows="all"/>
- <text bottom_delta="25" left="15" width="100" follows="bottom|left" height="15" name="streaming cost">
- Prim Cost: [COST]
- </text>
+ <text bottom_delta="25" left="25" width="100" follows="bottom|left">Upload Details</text>
+ <panel top_pad="5" border="true" left="15" width="290" height="70" follows="bottom|left"
+ bevel_style="in" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
+ <text left="25" follows="bottom|left" width="140" height="15" name="streaming cost">
+ Resource Cost: [COST]
+ </text>
+ <text left="25" top_pad="5" width="140" follows="bottom|left" height="15" name="physics cost">
+ Physics Cost: Unknown
+ </text>
+ <text left="25" top_pad="5" follows="bottom|left" height="15" name="upload fee">
+ Upload Fee: N/A
+ </text>
+ </panel>
+
+ <text left="10" bottom="540" width="290" height="15" follows="bottom|left|right" name="status">[STATUS]</text>
- <text right="320" width="100" height="15" bottom_delta="0" follows="bottom|right" name="status">[STATUS]</text>
-
- <text bottom_delta="20" left="15" follows="left|bottom" height="15" name="lod_label">
- Level of Detail:
- </text>
- <combo_box bottom_delta="20" follows="left|bottom" list_position="below" height="18"
- name="preview_lod_combo" width="90" tool_tip="LOD to view in preview render">
- <combo_item name="high">
- High
- </combo_item>
- <combo_item name="medium">
- Medium
- </combo_item>
- <combo_item name="lowest">
- Lowest
- </combo_item>
- <combo_item name="low">
- Low
- </combo_item>
- </combo_box>
-
- <check_box bottom="450" left="125" follows="left|bottom" label="Show Edges" name="show edges" width="120" height="16" tool_tip="Render wireframe in preview window"/>
- <check_box bottom_delta="15" left="125" follows="left|bottom" label="Show Physics" name="show physics" width="120" height="16" tool_tip="Show physics shape."/>
-
- <button bottom="510" follows="bottom|left" height="20" label="Upload"
- left="15" width="80" name="ok_btn" tool_tip="Upload to simulator"/>
- <button left_pad="10" follows="left|bottom" height="20" width="80" label="Cancel" name="cancel_btn"/>
+
+ <button bottom="540" left="430" follows="bottom|right" height="20" label="Upload"
+ width="80" name="ok_btn" tool_tip="Upload to simulator"/>
+ <button left_pad="10" follows="right|bottom" height="20" width="80" label="Cancel" name="cancel_btn"/>
<tab_container
follows="right|top|bottom"
top="15"
- left="330"
- height="475"
- width="280"
+ left="310"
+ height="470"
+ width="300"
name="import_tab"
border="true"
tab_position="top">
- <!-- MODIFIERS PANEL -->
- <panel
- border="true"
- label="Modifiers"
- name="modifiers_panel"
- left="330"
- width="280"
- height="450">
-
- <text left="10" width="90" bottom="30" follows="top|left" height="15">
- Scale:
- </text>
- <text left_pad="5" width="140" follows="top|left" height="15">
- Dimensions:
- </text>
-
- <spinner left="10" height="20" follows="top|left" width="80" top_pad="5" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/>
-
- <text left_pad="20" height="15" name="import_dimensions" follows="top|left">
- [X] x [Y] x [Z] m
- </text>
-
- <text left="10" top_pad="20" follows="top_left" height="15">
- Include:
- </text>
-
- <check_box top_pad="5" name="upload_textures" height="15" follows="top|left" label="Textures"/>
- <check_box top_pad="5" name="upload_skin" height="15" follows="top|left" label="Skin weight"/>
- <check_box top_pad="5" left="20" name="upload_joints" height="15" follows="top|left" label="Joint positions"/>
- </panel>
-
-
<!-- LOD PANEL -->
<panel
border="true"
@@ -124,60 +110,110 @@
<text valign="center" halign="center" bg_visible="true" name="high_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="High"/>
<text valign="center" halign="center" bg_visible="true" name="high_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
<text valign="center" halign="center" bg_visible="true" name="high_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
- <text valign="center" halign="center" bg_visible="true" name="high_status" left_pad="0" width="65" height="18" follows="left|top" value="Good"/>
+ <text valign="center" halign="center" bg_visible="true" name="high_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_high" left_delta="20" top_delta="0" />
<text valign="center" halign="center" bg_visible="true" name="medium_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="Medium"/>
<text valign="center" halign="center" bg_visible="true" name="medium_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
<text valign="center" halign="center" bg_visible="true" name="medium_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
- <text valign="center" halign="center" bg_visible="true" name="medium_status" left_pad="0" width="65" height="18" follows="left|top" value="Good"/>
+ <text valign="center" halign="center" bg_visible="true" name="medium_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_medium" left_delta="20" top_delta="0" />
<text valign="center" halign="center" bg_visible="true" name="low_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="Low"/>
<text valign="center" halign="center" bg_visible="true" name="low_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
<text valign="center" halign="center" bg_visible="true" name="low_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
- <text valign="center" halign="center" bg_visible="true" name="low_status" left_pad="0" width="65" height="18" follows="left|top" value="Good"/>
+ <text valign="center" halign="center" bg_visible="true" name="low_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_low" left_delta="20" top_delta="0" />
<text valign="center" halign="center" bg_visible="true" name="lowest_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="Lowest"/>
<text valign="center" halign="center" bg_visible="true" name="lowest_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
<text valign="center" halign="center" bg_visible="true" name="lowest_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
- <text valign="center" halign="center" bg_visible="true" name="lowest_status" left_pad="0" width="65" height="18" follows="left|top" value="Good"/>
-
- <text left="10" width="240" height="15" top_pad="15" follows="left|top" name="lod_tabel_footer">
+ <text valign="center" halign="center" bg_visible="true" name="lowest_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_lowest" left_delta="20" top_delta="0" />
+
+ <text left="10" width="240" height="15" top_pad="15" follows="left|top" name="lod_table_footer">
Level of Detail: [DETAIL]
</text>
- <text top_pad="10" height="15" follows="left|top">
+ <icon height="16" width="16" left="20" follows="left|top" name="lod_status_message_icon"/>
+ <text left_pad="5" width="200" height="15" follows="left|top" name="lod_status_message_text"/>
+
+ <text top_pad="10" left="10" height="15" follows="left|top">
Mesh
</text>
- <radio_group follows="top|left" height="100" left="30" name="lod_file_or_limit" width="240" value="lod_from_file">
- <radio_item bottom="85" label="Load from file" name="lod_from_file"/>
- <radio_item bottom="40" label="Auto generate" name="lod_auuto_generate"/>
+ <radio_group follows="top|left" height="210" left="30" name="lod_file_or_limit" width="240" value="lod_from_file">
+ <radio_item bottom="195" label="Load from file" name="lod_from_file"/>
+ <radio_item bottom="150" label="Auto generate" name="lod_auto_generate"/>
+ <radio_item bottom="0" label="None" name="lod_none"/>
</radio_group>
- <line_editor follows="left|top" bottom_delta="-60" width="140" left="45" value="" name="lod_file" height="20"/>
+ <line_editor follows="left|top" bottom_delta="-170" width="140" left="45" value="" name="lod_file" height="20"/>
<button bottom_delta="3" name="lod_browse" label="Browse..." left_pad="5" follows="left|top" width="70" height="25"/>
- <text follows="top|left" top_pad="22" width="140" left="45" height="15">
- Triangle Limit:
+ <combo_box follows="top|left" name="lod_mode" top_pad="22" width="100" left="45" height="20">
+ <combo_item name="triangle_limit">
+ Triangle Limit
+ </combo_item>
+ <combo_item name="error_threshold">
+ Error Threshold
+ </combo_item>
+ </combo_box>
+ <spinner follows="top|left" name="lod_triangle_limit" left_pad="5" height="20" width="100" decimal_digits="0" enabled="true"/>
+ <spinner left_delta="0" bottom_delta="0" follows="top|left" name="lod_error_threshold" min_val="0" max_val="100" height="20" width="100" decimal_digits="3" visible="false" enabled="true"/>
+
+ <text follows="top|left" name="build_operator_text" left="45" top_pad="10" width="100" height="15">
+ Build Operator:
+ </text>
+ <text follows="top|left" name="queue_mode_text" left_pad="5" width="100" height="15">
+ Queue Mode:
+ </text>
+ <combo_box follows="top|left" name="build_operator" top_pad="5" left="45" width="100" height="20">
+ <combo_item name="half_edge_collapse">
+ Half Edge Collapse
+ </combo_item>
+ <combo_item name="edge_collapse">
+ Edge Collapse
+ </combo_item>
+ </combo_box>
+
+ <combo_box follows="top|left" name="queue_mode" left_pad="5" width="100" height="20">
+ <combo_item name="greedy">
+ Greedy
+ </combo_item>
+ <combo_item name="lazy">
+ Lazy
+ </combo_item>
+ <combo_item name="independent">
+ Independent
+ </combo_item>
+ </combo_box>
+
+ <text top_pad="10" name="border_mode_text" left="45" follows="left|top" width="100" height="15">
+ Border Mode:
</text>
- <spinner follows="top|left" name="lod_triangle_limit" top_pad="5" height="20" width="60" decimal_digits="0" enabled="true"/>
-
- <button bottom_delta="3" left_pad="5" name="lod_generate" label="Generate" height="25" width="70" follows="left|top"/>
- <text name="submeshes_info" follows="left|top" left="10" top_pad="7" height="15 width=240">
- Layers: [SUBMESHES]
+ <text left_pad="5" name="share_tolderance_text" follows="left|top" width="100" height="15">
+ Share Tolerance:
</text>
- <button left="30" follows="top|left" top_pad="5" name="clear_materials" label="Clear Materials" width="100" height="25"/>
- <button left="30" follows="top|left" top_pad="5" name="consolidate" label="Consolidate" width="100" height="25"/>
- <text left="10" top_pad="10" follows="top|left" width="240" height="15">
- Normals
+ <combo_box follows="left|top" left="45" height="20" name="border_mode" width="100">
+ <combo_item name="border_unlock">
+ Unlock
+ </combo_item>
+ <combo_item name="border_lock">
+ Lock
+ </combo_item>
+ </combo_box>
+ <spinner follows="left|top" name="share_tolerance" left_pad="5" width="100" height="20"/>
+
+ <text left="10" top_pad="35" follows="top|left" width="240" height="15">
+ Generate Normals
</text>
<text left="35" top_pad="5" follows="top|left" width="100" height="15">
Crease Angle:
</text>
- <spinner follows="top|left" top_pad="5" min_val="0" max_val="180" value="75" width="60" height="20" name="crease_angle"/>
- <button follows="top|left" bottom_delta="3" left_pad="5" width="140" height="25" label="Generate Normals" name="generate_normals"/>
+ <spinner follows="top|left" left_pad="5" min_val="0" max_val="180" value="75" width="60" height="20" name="crease_angle"/>
</panel>
<!-- PANEL -->
@@ -341,8 +377,32 @@
</panel>
</panel>
-
-
+ <!-- MODIFIERS PANEL -->
+ <panel
+ border="true"
+ label="Modifiers"
+ name="modifiers_panel">
+ <text left="10" width="90" bottom="30" follows="top|left" height="15">
+ Scale:
+ </text>
+ <text left_pad="5" width="140" follows="top|left" height="15">
+ Dimensions:
+ </text>
+
+ <spinner left="10" height="20" follows="top|left" width="80" top_pad="5" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/>
+
+ <text left_pad="20" height="15" name="import_dimensions" follows="top|left">
+ [X] x [Y] x [Z] m
+ </text>
+
+ <text left="10" top_pad="20" follows="top|left" height="15">
+ Include:
+ </text>
+
+ <check_box top_pad="5" name="upload_textures" height="15" follows="top|left" label="Textures"/>
+ <check_box top_pad="5" name="upload_skin" height="15" follows="top|left" label="Skin weight"/>
+ <check_box top_pad="5" left="20" name="upload_joints" height="15" follows="top|left" label="Joint positions"/>
+ </panel>
</tab_container>
<!--
diff --git a/indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml b/indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml
new file mode 100644
index 0000000000..2650903f88
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ bottom="806"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="model_menu_gear_default"
+ visible="false">
+ <menu_item_check
+ label="Show edges"
+ layout="topleft"
+ name="show_edges">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_edges" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_edges" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_edges" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show physics"
+ layout="topleft"
+ name="show_physics">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_physics" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_physics" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_physics" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show textures"
+ layout="topleft"
+ name="show_textures">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_textures" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_textures" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_textures" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show skin weight"
+ layout="topleft"
+ name="show_skin_weight">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_skin_weight" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_skin_weight" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_skin_weight" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show joint positions"
+ layout="topleft"
+ name="show_joint_positions">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_joint_positions" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_joint_positions" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_joint_positions" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 38833d14df..6c1e9a3082 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -3153,17 +3153,7 @@
<menu_item_call.on_click
function="Advanced.LeaveAdminStatus" />
</menu_item_call>
- <menu_item_call
- label="HACK Upload Model..."
- layout="topleft"
- name="Upload Model">
- <menu_item_call.on_click
- function="File.UploadModel"
- parameter="" />
- <menu_item_call.on_enable
- function="File.EnableUploadModel" />
- </menu_item_call>
- <menu_item_check
+ <menu_item_check
label="Show Admin Menu"
name="View Admin Options">
<menu_item_check.on_enable