PageRenderTime 240ms CodeModel.GetById 13ms app.highlight 202ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llfloatermodelpreview.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2236 lines | 1677 code | 365 blank | 194 comment | 273 complexity | ec1ea93da092dfb0a77706f06582b3f6 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * @file llfloatermodelpreview.cpp
   3 * @brief LLFloaterModelPreview class implementation
   4 *
   5 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 *
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 *
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 *
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#if LL_MSVC
  30#pragma warning (disable : 4263)
  31#pragma warning (disable : 4264)
  32#endif
  33#include "dae.h"
  34//#include "dom.h"
  35#include "dom/domAsset.h"
  36#include "dom/domBind_material.h"
  37#include "dom/domCOLLADA.h"
  38#include "dom/domConstants.h"
  39#include "dom/domController.h"
  40#include "dom/domEffect.h"
  41#include "dom/domGeometry.h"
  42#include "dom/domInstance_geometry.h"
  43#include "dom/domInstance_material.h"
  44#include "dom/domInstance_node.h"
  45#include "dom/domInstance_effect.h"
  46#include "dom/domMaterial.h"
  47#include "dom/domMatrix.h"
  48#include "dom/domNode.h"
  49#include "dom/domProfile_COMMON.h"
  50#include "dom/domRotate.h"
  51#include "dom/domScale.h"
  52#include "dom/domTranslate.h"
  53#include "dom/domVisual_scene.h"
  54#if LL_MSVC
  55#pragma warning (default : 4263)
  56#pragma warning (default : 4264)
  57#endif
  58
  59#include "llfloatermodelpreview.h"
  60
  61#include "llfilepicker.h"
  62#include "llimagebmp.h"
  63#include "llimagetga.h"
  64#include "llimagejpeg.h"
  65#include "llimagepng.h"
  66
  67#include "llagent.h"
  68#include "llbutton.h"
  69#include "llcombobox.h"
  70#include "lldatapacker.h"
  71#include "lldrawable.h"
  72#include "lldrawpoolavatar.h"
  73#include "llrender.h"
  74#include "llface.h"
  75#include "lleconomy.h"
  76#include "llfocusmgr.h"
  77#include "llfloaterperms.h"
  78#include "lliconctrl.h"
  79#include "llmatrix4a.h"
  80#include "llmenubutton.h"
  81#include "llmeshrepository.h"
  82#include "llnotificationsutil.h"
  83#include "llsdutil_math.h"
  84#include "lltextbox.h"
  85#include "lltoolmgr.h"
  86#include "llui.h"
  87#include "llvector4a.h"
  88#include "llviewercamera.h"
  89#include "llviewerwindow.h"
  90#include "llvoavatar.h"
  91#include "llvoavatarself.h"
  92#include "pipeline.h"
  93#include "lluictrlfactory.h"
  94#include "llviewercontrol.h"
  95#include "llviewermenu.h"
  96#include "llviewermenufile.h"
  97#include "llviewerregion.h"
  98#include "llviewertexturelist.h"
  99#include "llstring.h"
 100#include "llbutton.h"
 101#include "llcheckboxctrl.h"
 102#include "llradiogroup.h"
 103#include "llsdserialize.h"
 104#include "llsliderctrl.h"
 105#include "llspinctrl.h"
 106#include "lltoggleablemenu.h"
 107#include "lltrans.h"
 108#include "llvfile.h"
 109#include "llvfs.h"
 110#include "llcallbacklist.h"
 111#include "llviewerobjectlist.h"
 112#include "llanimationstates.h"
 113#include "llviewernetwork.h"
 114#include "llviewershadermgr.h"
 115#include "glod/glod.h"
 116#include <boost/algorithm/string.hpp>
 117
 118
 119const S32 SLM_SUPPORTED_VERSION = 3;
 120
 121//static
 122S32 LLFloaterModelPreview::sUploadAmount = 10;
 123LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL;
 124std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
 125
 126const S32 PREVIEW_BORDER_WIDTH = 2;
 127const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
 128const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
 129const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
 130const S32 PREVIEW_TEXTURE_HEIGHT = 300;
 131
 132// "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01
 133// But according to the UI spec for upload model floater, this parameter
 134// should be represented by Retain spinner with values from 1 to 100 by 1.
 135// To achieve this, RETAIN_COEFFICIENT is used while creating spinner
 136// and when value is requested from spinner.
 137const double RETAIN_COEFFICIENT = 100;
 138
 139// "Cosine%" decomp parameter has values from 0.9 to 1 by 0.001
 140// But according to the UI spec for upload model floater, this parameter
 141// should be represented by Smooth combobox with only 10 values.
 142// So this const is used as a size of Smooth combobox list.
 143const S32 SMOOTH_VALUES_NUMBER = 10;
 144
 145void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
 146
 147
 148std::string lod_name[NUM_LOD+1] =
 149{
 150	"lowest",
 151	"low",
 152	"medium",
 153	"high",
 154	"I went off the end of the lod_name array.  Me so smart."
 155};
 156
 157std::string lod_triangles_name[NUM_LOD+1] =
 158{
 159	"lowest_triangles",
 160	"low_triangles",
 161	"medium_triangles",
 162	"high_triangles",
 163	"I went off the end of the lod_triangles_name array.  Me so smart."
 164};
 165
 166std::string lod_vertices_name[NUM_LOD+1] =
 167{
 168	"lowest_vertices",
 169	"low_vertices",
 170	"medium_vertices",
 171	"high_vertices",
 172	"I went off the end of the lod_vertices_name array.  Me so smart."
 173};
 174
 175std::string lod_status_name[NUM_LOD+1] =
 176{
 177	"lowest_status",
 178	"low_status",
 179	"medium_status",
 180	"high_status",
 181	"I went off the end of the lod_status_name array.  Me so smart."
 182};
 183
 184std::string lod_icon_name[NUM_LOD+1] =
 185{
 186	"status_icon_lowest",
 187	"status_icon_low",
 188	"status_icon_medium",
 189	"status_icon_high",
 190	"I went off the end of the lod_status_name array.  Me so smart."
 191};
 192
 193std::string lod_status_image[NUM_LOD+1] =
 194{
 195	"ModelImport_Status_Good",
 196	"ModelImport_Status_Warning",
 197	"ModelImport_Status_Error",
 198	"I went off the end of the lod_status_image array.  Me so smart."
 199};
 200
 201std::string lod_label_name[NUM_LOD+1] =
 202{
 203	"lowest_label",
 204	"low_label",
 205	"medium_label",
 206	"high_label",
 207	"I went off the end of the lod_label_name array.  Me so smart."
 208};
 209
 210std::string colladaVersion[VERSIONTYPE_COUNT+1] = 
 211{
 212	"1.4.0",
 213	"1.4.1",
 214	"Unsupported"
 215};
 216
 217
 218#define LL_DEGENERACY_TOLERANCE  1e-7f
 219
 220inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
 221{
 222    volatile F32 p0 = a[0] * b[0];
 223    volatile F32 p1 = a[1] * b[1];
 224    volatile F32 p2 = a[2] * b[2];
 225    return p0 + p1 + p2;
 226}
 227
 228bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE)
 229{
 230        // small area check
 231        {
 232                LLVector4a edge1; edge1.setSub( a, b );
 233                LLVector4a edge2; edge2.setSub( a, c );
 234                //////////////////////////////////////////////////////////////////////////
 235                /// Linden Modified
 236                //////////////////////////////////////////////////////////////////////////
 237
 238                // If no one edge is more than 10x longer than any other edge, we weaken
 239                // the tolerance by a factor of 1e-4f.
 240
 241                LLVector4a edge3; edge3.setSub( c, b );
 242				const F32 len1sq = edge1.dot3(edge1).getF32();
 243                const F32 len2sq = edge2.dot3(edge2).getF32();
 244                const F32 len3sq = edge3.dot3(edge3).getF32();
 245                bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
 246                bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
 247                bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
 248                if ( abOK && acOK && cbOK )
 249                {
 250                        tolerance *= 1e-4f;
 251                }
 252
 253                //////////////////////////////////////////////////////////////////////////
 254                /// End Modified
 255                //////////////////////////////////////////////////////////////////////////
 256
 257                LLVector4a cross; cross.setCross3( edge1, edge2 );
 258
 259                LLVector4a edge1b; edge1b.setSub( b, a );
 260                LLVector4a edge2b; edge2b.setSub( b, c );
 261                LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
 262
 263                if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
 264                {
 265                        return true;
 266                }
 267        }
 268
 269        // point triangle distance check
 270        {
 271                LLVector4a Q; Q.setSub(a, b);
 272                LLVector4a R; R.setSub(c, b);
 273
 274                const F32 QQ = dot3fpu(Q, Q);
 275                const F32 RR = dot3fpu(R, R);
 276                const F32 QR = dot3fpu(R, Q);
 277
 278                volatile F32 QQRR = QQ * RR;
 279                volatile F32 QRQR = QR * QR;
 280                F32 Det = (QQRR - QRQR);
 281
 282                if( Det == 0.0f )
 283                {
 284                        return true;
 285                }
 286        }
 287
 288        return false;
 289}
 290
 291bool validate_face(const LLVolumeFace& face)
 292{
 293	for (U32 i = 0; i < face.mNumIndices; ++i)
 294	{
 295		if (face.mIndices[i] >= face.mNumVertices)
 296		{
 297			llwarns << "Face has invalid index." << llendl;
 298			return false;
 299		}
 300	}
 301
 302	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
 303	{
 304		llwarns << "Face has invalid number of indices." << llendl;
 305		return false;
 306	}
 307
 308	/*const LLVector4a scale(0.5f);
 309
 310	for (U32 i = 0; i < face.mNumIndices; i+=3)
 311	{
 312		U16 idx1 = face.mIndices[i];
 313		U16 idx2 = face.mIndices[i+1];
 314		U16 idx3 = face.mIndices[i+2];
 315
 316		LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
 317		LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
 318		LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
 319
 320		if (ll_is_degenerate(v1,v2,v3))
 321		{
 322			llwarns << "Degenerate face found!" << llendl;
 323			return false;
 324		}
 325	}*/
 326
 327	return true;
 328}
 329
 330bool validate_model(const LLModel* mdl)
 331{
 332	if (mdl->getNumVolumeFaces() == 0)
 333	{
 334		llwarns << "Model has no faces!" << llendl;
 335		return false;
 336	}
 337
 338	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
 339	{
 340		if (mdl->getVolumeFace(i).mNumVertices == 0)
 341		{
 342			llwarns << "Face has no vertices." << llendl;
 343			return false;
 344		}
 345
 346		if (mdl->getVolumeFace(i).mNumIndices == 0)
 347		{
 348			llwarns << "Face has no indices." << llendl;
 349			return false;
 350		}
 351
 352		if (!validate_face(mdl->getVolumeFace(i)))
 353		{
 354			return false;
 355		}
 356	}
 357
 358	return true;
 359}
 360
 361BOOL stop_gloderror()
 362{
 363	GLuint error = glodGetError();
 364
 365	if (error != GLOD_NO_ERROR)
 366	{
 367		llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl;
 368		return TRUE;
 369	}
 370
 371	return FALSE;
 372}
 373
 374
 375LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
 376	: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
 377	{
 378		mMP = mp;
 379		mLOD = lod;
 380	}
 381
 382void LLMeshFilePicker::notify(const std::string& filename)
 383{
 384	mMP->loadModel(mFile, mLOD);
 385}
 386
 387
 388//-----------------------------------------------------------------------------
 389// LLFloaterModelPreview()
 390//-----------------------------------------------------------------------------
 391LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) :
 392LLFloaterModelUploadBase(key),
 393mUploadBtn(NULL),
 394mCalculateBtn(NULL)
 395{
 396	sInstance = this;
 397	mLastMouseX = 0;
 398	mLastMouseY = 0;
 399	mGLName = 0;
 400	mStatusLock = new LLMutex(NULL);
 401	mModelPreview = NULL;
 402
 403	mLODMode[LLModel::LOD_HIGH] = 0;
 404	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
 405	{
 406		mLODMode[i] = 1;
 407	}
 408}
 409
 410//-----------------------------------------------------------------------------
 411// postBuild()
 412//-----------------------------------------------------------------------------
 413BOOL LLFloaterModelPreview::postBuild()
 414{
 415	if (!LLFloater::postBuild())
 416	{
 417		return FALSE;
 418	}
 419
 420	childSetCommitCallback("cancel_btn", onCancel, this);
 421	childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this);
 422	getChild<LLCheckBoxCtrl>("gen_normals")->setCommitCallback(boost::bind(&LLFloaterModelPreview::toggleGenarateNormals, this));
 423
 424	childSetCommitCallback("lod_generate", onAutoFillCommit, this);
 425
 426	for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
 427	{
 428		LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
 429		lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod));
 430		lod_source_combo->setCurrentByIndex(mLODMode[lod]);
 431
 432		getChild<LLButton>("lod_browse_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onBrowseLOD, this, lod));
 433		getChild<LLComboBox>("lod_mode_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLODParamCommit, this, lod, false));
 434		getChild<LLSpinCtrl>("lod_error_threshold_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLODParamCommit, this, lod, false));
 435		getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLODParamCommit, this, lod, true));
 436	}
 437
 438	childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
 439	childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
 440	childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
 441
 442	childSetTextArg("status", "[STATUS]", getString("status_idle"));
 443
 444	childSetAction("ok_btn", onUpload, this);
 445	childDisable("ok_btn");
 446
 447	childSetAction("reset_btn", onReset, this);
 448
 449	childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this);
 450
 451	childSetCommitCallback("upload_skin", onUploadSkinCommit, this);
 452	childSetCommitCallback("upload_joints", onUploadJointsCommit, this);
 453
 454	childSetCommitCallback("import_scale", onImportScaleCommit, this);
 455	childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this);
 456
 457	getChild<LLCheckBoxCtrl>("show_edges")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
 458	getChild<LLCheckBoxCtrl>("show_physics")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
 459	getChild<LLCheckBoxCtrl>("show_textures")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
 460	getChild<LLCheckBoxCtrl>("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
 461	getChild<LLCheckBoxCtrl>("show_joint_positions")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
 462
 463	childDisable("upload_skin");
 464	childDisable("upload_joints");
 465
 466	initDecompControls();
 467
 468	LLView* preview_panel = getChild<LLView>("preview_panel");
 469
 470	mPreviewRect = preview_panel->getRect();
 471
 472	initModelPreview();
 473
 474	//set callbacks for left click on line editor rows
 475	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
 476	{
 477		LLTextBox* text = getChild<LLTextBox>(lod_label_name[i]);
 478		if (text)
 479		{
 480			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 481		}
 482
 483		text = getChild<LLTextBox>(lod_triangles_name[i]);
 484		if (text)
 485		{
 486			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 487		}
 488
 489		text = getChild<LLTextBox>(lod_vertices_name[i]);
 490		if (text)
 491		{
 492			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 493		}
 494
 495		text = getChild<LLTextBox>(lod_status_name[i]);
 496		if (text)
 497		{
 498			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 499		}
 500	}
 501	std::string current_grid = LLGridManager::getInstance()->getGridLabel();
 502	std::transform(current_grid.begin(),current_grid.end(),current_grid.begin(),::tolower);
 503	std::string validate_url;
 504	if (current_grid == "agni")
 505	{
 506		validate_url = "http://secondlife.com/my/account/mesh.php";
 507	}
 508	else if (current_grid == "damballah")
 509	{
 510		// Staging grid has its own naming scheme.
 511		validate_url = "http://secondlife-staging.com/my/account/mesh.php";
 512	}
 513	else
 514	{
 515		validate_url = llformat("http://secondlife.%s.lindenlab.com/my/account/mesh.php",current_grid.c_str());
 516	}
 517	getChild<LLTextBox>("warning_message")->setTextArg("[VURL]", validate_url);
 518
 519	mUploadBtn = getChild<LLButton>("ok_btn");
 520	mCalculateBtn = getChild<LLButton>("calculate_btn");
 521
 522	mCalculateBtn->setClickedCallback(boost::bind(&LLFloaterModelPreview::onClickCalculateBtn, this));
 523
 524	toggleCalculateButton(true);
 525
 526	return TRUE;
 527}
 528
 529//-----------------------------------------------------------------------------
 530// LLFloaterModelPreview()
 531//-----------------------------------------------------------------------------
 532LLFloaterModelPreview::~LLFloaterModelPreview()
 533{
 534	sInstance = NULL;
 535	
 536	if ( mModelPreview )
 537	{
 538		delete mModelPreview;
 539	}
 540
 541	if (mGLName)
 542	{
 543		LLImageGL::deleteTextures(1, &mGLName );
 544	}
 545
 546	delete mStatusLock;
 547	mStatusLock = NULL;
 548}
 549
 550void LLFloaterModelPreview::initModelPreview()
 551{
 552	if (mModelPreview)
 553	{
 554		delete mModelPreview;
 555	}
 556
 557	mModelPreview = new LLModelPreview(512, 512, this );
 558	mModelPreview->setPreviewTarget(16.f);
 559	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
 560	mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1));
 561}
 562
 563void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl)
 564{
 565	if (mModelPreview)
 566	{
 567		mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()];
 568		
 569		mModelPreview->refresh();
 570	}
 571}
 572
 573bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata)
 574{
 575	if (mModelPreview)
 576	{
 577		return mModelPreview->mViewOption[userdata.asString()];
 578	}
 579
 580	return false;
 581}
 582
 583bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata)
 584{
 585	return childIsEnabled(userdata.asString());
 586}
 587
 588void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled)
 589{
 590	childSetEnabled(option, enabled);
 591}
 592
 593void LLFloaterModelPreview::enableViewOption(const std::string& option)
 594{
 595	setViewOptionEnabled(option, true);
 596}
 597
 598void LLFloaterModelPreview::disableViewOption(const std::string& option)
 599{
 600	setViewOptionEnabled(option, false);
 601}
 602
 603void LLFloaterModelPreview::loadModel(S32 lod)
 604{
 605	mModelPreview->mLoading = true;
 606
 607	(new LLMeshFilePicker(mModelPreview, lod))->getFile();
 608}
 609
 610void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name, bool force_disable_slm)
 611{
 612	mModelPreview->mLoading = true;
 613
 614	mModelPreview->loadModel(file_name, lod, force_disable_slm);
 615}
 616
 617void LLFloaterModelPreview::onClickCalculateBtn()
 618{
 619	mModelPreview->rebuildUploadData();
 620
 621	bool upload_skinweights = childGetValue("upload_skin").asBoolean();
 622	bool upload_joint_positions = childGetValue("upload_joints").asBoolean();
 623
 624	mUploadModelUrl.clear();
 625
 626	gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
 627			childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false,
 628						  getWholeModelFeeObserverHandle());
 629
 630	toggleCalculateButton(false);
 631	mUploadBtn->setEnabled(false);
 632}
 633
 634//static
 635void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
 636{
 637	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 638
 639	if (!fp->mModelPreview)
 640	{
 641		return;
 642	}
 643
 644	fp->mModelPreview->mDirty = true;
 645
 646	fp->toggleCalculateButton(true);
 647
 648	fp->mModelPreview->refresh();
 649}
 650//static
 651void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata )
 652{
 653	LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata;
 654
 655	if (!fp->mModelPreview)
 656	{
 657		return;
 658	}
 659
 660	fp->mModelPreview->mDirty = true;
 661
 662	fp->toggleCalculateButton(true);
 663
 664	fp->mModelPreview->refresh();
 665}
 666
 667//static
 668void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata)
 669{
 670	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 671
 672	if (!fp->mModelPreview)
 673	{
 674		return;
 675	}
 676
 677	fp->mModelPreview->refresh();
 678}
 679
 680//static
 681void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata)
 682{
 683	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 684
 685	if (!fp->mModelPreview)
 686	{
 687		return;
 688	}
 689	fp->mModelPreview->refresh();
 690	fp->mModelPreview->resetPreviewTarget();
 691	fp->mModelPreview->clearBuffers();
 692}
 693
 694//static
 695void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata)
 696{
 697	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 698
 699	if (!fp->mModelPreview)
 700	{
 701		return;
 702	}
 703
 704	S32 which_mode = 0;
 705
 706	LLComboBox* combo = (LLComboBox*) ctrl;
 707
 708	which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order
 709
 710	fp->mModelPreview->setPreviewLOD(which_mode);
 711}
 712
 713//static
 714void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata)
 715{
 716	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
 717
 718	fp->mModelPreview->generateNormals();
 719}
 720
 721void LLFloaterModelPreview::toggleGenarateNormals()
 722{
 723	bool enabled = childGetValue("gen_normals").asBoolean();
 724	childSetEnabled("crease_angle", enabled);
 725}
 726
 727//static
 728void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata)
 729{
 730	LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance;
 731
 732	fp->mModelPreview->refresh();
 733}
 734
 735//static
 736void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
 737{
 738	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
 739
 740	fp->mModelPreview->genLODs();
 741}
 742
 743void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
 744{
 745	mModelPreview->onLODParamCommit(lod, enforce_tri_limit);
 746}
 747
 748
 749//-----------------------------------------------------------------------------
 750// draw()
 751//-----------------------------------------------------------------------------
 752void LLFloaterModelPreview::draw()
 753{
 754	LLFloater::draw();
 755	LLRect r = getRect();
 756
 757	mModelPreview->update();
 758
 759	if (!mModelPreview->mLoading)
 760	{
 761		if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_MATERIALS )
 762		{
 763			childSetTextArg("status", "[STATUS]", getString("status_material_mismatch"));
 764		}
 765		else
 766		if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING )
 767		{		
 768			childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));
 769		}
 770		else
 771		if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING )
 772		{
 773			childSetTextArg("status", "[STATUS]", getString("status_parse_error"));
 774			toggleCalculateButton(false);
 775		}
 776		else
 777		{
 778			childSetTextArg("status", "[STATUS]", getString("status_idle"));
 779		}
 780	}
 781
 782	childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
 783	childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size()));
 784
 785	if (mModelPreview)
 786	{
 787		gGL.color3f(1.f, 1.f, 1.f);
 788
 789		gGL.getTexUnit(0)->bind(mModelPreview);
 790
 791
 792		LLView* preview_panel = getChild<LLView>("preview_panel");
 793
 794		LLRect rect = preview_panel->getRect();
 795		if (rect != mPreviewRect)
 796		{
 797			mModelPreview->refresh();
 798			mPreviewRect = preview_panel->getRect();
 799		}
 800
 801		gGL.begin( LLRender::QUADS );
 802		{
 803			gGL.texCoord2f(0.f, 1.f);
 804			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1);
 805			gGL.texCoord2f(0.f, 0.f);
 806			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom);
 807			gGL.texCoord2f(1.f, 0.f);
 808			gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom);
 809			gGL.texCoord2f(1.f, 1.f);
 810			gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1);
 811		}
 812		gGL.end();
 813
 814		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 815	}
 816}
 817
 818//-----------------------------------------------------------------------------
 819// handleMouseDown()
 820//-----------------------------------------------------------------------------
 821BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask)
 822{
 823	if (mPreviewRect.pointInRect(x, y))
 824	{
 825		bringToFront( x, y );
 826		gFocusMgr.setMouseCapture(this);
 827		gViewerWindow->hideCursor();
 828		mLastMouseX = x;
 829		mLastMouseY = y;
 830		return TRUE;
 831	}
 832
 833	return LLFloater::handleMouseDown(x, y, mask);
 834}
 835
 836//-----------------------------------------------------------------------------
 837// handleMouseUp()
 838//-----------------------------------------------------------------------------
 839BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask)
 840{
 841	gFocusMgr.setMouseCapture(FALSE);
 842	gViewerWindow->showCursor();
 843	return LLFloater::handleMouseUp(x, y, mask);
 844}
 845
 846//-----------------------------------------------------------------------------
 847// handleHover()
 848//-----------------------------------------------------------------------------
 849BOOL LLFloaterModelPreview::handleHover	(S32 x, S32 y, MASK mask)
 850{
 851	MASK local_mask = mask & ~MASK_ALT;
 852
 853	if (mModelPreview && hasMouseCapture())
 854	{
 855		if (local_mask == MASK_PAN)
 856		{
 857			// pan here
 858			mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
 859		}
 860		else if (local_mask == MASK_ORBIT)
 861		{
 862			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
 863			F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
 864
 865			mModelPreview->rotate(yaw_radians, pitch_radians);
 866		}
 867		else
 868		{
 869
 870			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
 871			F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f;
 872
 873			mModelPreview->rotate(yaw_radians, 0.f);
 874			mModelPreview->zoom(zoom_amt);
 875		}
 876
 877
 878		mModelPreview->refresh();
 879
 880		LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY);
 881	}
 882
 883	if (!mPreviewRect.pointInRect(x, y) || !mModelPreview)
 884	{
 885		return LLFloater::handleHover(x, y, mask);
 886	}
 887	else if (local_mask == MASK_ORBIT)
 888	{
 889		gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA);
 890	}
 891	else if (local_mask == MASK_PAN)
 892	{
 893		gViewerWindow->setCursor(UI_CURSOR_TOOLPAN);
 894	}
 895	else
 896	{
 897		gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN);
 898	}
 899
 900	return TRUE;
 901}
 902
 903//-----------------------------------------------------------------------------
 904// handleScrollWheel()
 905//-----------------------------------------------------------------------------
 906BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
 907{
 908	if (mPreviewRect.pointInRect(x, y) && mModelPreview)
 909	{
 910		mModelPreview->zoom((F32)clicks * -0.2f);
 911		mModelPreview->refresh();
 912	}
 913
 914	return TRUE;
 915}
 916
 917/*virtual*/
 918void LLFloaterModelPreview::onOpen(const LLSD& key)
 919{
 920	requestAgentUploadPermissions();
 921}
 922
 923//static
 924void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
 925{
 926	if (LLConvexDecomposition::getInstance() == NULL)
 927	{
 928		llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl;
 929		return;
 930	}
 931
 932	if (sInstance)
 933	{
 934		LLCDParam* param = (LLCDParam*) data;
 935		std::string name(param->mName);
 936
 937		LLSD value = ctrl->getValue();
 938
 939		if("Retain%" == name)
 940		{
 941			value = ctrl->getValue().asReal() / RETAIN_COEFFICIENT;
 942		}
 943
 944		sInstance->mDecompParams[name] = value;
 945
 946		if (name == "Simplify Method")
 947		{
 948			bool show_retain = false;
 949			bool show_detail = true;
 950
 951			if (ctrl->getValue().asInteger() == 0)
 952			{
 953				 show_retain = true;
 954				 show_detail = false;
 955			}
 956
 957			sInstance->childSetVisible("Retain%", show_retain);
 958			sInstance->childSetVisible("Retain%_label", show_retain);
 959
 960			sInstance->childSetVisible("Detail Scale", show_detail);
 961			sInstance->childSetVisible("Detail Scale label", show_detail);
 962		}
 963	}
 964}
 965
 966//static
 967void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data)
 968{
 969	LLCDStageData* stage_data = (LLCDStageData*) data;
 970	std::string stage = stage_data->mName;
 971
 972	if (sInstance)
 973	{
 974		if (!sInstance->mCurRequest.empty())
 975		{
 976			llinfos << "Decomposition request still pending." << llendl;
 977			return;
 978		}
 979
 980		if (sInstance->mModelPreview)
 981		{
 982			for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i)
 983			{
 984				LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i];
 985				DecompRequest* request = new DecompRequest(stage, mdl);
 986				sInstance->mCurRequest.insert(request);
 987				gMeshRepo.mDecompThread->submitRequest(request);
 988			}
 989		}
 990
 991		if (stage == "Decompose")
 992		{
 993			sInstance->setStatusMessage(sInstance->getString("decomposing"));
 994			sInstance->childSetVisible("Decompose", false);
 995			sInstance->childSetVisible("decompose_cancel", true);
 996			sInstance->childDisable("Simplify");
 997		}
 998		else if (stage == "Simplify")
 999		{
1000			sInstance->setStatusMessage(sInstance->getString("simplifying"));
1001			sInstance->childSetVisible("Simplify", false);
1002			sInstance->childSetVisible("simplify_cancel", true);
1003			sInstance->childDisable("Decompose");
1004		}
1005	}
1006}
1007
1008//static
1009void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata)
1010{
1011	sInstance->loadModel(LLModel::LOD_PHYSICS);
1012}
1013
1014//static
1015void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata)
1016{
1017	S32 num_lods = 4;
1018	S32 which_mode;
1019
1020	LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo");
1021	if (iface)
1022	{
1023		which_mode = iface->getFirstSelectedIndex();
1024	}
1025	else
1026	{
1027		llwarns << "no iface" << llendl;
1028		return;
1029	}
1030
1031	if (which_mode <= 0)
1032	{
1033		llwarns << "which_mode out of range, " << which_mode << llendl;
1034	}
1035
1036	S32 file_mode = iface->getItemCount() - 1;
1037	if (which_mode < file_mode)
1038	{
1039		S32 which_lod = num_lods - which_mode;
1040		sInstance->mModelPreview->setPhysicsFromLOD(which_lod);
1041	}
1042
1043	LLModelPreview *model_preview = sInstance->mModelPreview;
1044	if (model_preview)
1045	{
1046		model_preview->refresh();
1047		model_preview->updateStatusMessages();
1048	}
1049}
1050
1051//static 
1052void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data)
1053{
1054	if (sInstance)
1055	{
1056		sInstance->closeFloater(false);
1057	}
1058}
1059
1060//static
1061void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data)
1062{
1063	if (sInstance)
1064	{
1065		for (std::set<LLPointer<DecompRequest> >::iterator iter = sInstance->mCurRequest.begin();
1066			iter != sInstance->mCurRequest.end(); ++iter)
1067		{
1068		    DecompRequest* req = *iter;
1069		    req->mContinue = 0;
1070		}
1071
1072		sInstance->mCurRequest.clear();
1073
1074		if (sInstance->mModelPreview)
1075		{
1076			sInstance->mModelPreview->updateStatusMessages();
1077		}
1078	}
1079}
1080
1081void LLFloaterModelPreview::initDecompControls()
1082{
1083	LLSD key;
1084
1085	childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL);
1086	childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL);
1087
1088	childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL);
1089	childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL);
1090
1091	static const LLCDStageData* stage = NULL;
1092	static S32 stage_count = 0;
1093
1094	if (!stage && LLConvexDecomposition::getInstance() != NULL)
1095	{
1096		stage_count = LLConvexDecomposition::getInstance()->getStages(&stage);
1097	}
1098
1099	static const LLCDParam* param = NULL;
1100	static S32 param_count = 0;
1101	if (!param && LLConvexDecomposition::getInstance() != NULL)
1102	{
1103		param_count = LLConvexDecomposition::getInstance()->getParameters(&param);
1104	}
1105
1106	for (S32 j = stage_count-1; j >= 0; --j)
1107	{
1108		LLButton* button = getChild<LLButton>(stage[j].mName);
1109		if (button)
1110		{
1111			button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]);
1112		}
1113
1114		gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j;
1115		// protected against stub by stage_count being 0 for stub above
1116		LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback);
1117
1118		//llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl;
1119		//llinfos << "------------------------------------" << llendl;
1120
1121		for (S32 i = 0; i < param_count; ++i)
1122		{
1123			if (param[i].mStage != j)
1124			{
1125				continue;
1126			}
1127
1128			std::string name(param[i].mName ? param[i].mName : "");
1129			std::string description(param[i].mDescription ? param[i].mDescription : "");
1130
1131			std::string type = "unknown";
1132
1133			llinfos << name << " - " << description << llendl;
1134
1135			if (param[i].mType == LLCDParam::LLCD_FLOAT)
1136			{
1137				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat);
1138				//llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl;
1139
1140
1141				LLUICtrl* ctrl = getChild<LLUICtrl>(name);
1142				if (LLSliderCtrl* slider = dynamic_cast<LLSliderCtrl*>(ctrl))
1143				{
1144					slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat);
1145					slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat);
1146					slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat);
1147					slider->setValue(param[i].mDefault.mFloat);
1148					slider->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1149				}
1150				else if (LLSpinCtrl* spinner = dynamic_cast<LLSpinCtrl*>(ctrl))
1151				{
1152					bool is_retain_ctrl = "Retain%" == name;
1153					double coefficient = is_retain_ctrl ? RETAIN_COEFFICIENT : 1.f;
1154
1155					spinner->setMinValue(param[i].mDetails.mRange.mLow.mFloat * coefficient);
1156					spinner->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat * coefficient);
1157					spinner->setIncrement(param[i].mDetails.mRange.mDelta.mFloat * coefficient);
1158					spinner->setValue(param[i].mDefault.mFloat * coefficient);
1159					spinner->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1160				}
1161				else if (LLComboBox* combo_box = dynamic_cast<LLComboBox*>(ctrl))
1162				{
1163					float min = param[i].mDetails.mRange.mLow.mFloat;
1164					float max = param[i].mDetails.mRange.mHigh.mFloat;
1165					float delta = param[i].mDetails.mRange.mDelta.mFloat;
1166
1167					if ("Cosine%" == name)
1168					{
1169						createSmoothComboBox(combo_box, min, max);
1170					}
1171					else
1172					{
1173						for(float value = min; value <= max; value += delta)
1174						{
1175							std::string label = llformat("%.1f", value);
1176							combo_box->add(label, value, ADD_BOTTOM, true);
1177						}
1178						combo_box->setValue(param[i].mDefault.mFloat);
1179
1180					}
1181
1182					combo_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1183				}
1184			}
1185			else if (param[i].mType == LLCDParam::LLCD_INTEGER)
1186			{
1187				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
1188				//llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl;
1189
1190
1191				LLUICtrl* ctrl = getChild<LLUICtrl>(name);
1192				if (LLSliderCtrl* slider = dynamic_cast<LLSliderCtrl*>(ctrl))
1193				{
1194					slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue);
1195					slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue);
1196					slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue);
1197					slider->setValue(param[i].mDefault.mIntOrEnumValue);
1198					slider->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1199				}
1200				else if (LLComboBox* combo_box = dynamic_cast<LLComboBox*>(ctrl))
1201				{
1202					for(int k = param[i].mDetails.mRange.mLow.mIntOrEnumValue; k<=param[i].mDetails.mRange.mHigh.mIntOrEnumValue; k+=param[i].mDetails.mRange.mDelta.mIntOrEnumValue)
1203					{
1204						std::string name = llformat("%.1d", k);
1205						combo_box->add(name, k, ADD_BOTTOM, true);
1206					}
1207					combo_box->setValue(param[i].mDefault.mIntOrEnumValue);
1208					combo_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1209				}
1210			}
1211			else if (param[i].mType == LLCDParam::LLCD_BOOLEAN)
1212			{
1213				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool);
1214				//llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl;
1215
1216				LLCheckBoxCtrl* check_box = getChild<LLCheckBoxCtrl>(name);
1217				if (check_box)
1218				{
1219					check_box->setValue(param[i].mDefault.mBool);
1220					check_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1221				}
1222			}
1223			else if (param[i].mType == LLCDParam::LLCD_ENUM)
1224			{
1225				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
1226				//llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl;
1227
1228				{ //plug into combo box
1229
1230					//llinfos << "Accepted values: " << llendl;
1231					LLComboBox* combo_box = getChild<LLComboBox>(name);
1232					for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k)
1233					{
1234						//llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue
1235						//	<< " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl;
1236
1237						std::string name(param[i].mDetails.mEnumValues.mEnumsArray[k].mName);
1238						std::string localized_name;
1239						bool is_localized = LLTrans::findString(localized_name, name);
1240
1241						combo_box->add(is_localized ? localized_name : name,
1242							LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue));
1243					}
1244					combo_box->setValue(param[i].mDefault.mIntOrEnumValue);
1245					combo_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
1246				}
1247
1248				//llinfos << "----" << llendl;
1249			}
1250			//llinfos << "-----------------------------" << llendl;
1251		}
1252	}
1253
1254	childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this);
1255}
1256
1257void LLFloaterModelPreview::createSmoothComboBox(LLComboBox* combo_box, float min, float max)
1258{
1259	float delta = (max - min) / SMOOTH_VALUES_NUMBER;
1260	int ilabel = 0;
1261
1262	combo_box->add("0 (none)", ADD_BOTTOM, true);
1263
1264	for(float value = min + delta; value < max; value += delta)
1265	{
1266		std::string label = (++ilabel == SMOOTH_VALUES_NUMBER) ? "10 (max)" : llformat("%.1d", ilabel);
1267		combo_box->add(label, value, ADD_BOTTOM, true);
1268	}
1269
1270
1271}
1272
1273//-----------------------------------------------------------------------------
1274// onMouseCaptureLost()
1275//-----------------------------------------------------------------------------
1276// static
1277void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler)
1278{
1279	gViewerWindow->showCursor();
1280}
1281
1282//-----------------------------------------------------------------------------
1283// LLModelLoader
1284//-----------------------------------------------------------------------------
1285LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, 
1286							  std::deque<std::string>& jointsFromNodes )
1287: mJointList( jointMap )
1288, mJointsFromNode( jointsFromNodes )
1289, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0)
1290{
1291	mJointMap["mPelvis"] = "mPelvis";
1292	mJointMap["mTorso"] = "mTorso";
1293	mJointMap["mChest"] = "mChest";
1294	mJointMap["mNeck"] = "mNeck";
1295	mJointMap["mHead"] = "mHead";
1296	mJointMap["mSkull"] = "mSkull";
1297	mJointMap["mEyeRight"] = "mEyeRight";
1298	mJointMap["mEyeLeft"] = "mEyeLeft";
1299	mJointMap["mCollarLeft"] = "mCollarLeft";
1300	mJointMap["mShoulderLeft"] = "mShoulderLeft";
1301	mJointMap["mElbowLeft"] = "mElbowLeft";
1302	mJointMap["mWristLeft"] = "mWristLeft";
1303	mJointMap["mCollarRight"] = "mCollarRight";
1304	mJointMap["mShoulderRight"] = "mShoulderRight";
1305	mJointMap["mElbowRight"] = "mElbowRight";
1306	mJointMap["mWristRight"] = "mWristRight";
1307	mJointMap["mHipRight"] = "mHipRight";
1308	mJointMap["mKneeRight"] = "mKneeRight";
1309	mJointMap["mAnkleRight"] = "mAnkleRight";
1310	mJointMap["mFootRight"] = "mFootRight";
1311	mJointMap["mToeRight"] = "mToeRight";
1312	mJointMap["mHipLeft"] = "mHipLeft";
1313	mJointMap["mKneeLeft"] = "mKneeLeft";
1314	mJointMap["mAnkleLeft"] = "mAnkleLeft";
1315	mJointMap["mFootLeft"] = "mFootLeft";
1316	mJointMap["mToeLeft"] = "mToeLeft";
1317
1318	mJointMap["avatar_mPelvis"] = "mPelvis";
1319	mJointMap["avatar_mTorso"] = "mTorso";
1320	mJointMap["avatar_mChest"] = "mChest";
1321	mJointMap["avatar_mNeck"] = "mNeck";
1322	mJointMap["avatar_mHead"] = "mHead";
1323	mJointMap["avatar_mSkull"] = "mSkull";
1324	mJointMap["avatar_mEyeRight"] = "mEyeRight";
1325	mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
1326	mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
1327	mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
1328	mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
1329	mJointMap["avatar_mWristLeft"] = "mWristLeft";
1330	mJointMap["avatar_mCollarRight"] = "mCollarRight";
1331	mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
1332	mJointMap["avatar_mElbowRight"] = "mElbowRight";
1333	mJointMap["avatar_mWristRight"] = "mWristRight";
1334	mJointMap["avatar_mHipRight"] = "mHipRight";
1335	mJointMap["avatar_mKneeRight"] = "mKneeRight";
1336	mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
1337	mJointMap["avatar_mFootRight"] = "mFootRight";
1338	mJointMap["avatar_mToeRight"] = "mToeRight";
1339	mJointMap["avatar_mHipLeft"] = "mHipLeft";
1340	mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
1341	mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
1342	mJointMap["avatar_mFootLeft"] = "mFootLeft";
1343	mJointMap["avatar_mToeLeft"] = "mToeLeft";
1344
1345
1346	mJointMap["hip"] = "mPelvis";
1347	mJointMap["abdomen"] = "mTorso";
1348	mJointMap["chest"] = "mChest";
1349	mJointMap["neck"] = "mNeck";
1350	mJointMap["head"] = "mHead";
1351	mJointMap["figureHair"] = "mSkull";
1352	mJointMap["lCollar"] = "mCollarLeft";
1353	mJointMap["lShldr"] = "mShoulderLeft";
1354	mJointMap["lForeArm"] = "mElbowLeft";
1355	mJointMap["lHand"] = "mWristLeft";
1356	mJointMap["rCollar"] = "mCollarRight";
1357	mJointMap["rShldr"] = "mShoulderRight";
1358	mJointMap["rForeArm"] = "mElbowRight";
1359	mJointMap["rHand"] = "mWristRight";
1360	mJointMap["rThigh"] = "mHipRight";
1361	mJointMap["rShin"] = "mKneeRight";
1362	mJointMap["rFoot"] = "mFootRight";
1363	mJointMap["lThigh"] = "mHipLeft";
1364	mJointMap["lShin"] = "mKneeLeft";
1365	mJointMap["lFoot"] = "mFootLeft";
1366
1367	if (mPreview)
1368	{
1369		//only try to load from slm if viewer is configured to do so and this is the 
1370		//initial model load (not an LoD or physics shape)
1371		mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
1372		mPreview->setLoadState(STARTING);
1373	}
1374	else
1375	{
1376		mTrySLM = false;
1377	}
1378
1379	assert_main_thread();
1380	sActiveLoaderList.push_back(this) ;
1381}
1382
1383LLModelLoader::~LLModelLoader()
1384{
1385	assert_main_thread();
1386	sActiveLoaderList.remove(this);
1387}
1388
1389void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
1390{
1391	LLVector4a box[] =
1392	{
1393		LLVector4a(-1, 1,-1),
1394		LLVector4a(-1, 1, 1),
1395		LLVector4a(-1,-1,-1),
1396		LLVector4a(-1,-1, 1),
1397		LLVector4a( 1, 1,-1),
1398		LLVector4a( 1, 1, 1),
1399		LLVector4a( 1,-1,-1),
1400		LLVector4a( 1,-1, 1),
1401	};
1402
1403	for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
1404	{
1405		const LLVolumeFace& face = model->getVolumeFace(j);
1406
1407		LLVector4a center;
1408		center.setAdd(face.mExtents[0], face.mExtents[1]);
1409		center.mul(0.5f);
1410		LLVector4a size;
1411		size.setSub(face.mExtents[1],face.mExtents[0]);
1412		size.mul(0.5f);
1413
1414		for (U32 i = 0; i < 8; i++)
1415		{
1416			LLVector4a t;
1417			t.setMul(size, box[i]);
1418			t.add(center);
1419
1420			LLVector4a v;
1421
1422			mat.affineTransform(t, v);
1423
1424			if (first_transform)
1425			{
1426				first_transform = FALSE;
1427				min = max = v;
1428			}
1429			else
1430			{
1431				update_min_max(min, max, v);
1432			}
1433		}
1434	}
1435}
1436
1437void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
1438{
1439	LLVector4a mina, maxa;
1440	LLMatrix4a mata;
1441
1442	mata.loadu(mat);
1443	mina.load3(min.mV);
1444	maxa.load3(max.mV);
1445
1446	stretch_extents(model, mata, mina, maxa, first_transform);
1447
1448	min.set(mina.getF32ptr());
1449	max.set(maxa.getF32ptr());
1450}
1451
1452void LLModelLoader::run()
1453{
1454	doLoadModel();
1455	doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
1456}
1457
1458bool LLModelLoader::doLoadModel()
1459{
1460	//first, look for a .slm file of the same name that was modified later
1461	//than the .dae
1462
1463	if (mTrySLM)
1464	{
1465		std::string filename = mFilename;
1466			
1467		std::string::size_type i = filename.rfind(".");
1468		if (i != std::string::npos)
1469		{
1470			filename.replace(i, filename.size()-1, ".slm");
1471			llstat slm_status;
1472			if (LLFile::stat(filename, &slm_status) == 0)
1473			{ //slm file exists
1474				llstat dae_status;
1475				if (LLFile::stat(mFilename, &dae_status) != 0 ||
1476					dae_status.st_mtime < slm_status.st_mtime)
1477				{
1478					if (loadFromSLM(filename))
1479					{ //slm successfully loaded, if this fails, fall through and
1480						//try loading from dae
1481
1482						mLod = -1; //successfully loading from an slm implicitly sets all 
1483									//LoDs
1484						return true;
1485					}
1486				}
1487			}	
1488		}
1489	}
1490
1491	//no suitable slm exists, load from the .dae file
1492	DAE dae;
1493	domCOLLADA* dom = dae.open(mFilename);
1494	
1495	if (!dom)
1496	{
1497		llinfos<<" Error with dae - traditionally indicates a corrupt file."<<llendl;
1498		setLoadState( ERROR_PARSING );
1499		return false;
1500	}
1501	//Dom version
1502	daeString domVersion = dae.getDomVersion();
1503	std::string sldom(domVersion);
1504	llinfos<<"Collada Importer Version: "<<sldom<<llendl;
1505	//Dae version
1506	domVersionType docVersion = dom->getVersion();
1507	//0=1.4
1508	//1=1.4.1
1509	//2=Currently unsupported, however may work
1510	if (docVersion > 1 ) 
1511	{ 
1512		docVersion = VERSIONTYPE_COUNT;
1513	}
1514	llinfos<<"Dae version "<<colladaVersion[docVersion]<<llendl;
1515	
1516	
1517	daeDatabase* db = dae.getDatabase();
1518	
1519	daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
1520	
1521	daeDocument* doc = dae.getDoc(mFilename);
1522	if (!doc)
1523	{
1524		llwarns << "can't find internal doc" << llendl;
1525		return false;
1526	}
1527	
1528	daeElement* root = doc->getDomRoot();
1529	if (!root)
1530	{
1531		llwarns << "document has no root" << llendl;
1532		return false;
1533	}
1534	
1535	//Verify some basic properties of the dae
1536	//1. Basic validity check on controller 
1537	U32 controllerCount = (int) db->getElementCount( NULL, "controller" );
1538	bool result = false;
1539	for ( int i=0; i<controllerCount; ++i )
1540	{
1541		domController* pController = NULL;
1542		db->getElement( (daeElement**) &pController, i , NULL, "controller" );
1543		result = mPreview->verifyController( pController );
1544		if (!result)
1545		{
1546			setLoadState( ERROR_PARSING );
1547			return true;
1548		}
1549	}
1550
1551
1552	//get unit scale
1553	mTransform.setIdentity();
1554	
1555	domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
1556	
1557	if (unit)
1558	{
1559		F32 meter = unit->getMeter();
1560		mTransform.mMatrix[0][0] = meter;
1561		mTransform.mMatrix[1][1] = meter;
1562		mTransform.mMatrix[2][2] = meter;
1563	}
1564	
1565	//get up axis rotation
1566	LLMatrix4 rotation;
1567	
1568	domUpAxisType up = UPAXISTYPE_Y_UP;  // default is Y_UP
1569	domAsset::domUp_axis* up_axis =
1570	daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
1571	
1572	if (up_axis)
1573	{
1574		up = up_axis->getValue();
1575	}
1576	
1577	if (up == UPAXISTYPE_X_UP)
1578	{
1579		rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
1580	}
1581	else if (up == UPAXISTYPE_Y_UP)
1582	{
1583		rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
1584	}
1585	
1586	rotation *= mTransform;
1587	mTransform = rotation;
1588	
1589	
1590	for (daeInt idx = 0; idx < count; ++idx)
1591	{ //build map of domEntities to LLModel
1592		domMesh* mesh = NULL;
1593		db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
1594		
1595		if (mesh)
1596		{
1597			LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
1598			
1599			if(model->getStatus() != LLModel::NO_ERRORS)
1600			{
1601				setLoadState(ERROR_PARSING + model->getStatus()) ;
1602				return false; //abort
1603			}
1604
1605			if (model.notNull() && validate_model(model))
1606			{
1607				mModelList.push_back(model);
1608				mModel[mesh] = model;
1609			}
1610		}
1611	}
1612	
1613	count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
1614	for (daeInt idx = 0; idx < count; ++idx)
1615	{ //add skinned meshes as instances
1616		domSkin* skin = NULL;
1617		db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
1618		
1619		if (skin)
1620		{
1621			domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
1622			
1623			if (geom)
1624			{
1625				domMesh* mesh = geom->getMesh();
1626				if (mesh)
1627				{
1628					LLModel* model = mModel[mesh];
1629					if (model)
1630					{
1631						LLVector3 mesh_scale_vector;
1632						LLVector3 mesh_translation_vector;
1633						model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
1634						
1635						LLMatrix4 normalized_transformation;
1636						normalized_transformation.setTranslation(mesh_translation_vector);
1637						
1638						LLMatrix4 mesh_scale;
1639						mesh_scale.initScale(mesh_scale_vector);
1640						mesh_scale *= normalized_transformation;
1641						normalized_transformation = mesh_scale;
1642						
1643						glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
1644						inv_mat = inv_mat.inverse();
1645						LLMatrix4 inverse_normalized_transformation(inv_mat.m);
1646						
1647						domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
1648						
1649						if (bind_mat)
1650						{ //get bind shape matrix
1651							domFloat4x4& dom_value = bind_mat->getValue();
1652							
1653							LLMeshSkinInfo& skin_info = model->mSkinInfo;
1654
1655							for (int i = 0; i < 4; i++)
1656							{
1657								for(int j = 0; j < 4; j++)
1658								{
1659									skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
1660								}
1661							}
1662							
1663							LLMatrix4 trans = normalized_transformation;
1664							trans *= skin_info.mBindShapeMatrix;
1665							skin_info.mBindShapeMatrix = trans;							
1666						}
1667										
1668											
1669						//Some collada setup for accessing the skeleton
1670						daeElement* pElement = 0;
1671						dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
1672						
1673						//Try to get at the skeletal instance controller
1674						domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
1675						bool missingSkeletonOrScene = false;
1676						
1677						//If no skeleton, do a breadth-first search to get at specific joints
1678						bool rootNode = false;
1679						bool skeletonWithNoRootNode = false;
1680						
1681						//Need to test for a skeleton that does not have a root node
1682						//This occurs when your instance controller does not have an associated scene 
1683						if ( pSkeleton )
1684						{
1685							daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
1686							if ( pSkeletonRootNode )
1687							{
1688								rootNode = true;
1689							}
1690							else 
1691							{
1692								skeletonWithNoRootNode = true;
1693							}
1694
1695						}
1696						if ( !pSkeleton || !rootNode )
1697						{
1698							daeElement* pScene = root->getDescendant("visual_scene");
1699							if ( !pScene )
1700							{
1701								llwarns<<"No visual scene - unable to parse bone offsets "<<llendl;
1702								missingSkeletonOrScene = true;
1703							}
1704							else
1705							{
1706								//Get the children at this level
1707								daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
1708								S32 childCount = children.getCount();
1709								
1710								//Process any children that are joints
1711								//Not all children are joints, some code be ambient lights, cameras, geometry etc..
1712								for (S32 i = 0; i < childCount; ++i)
1713								{
1714									domNode* pNode = daeSafeCast<domNode>(children[i]);
1715									if ( isNodeAJoint( pNode ) )
1716									{
1717										processJointNode( pNode, mJointList );
1718									}
1719								}
1720							}
1721						}
1722						else
1723							//Has Skeleton
1724						{
1725							//Get the root node of the skeleton
1726							daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
1727							if ( pSkeletonRootNode )
1728							{
1729								//Once we have the root node - start acccessing it's joint components
1730								const int jointCnt = mJointMap.size();
1731								std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
1732								
1733								//Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
1734								for ( int i=0; i<jointCnt; ++i, ++jointIt )
1735								{
1736									//Build a joint for the resolver to work with
1737									char str[64]={0};
1738									sprintf(str,"./%s",(*jointIt).first.c_str() );
1739									//llwarns<<"Joint "<< str <<llendl;
1740									
1741									//Setup the resolver
1742                                    daeSIDResolver resolver( p

Large files files are truncated, but you can click here to view the full file