PageRenderTime 1471ms CodeModel.GetById 221ms app.highlight 1016ms RepoModel.GetById 121ms app.codeStats 1ms

/indra/newview/llmeshrepository.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2581 lines | 2011 code | 444 blank | 126 comment | 336 complexity | 8ee4dde486a2ada7ec4f722c201b0648 MD5 | raw file

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

   1/** 
   2 * @file llmeshrepository.cpp
   3 * @brief Mesh repository implementation.
   4 *
   5 * $LicenseInfo:firstyear=2005&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#include "apr_pools.h"
  30#include "apr_dso.h"
  31#include "llhttpstatuscodes.h"
  32#include "llmeshrepository.h"
  33
  34#include "llagent.h"
  35#include "llappviewer.h"
  36#include "llbufferstream.h"
  37#include "llcallbacklist.h"
  38#include "llcurl.h"
  39#include "lldatapacker.h"
  40#include "llfloatermodelpreview.h"
  41#include "llfloaterperms.h"
  42#include "lleconomy.h"
  43#include "llimagej2c.h"
  44#include "llhost.h"
  45#include "llnotificationsutil.h"
  46#include "llsd.h"
  47#include "llsdutil_math.h"
  48#include "llsdserialize.h"
  49#include "llthread.h"
  50#include "llvfile.h"
  51#include "llviewercontrol.h"
  52#include "llviewerinventory.h"
  53#include "llviewermenufile.h"
  54#include "llviewerobjectlist.h"
  55#include "llviewerregion.h"
  56#include "llviewertexturelist.h"
  57#include "llvolume.h"
  58#include "llvolumemgr.h"
  59#include "llvovolume.h"
  60#include "llworld.h"
  61#include "material_codes.h"
  62#include "pipeline.h"
  63#include "llinventorymodel.h"
  64#include "llfoldertype.h"
  65#include "llviewerparcelmgr.h"
  66#include "lluploadfloaterobservers.h"
  67
  68#include "boost/lexical_cast.hpp"
  69
  70#ifndef LL_WINDOWS
  71#include "netdb.h"
  72#endif
  73
  74#include <queue>
  75
  76LLMeshRepository gMeshRepo;
  77
  78const U32 MAX_MESH_REQUESTS_PER_SECOND = 100;
  79
  80// Maximum mesh version to support.  Three least significant digits are reserved for the minor version, 
  81// with major version changes indicating a format change that is not backwards compatible and should not
  82// be parsed by viewers that don't specifically support that version. For example, if the integer "1" is 
  83// present, the version is 0.001. A viewer that can parse version 0.001 can also parse versions up to 0.999, 
  84// but not 1.0 (integer 1000).
  85// See wiki at https://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format
  86const S32 MAX_MESH_VERSION = 999;
  87
  88U32 LLMeshRepository::sBytesReceived = 0;
  89U32 LLMeshRepository::sHTTPRequestCount = 0;
  90U32 LLMeshRepository::sHTTPRetryCount = 0;
  91U32 LLMeshRepository::sCacheBytesRead = 0;
  92U32 LLMeshRepository::sCacheBytesWritten = 0;
  93U32 LLMeshRepository::sPeakKbps = 0;
  94	
  95
  96const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5;
  97
  98static S32 dump_num = 0;
  99std::string make_dump_name(std::string prefix, S32 num)
 100{
 101	return prefix + boost::lexical_cast<std::string>(num) + std::string(".xml");
 102	
 103}
 104void dump_llsd_to_file(const LLSD& content, std::string filename);
 105LLSD llsd_from_file(std::string filename);
 106
 107std::string header_lod[] = 
 108{
 109	"lowest_lod",
 110	"low_lod",
 111	"medium_lod",
 112	"high_lod"
 113};
 114
 115
 116//get the number of bytes resident in memory for given volume
 117U32 get_volume_memory_size(const LLVolume* volume)
 118{
 119	U32 indices = 0;
 120	U32 vertices = 0;
 121
 122	for (U32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 123	{
 124		const LLVolumeFace& face = volume->getVolumeFace(i);
 125		indices += face.mNumIndices;
 126		vertices += face.mNumVertices;
 127	}
 128
 129
 130	return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces();
 131}
 132
 133void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f)
 134{
 135	res.mPositions.clear();
 136	res.mNormals.clear();
 137	
 138	const F32* v = mesh.mVertexBase;
 139
 140	if (mesh.mIndexType == LLCDMeshData::INT_16)
 141	{
 142		U16* idx = (U16*) mesh.mIndexBase;
 143		for (S32 j = 0; j < mesh.mNumTriangles; ++j)
 144		{ 
 145			F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes);
 146			F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes);
 147			F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes);
 148
 149			idx = (U16*) (((U8*)idx)+mesh.mIndexStrideBytes);
 150			
 151			LLVector3 v0(mp0);
 152			LLVector3 v1(mp1);
 153			LLVector3 v2(mp2);
 154
 155			LLVector3 n = (v1-v0)%(v2-v0);
 156			n.normalize();
 157
 158			res.mPositions.push_back(v0*scale);
 159			res.mPositions.push_back(v1*scale);
 160			res.mPositions.push_back(v2*scale);
 161
 162			res.mNormals.push_back(n);
 163			res.mNormals.push_back(n);
 164			res.mNormals.push_back(n);			
 165		}
 166	}
 167	else
 168	{
 169		U32* idx = (U32*) mesh.mIndexBase;
 170		for (S32 j = 0; j < mesh.mNumTriangles; ++j)
 171		{ 
 172			F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes);
 173			F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes);
 174			F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes);
 175
 176			idx = (U32*) (((U8*)idx)+mesh.mIndexStrideBytes);
 177			
 178			LLVector3 v0(mp0);
 179			LLVector3 v1(mp1);
 180			LLVector3 v2(mp2);
 181
 182			LLVector3 n = (v1-v0)%(v2-v0);
 183			n.normalize();
 184
 185			res.mPositions.push_back(v0*scale);
 186			res.mPositions.push_back(v1*scale);
 187			res.mPositions.push_back(v2*scale);
 188
 189			res.mNormals.push_back(n);
 190			res.mNormals.push_back(n);
 191			res.mNormals.push_back(n);			
 192		}
 193	}
 194}
 195
 196S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
 197S32 LLMeshRepoThread::sActiveLODRequests = 0;
 198U32	LLMeshRepoThread::sMaxConcurrentRequests = 1;
 199
 200class LLMeshHeaderResponder : public LLCurl::Responder
 201{
 202public:
 203	LLVolumeParams mMeshParams;
 204	
 205	LLMeshHeaderResponder(const LLVolumeParams& mesh_params)
 206		: mMeshParams(mesh_params)
 207	{
 208	}
 209
 210	virtual void completedRaw(U32 status, const std::string& reason,
 211							  const LLChannelDescriptors& channels,
 212							  const LLIOPipe::buffer_ptr_t& buffer);
 213
 214};
 215
 216class LLMeshLODResponder : public LLCurl::Responder
 217{
 218public:
 219	LLVolumeParams mMeshParams;
 220	S32 mLOD;
 221	U32 mRequestedBytes;
 222	U32 mOffset;
 223
 224	LLMeshLODResponder(const LLVolumeParams& mesh_params, S32 lod, U32 offset, U32 requested_bytes)
 225		: mMeshParams(mesh_params), mLOD(lod), mOffset(offset), mRequestedBytes(requested_bytes)
 226	{
 227	}
 228
 229	virtual void completedRaw(U32 status, const std::string& reason,
 230							  const LLChannelDescriptors& channels,
 231							  const LLIOPipe::buffer_ptr_t& buffer);
 232
 233};
 234
 235class LLMeshSkinInfoResponder : public LLCurl::Responder
 236{
 237public:
 238	LLUUID mMeshID;
 239	U32 mRequestedBytes;
 240	U32 mOffset;
 241
 242	LLMeshSkinInfoResponder(const LLUUID& id, U32 offset, U32 size)
 243		: mMeshID(id), mRequestedBytes(size), mOffset(offset)
 244	{
 245	}
 246
 247	virtual void completedRaw(U32 status, const std::string& reason,
 248							  const LLChannelDescriptors& channels,
 249							  const LLIOPipe::buffer_ptr_t& buffer);
 250
 251};
 252
 253class LLMeshDecompositionResponder : public LLCurl::Responder
 254{
 255public:
 256	LLUUID mMeshID;
 257	U32 mRequestedBytes;
 258	U32 mOffset;
 259
 260	LLMeshDecompositionResponder(const LLUUID& id, U32 offset, U32 size)
 261		: mMeshID(id), mRequestedBytes(size), mOffset(offset)
 262	{
 263	}
 264
 265	virtual void completedRaw(U32 status, const std::string& reason,
 266							  const LLChannelDescriptors& channels,
 267							  const LLIOPipe::buffer_ptr_t& buffer);
 268
 269};
 270
 271class LLMeshPhysicsShapeResponder : public LLCurl::Responder
 272{
 273public:
 274	LLUUID mMeshID;
 275	U32 mRequestedBytes;
 276	U32 mOffset;
 277
 278	LLMeshPhysicsShapeResponder(const LLUUID& id, U32 offset, U32 size)
 279		: mMeshID(id), mRequestedBytes(size), mOffset(offset)
 280	{
 281	}
 282
 283	virtual void completedRaw(U32 status, const std::string& reason,
 284							  const LLChannelDescriptors& channels,
 285							  const LLIOPipe::buffer_ptr_t& buffer);
 286
 287};
 288
 289void log_upload_error(S32 status, const LLSD& content, std::string stage, std::string model_name)
 290{
 291	// Add notification popup.
 292	LLSD args;
 293	std::string message = content["error"]["message"];
 294	std::string identifier = content["error"]["identifier"];
 295	args["MESSAGE"] = message;
 296	args["IDENTIFIER"] = identifier;
 297	args["LABEL"] = model_name;
 298	gMeshRepo.uploadError(args);
 299
 300	// Log details.
 301	llwarns << "stage: " << stage << " http status: " << status << llendl;
 302	if (content.has("error"))
 303	{
 304		const LLSD& err = content["error"];
 305		llwarns << "err: " << err << llendl;
 306		llwarns << "mesh upload failed, stage '" << stage
 307				<< "' error '" << err["error"].asString()
 308				<< "', message '" << err["message"].asString()
 309				<< "', id '" << err["identifier"].asString()
 310				<< "'" << llendl;
 311		if (err.has("errors"))
 312		{
 313			S32 error_num = 0;
 314			const LLSD& err_list = err["errors"];
 315			for (LLSD::array_const_iterator it = err_list.beginArray();
 316				 it != err_list.endArray();
 317				 ++it)
 318			{
 319				const LLSD& err_entry = *it;
 320				llwarns << "error[" << error_num << "]:" << llendl;
 321				for (LLSD::map_const_iterator map_it = err_entry.beginMap();
 322					 map_it != err_entry.endMap();
 323					 ++map_it)
 324				{
 325					llwarns << "\t" << map_it->first << ": "
 326							<< map_it->second << llendl;
 327				}
 328				error_num++;
 329			}
 330		}
 331	}
 332	else
 333	{
 334		llwarns << "bad mesh, no error information available" << llendl;
 335	}
 336}
 337
 338class LLWholeModelFeeResponder: public LLCurl::Responder
 339{
 340	LLMeshUploadThread* mThread;
 341	LLSD mModelData;
 342	LLHandle<LLWholeModelFeeObserver> mObserverHandle;
 343public:
 344	LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelFeeObserver> observer_handle):
 345		mThread(thread),
 346		mModelData(model_data),
 347		mObserverHandle(observer_handle)
 348	{
 349	}
 350	virtual void completed(U32 status,
 351						   const std::string& reason,
 352						   const LLSD& content)
 353	{
 354		LLSD cc = content;
 355		if (gSavedSettings.getS32("MeshUploadFakeErrors")&1)
 356		{
 357			cc = llsd_from_file("fake_upload_error.xml");
 358		}
 359			
 360		mThread->mPendingUploads--;
 361		dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num));
 362
 363		LLWholeModelFeeObserver* observer = mObserverHandle.get();
 364
 365		if (isGoodStatus(status) &&
 366			cc["state"].asString() == "upload")
 367		{
 368			mThread->mWholeModelUploadURL = cc["uploader"].asString();
 369
 370			if (observer)
 371			{
 372				cc["data"]["upload_price"] = cc["upload_price"];
 373				observer->onModelPhysicsFeeReceived(cc["data"], mThread->mWholeModelUploadURL);
 374			}
 375		}
 376		else
 377		{
 378			llwarns << "fee request failed" << llendl;
 379			log_upload_error(status,cc,"fee",mModelData["name"]);
 380			mThread->mWholeModelUploadURL = "";
 381
 382			if (observer)
 383			{
 384				observer->setModelPhysicsFeeErrorStatus(status, reason);
 385			}
 386		}
 387	}
 388
 389};
 390
 391class LLWholeModelUploadResponder: public LLCurl::Responder
 392{
 393	LLMeshUploadThread* mThread;
 394	LLSD mModelData;
 395	LLHandle<LLWholeModelUploadObserver> mObserverHandle;
 396	
 397public:
 398	LLWholeModelUploadResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelUploadObserver> observer_handle):
 399		mThread(thread),
 400		mModelData(model_data),
 401		mObserverHandle(observer_handle)
 402	{
 403	}
 404	virtual void completed(U32 status,
 405						   const std::string& reason,
 406						   const LLSD& content)
 407	{
 408		LLSD cc = content;
 409		if (gSavedSettings.getS32("MeshUploadFakeErrors")&2)
 410		{
 411			cc = llsd_from_file("fake_upload_error.xml");
 412		}
 413
 414		mThread->mPendingUploads--;
 415		dump_llsd_to_file(cc,make_dump_name("whole_model_upload_response_",dump_num));
 416		
 417		LLWholeModelUploadObserver* observer = mObserverHandle.get();
 418
 419		// requested "mesh" asset type isn't actually the type
 420		// of the resultant object, fix it up here.
 421		if (isGoodStatus(status) &&
 422			cc["state"].asString() == "complete")
 423		{
 424			mModelData["asset_type"] = "object";
 425			gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mModelData,cc));
 426
 427			if (observer)
 428			{
 429				doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadSuccess, observer));
 430			}
 431		}
 432		else
 433		{
 434			llwarns << "upload failed" << llendl;
 435			std::string model_name = mModelData["name"].asString();
 436			log_upload_error(status,cc,"upload",model_name);
 437
 438			if (observer)
 439			{
 440				doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadFailure, observer));
 441			}
 442		}
 443	}
 444};
 445
 446LLMeshRepoThread::LLMeshRepoThread()
 447: LLThread("mesh repo") 
 448{ 
 449	mWaiting = false;
 450	mMutex = new LLMutex(NULL);
 451	mHeaderMutex = new LLMutex(NULL);
 452	mSignal = new LLCondition(NULL);
 453}
 454
 455LLMeshRepoThread::~LLMeshRepoThread()
 456{
 457	delete mMutex;
 458	mMutex = NULL;
 459	delete mHeaderMutex;
 460	mHeaderMutex = NULL;
 461	delete mSignal;
 462	mSignal = NULL;
 463}
 464
 465void LLMeshRepoThread::run()
 466{
 467	mCurlRequest = new LLCurlRequest();
 468	LLCDResult res = LLConvexDecomposition::initThread();
 469	if (res != LLCD_OK)
 470	{
 471		llwarns << "convex decomposition unable to be loaded" << llendl;
 472	}
 473
 474	while (!LLApp::isQuitting())
 475	{
 476		mWaiting = true;
 477		mSignal->wait();
 478		mWaiting = false;
 479
 480		if (!LLApp::isQuitting())
 481		{
 482			static U32 count = 0;
 483
 484			static F32 last_hundred = gFrameTimeSeconds;
 485
 486			if (gFrameTimeSeconds - last_hundred > 1.f)
 487			{ //a second has gone by, clear count
 488				last_hundred = gFrameTimeSeconds;
 489				count = 0;	
 490			}
 491
 492			// NOTE: throttling intentionally favors LOD requests over header requests
 493			
 494			while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < sMaxConcurrentRequests)
 495			{
 496				{
 497					mMutex->lock();
 498					LODRequest req = mLODReqQ.front();
 499					mLODReqQ.pop();
 500					mMutex->unlock();
 501					if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit
 502					{
 503						mMutex->lock();
 504						mLODReqQ.push(req) ; 
 505						mMutex->unlock();
 506					}
 507				}
 508			}
 509
 510			while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < sMaxConcurrentRequests)
 511			{
 512				{
 513					mMutex->lock();
 514					HeaderRequest req = mHeaderReqQ.front();
 515					mHeaderReqQ.pop();
 516					mMutex->unlock();
 517					if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit
 518					{
 519						mMutex->lock();
 520						mHeaderReqQ.push(req) ;
 521						mMutex->unlock();
 522					}
 523				}
 524			}
 525
 526			{ //mSkinRequests is protected by mSignal
 527				std::set<LLUUID> incomplete;
 528				for (std::set<LLUUID>::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter)
 529				{
 530					LLUUID mesh_id = *iter;
 531					if (!fetchMeshSkinInfo(mesh_id))
 532					{
 533						incomplete.insert(mesh_id);
 534					}
 535				}
 536				mSkinRequests = incomplete;
 537			}
 538
 539			{ //mDecompositionRequests is protected by mSignal
 540				std::set<LLUUID> incomplete;
 541				for (std::set<LLUUID>::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter)
 542				{
 543					LLUUID mesh_id = *iter;
 544					if (!fetchMeshDecomposition(mesh_id))
 545					{
 546						incomplete.insert(mesh_id);
 547					}
 548				}
 549				mDecompositionRequests = incomplete;
 550			}
 551
 552			{ //mPhysicsShapeRequests is protected by mSignal
 553				std::set<LLUUID> incomplete;
 554				for (std::set<LLUUID>::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter)
 555				{
 556					LLUUID mesh_id = *iter;
 557					if (!fetchMeshPhysicsShape(mesh_id))
 558					{
 559						incomplete.insert(mesh_id);
 560					}
 561				}
 562				mPhysicsShapeRequests = incomplete;
 563			}
 564
 565			mCurlRequest->process();
 566		}
 567	}
 568	
 569	if (mSignal->isLocked())
 570	{ //make sure to let go of the mutex associated with the given signal before shutting down
 571		mSignal->unlock();
 572	}
 573
 574	res = LLConvexDecomposition::quitThread();
 575	if (res != LLCD_OK)
 576	{
 577		llwarns << "convex decomposition unable to be quit" << llendl;
 578	}
 579
 580	delete mCurlRequest;
 581	mCurlRequest = NULL;
 582}
 583
 584void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)
 585{ //protected by mSignal, no locking needed here
 586	mSkinRequests.insert(mesh_id);
 587}
 588
 589void LLMeshRepoThread::loadMeshDecomposition(const LLUUID& mesh_id)
 590{ //protected by mSignal, no locking needed here
 591	mDecompositionRequests.insert(mesh_id);
 592}
 593
 594void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id)
 595{ //protected by mSignal, no locking needed here
 596	mPhysicsShapeRequests.insert(mesh_id);
 597}
 598
 599
 600void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
 601{ //protected by mSignal, no locking needed here
 602
 603	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
 604	if (iter != mMeshHeader.end())
 605	{ //if we have the header, request LOD byte range
 606		LODRequest req(mesh_params, lod);
 607		{
 608			LLMutexLock lock(mMutex);
 609			mLODReqQ.push(req);
 610		}
 611	}
 612	else
 613	{ 
 614		HeaderRequest req(mesh_params);
 615		
 616		pending_lod_map::iterator pending = mPendingLOD.find(mesh_params);
 617
 618		if (pending != mPendingLOD.end())
 619		{ //append this lod request to existing header request
 620			pending->second.push_back(lod);
 621			llassert(pending->second.size() <= LLModel::NUM_LODS)
 622		}
 623		else
 624		{ //if no header request is pending, fetch header
 625			LLMutexLock lock(mMutex);
 626			mHeaderReqQ.push(req);
 627			mPendingLOD[mesh_params].push_back(lod);
 628		}
 629	}
 630}
 631
 632//static 
 633std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
 634{
 635	std::string http_url;
 636	
 637	if (gAgent.getRegion())
 638	{
 639		http_url = gMeshRepo.mGetMeshCapability; 
 640	}
 641
 642	if (!http_url.empty())
 643	{
 644		http_url += "/?mesh_id=";
 645		http_url += mesh_id.asString().c_str();
 646	}
 647	else
 648	{
 649		llwarns << "Current region does not have GetMesh capability!  Cannot load " << mesh_id << ".mesh" << llendl;
 650	}
 651
 652	return http_url;
 653}
 654
 655bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
 656{ //protected by mMutex
 657	mHeaderMutex->lock();
 658
 659	if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
 660	{ //we have no header info for this mesh, do nothing
 661		mHeaderMutex->unlock();
 662		return false;
 663	}
 664
 665	bool ret = true ;
 666	U32 header_size = mMeshHeaderSize[mesh_id];
 667	
 668	if (header_size > 0)
 669	{
 670		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 671		S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger();
 672		S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger();
 673
 674		mHeaderMutex->unlock();
 675
 676		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 677		{
 678			//check VFS for mesh skin info
 679			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
 680			if (file.getSize() >= offset+size)
 681			{				
 682				LLMeshRepository::sCacheBytesRead += size;
 683				file.seek(offset);
 684				U8* buffer = new U8[size];
 685				file.read(buffer, size);
 686
 687				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 688				bool zero = true;
 689				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 690				{
 691					zero = buffer[i] > 0 ? false : true;
 692				}
 693
 694				if (!zero)
 695				{ //attempt to parse
 696					if (skinInfoReceived(mesh_id, buffer, size))
 697					{						
 698						delete[] buffer;
 699						return true;
 700					}
 701				}
 702
 703				delete[] buffer;
 704			}
 705
 706			//reading from VFS failed for whatever reason, fetch from sim
 707			std::vector<std::string> headers;
 708			headers.push_back("Accept: application/octet-stream");
 709
 710			std::string http_url = constructUrl(mesh_id);
 711			if (!http_url.empty())
 712			{				
 713				ret = mCurlRequest->getByteRange(http_url, headers, offset, size,
 714										   new LLMeshSkinInfoResponder(mesh_id, offset, size));
 715				if(ret)
 716				{
 717					++sActiveLODRequests;
 718					LLMeshRepository::sHTTPRequestCount++;
 719				}
 720			}
 721		}
 722	}
 723	else
 724	{	
 725		mHeaderMutex->unlock();
 726	}
 727
 728	//early out was not hit, effectively fetched
 729	return ret;
 730}
 731
 732bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
 733{ //protected by mMutex
 734	mHeaderMutex->lock();
 735
 736	if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
 737	{ //we have no header info for this mesh, do nothing
 738		mHeaderMutex->unlock();
 739		return false;
 740	}
 741
 742	U32 header_size = mMeshHeaderSize[mesh_id];
 743	bool ret = true ;
 744	
 745	if (header_size > 0)
 746	{
 747		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 748		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
 749		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
 750
 751		mHeaderMutex->unlock();
 752
 753		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 754		{
 755			//check VFS for mesh skin info
 756			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
 757			if (file.getSize() >= offset+size)
 758			{
 759				LLMeshRepository::sCacheBytesRead += size;
 760
 761				file.seek(offset);
 762				U8* buffer = new U8[size];
 763				file.read(buffer, size);
 764
 765				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 766				bool zero = true;
 767				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 768				{
 769					zero = buffer[i] > 0 ? false : true;
 770				}
 771
 772				if (!zero)
 773				{ //attempt to parse
 774					if (decompositionReceived(mesh_id, buffer, size))
 775					{
 776						delete[] buffer;
 777						return true;
 778					}
 779				}
 780
 781				delete[] buffer;
 782			}
 783
 784			//reading from VFS failed for whatever reason, fetch from sim
 785			std::vector<std::string> headers;
 786			headers.push_back("Accept: application/octet-stream");
 787
 788			std::string http_url = constructUrl(mesh_id);
 789			if (!http_url.empty())
 790			{				
 791				ret = mCurlRequest->getByteRange(http_url, headers, offset, size,
 792										   new LLMeshDecompositionResponder(mesh_id, offset, size));
 793				if(ret)
 794				{
 795					++sActiveLODRequests;
 796					LLMeshRepository::sHTTPRequestCount++;
 797				}
 798			}
 799		}
 800	}
 801	else
 802	{	
 803		mHeaderMutex->unlock();
 804	}
 805
 806	//early out was not hit, effectively fetched
 807	return ret;
 808}
 809
 810bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 811{ //protected by mMutex
 812	mHeaderMutex->lock();
 813
 814	if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
 815	{ //we have no header info for this mesh, do nothing
 816		mHeaderMutex->unlock();
 817		return false;
 818	}
 819
 820	U32 header_size = mMeshHeaderSize[mesh_id];
 821	bool ret = true ;
 822
 823	if (header_size > 0)
 824	{
 825		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 826		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
 827		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
 828
 829		mHeaderMutex->unlock();
 830
 831		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 832		{
 833			//check VFS for mesh physics shape info
 834			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
 835			if (file.getSize() >= offset+size)
 836			{
 837				LLMeshRepository::sCacheBytesRead += size;
 838				file.seek(offset);
 839				U8* buffer = new U8[size];
 840				file.read(buffer, size);
 841
 842				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 843				bool zero = true;
 844				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 845				{
 846					zero = buffer[i] > 0 ? false : true;
 847				}
 848
 849				if (!zero)
 850				{ //attempt to parse
 851					if (physicsShapeReceived(mesh_id, buffer, size))
 852					{
 853						delete[] buffer;
 854						return true;
 855					}
 856				}
 857
 858				delete[] buffer;
 859			}
 860
 861			//reading from VFS failed for whatever reason, fetch from sim
 862			std::vector<std::string> headers;
 863			headers.push_back("Accept: application/octet-stream");
 864
 865			std::string http_url = constructUrl(mesh_id);
 866			if (!http_url.empty())
 867			{				
 868				ret = mCurlRequest->getByteRange(http_url, headers, offset, size,
 869										   new LLMeshPhysicsShapeResponder(mesh_id, offset, size));
 870
 871				if(ret)
 872				{
 873					++sActiveLODRequests;
 874					LLMeshRepository::sHTTPRequestCount++;
 875				}
 876			}
 877		}
 878		else
 879		{ //no physics shape whatsoever, report back NULL
 880			physicsShapeReceived(mesh_id, NULL, 0);
 881		}
 882	}
 883	else
 884	{	
 885		mHeaderMutex->unlock();
 886	}
 887
 888	//early out was not hit, effectively fetched
 889	return ret;
 890}
 891
 892//return false if failed to get header
 893bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count)
 894{
 895	{
 896		//look for mesh in asset in vfs
 897		LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH);
 898			
 899		S32 size = file.getSize();
 900
 901		if (size > 0)
 902		{ //NOTE -- if the header size is ever more than 4KB, this will break
 903			U8 buffer[4096];
 904			S32 bytes = llmin(size, 4096);
 905			LLMeshRepository::sCacheBytesRead += bytes;	
 906			file.read(buffer, bytes);
 907			if (headerReceived(mesh_params, buffer, bytes))
 908			{ //did not do an HTTP request, return false
 909				return true;
 910			}
 911		}
 912	}
 913
 914	//either cache entry doesn't exist or is corrupt, request header from simulator	
 915	bool retval = true ;
 916	std::vector<std::string> headers;
 917	headers.push_back("Accept: application/octet-stream");
 918
 919	std::string http_url = constructUrl(mesh_params.getSculptID());
 920	if (!http_url.empty())
 921	{
 922		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits
 923		//within the first 4KB
 924		//NOTE -- this will break of headers ever exceed 4KB		
 925		retval = mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params));
 926		if(retval)
 927		{
 928			++sActiveHeaderRequests;
 929			LLMeshRepository::sHTTPRequestCount++;
 930		}
 931		count++;
 932	}
 933
 934	return retval;
 935}
 936
 937//return false if failed to get mesh lod.
 938bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count)
 939{ //protected by mMutex
 940	mHeaderMutex->lock();
 941
 942	bool retval = true;
 943
 944	LLUUID mesh_id = mesh_params.getSculptID();
 945	
 946	U32 header_size = mMeshHeaderSize[mesh_id];
 947
 948	if (header_size > 0)
 949	{
 950		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
 951		S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger();
 952		S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger();
 953		mHeaderMutex->unlock();
 954				
 955		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
 956		{
 957
 958			//check VFS for mesh asset
 959			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
 960			if (file.getSize() >= offset+size)
 961			{
 962				LLMeshRepository::sCacheBytesRead += size;
 963				file.seek(offset);
 964				U8* buffer = new U8[size];
 965				file.read(buffer, size);
 966
 967				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
 968				bool zero = true;
 969				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
 970				{
 971					zero = buffer[i] > 0 ? false : true;
 972				}
 973
 974				if (!zero)
 975				{ //attempt to parse
 976					if (lodReceived(mesh_params, lod, buffer, size))
 977					{
 978						delete[] buffer;
 979						return true;
 980					}
 981				}
 982
 983				delete[] buffer;
 984			}
 985
 986			//reading from VFS failed for whatever reason, fetch from sim
 987			std::vector<std::string> headers;
 988			headers.push_back("Accept: application/octet-stream");
 989
 990			std::string http_url = constructUrl(mesh_id);
 991			if (!http_url.empty())
 992			{				
 993				retval = mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
 994										   new LLMeshLODResponder(mesh_params, lod, offset, size));
 995
 996				if(retval)
 997				{
 998					++sActiveLODRequests;				
 999					LLMeshRepository::sHTTPRequestCount++;
1000				}
1001				count++;
1002			}
1003			else
1004			{
1005				mUnavailableQ.push(LODRequest(mesh_params, lod));
1006			}
1007		}
1008		else
1009		{
1010			mUnavailableQ.push(LODRequest(mesh_params, lod));
1011		}
1012	}
1013	else
1014	{
1015		mHeaderMutex->unlock();
1016	}
1017
1018	return retval;
1019}
1020
1021bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size)
1022{
1023	LLSD header;
1024	
1025	U32 header_size = 0;
1026	if (data_size > 0)
1027	{
1028		std::string res_str((char*) data, data_size);
1029
1030		std::string deprecated_header("<? LLSD/Binary ?>");
1031
1032		if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
1033		{
1034			res_str = res_str.substr(deprecated_header.size()+1, data_size);
1035			header_size = deprecated_header.size()+1;
1036		}
1037		data_size = res_str.size();
1038
1039		std::istringstream stream(res_str);
1040
1041		if (!LLSDSerialize::fromBinary(header, stream, data_size))
1042		{
1043			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
1044			return false;
1045		}
1046
1047		header_size += stream.tellg();
1048	}
1049	else
1050	{
1051		llinfos
1052			<< "Marking header as non-existent, will not retry." << llendl;
1053		header["404"] = 1;
1054	}
1055
1056	{
1057		LLUUID mesh_id = mesh_params.getSculptID();
1058		
1059		mHeaderMutex->lock();
1060		mMeshHeaderSize[mesh_id] = header_size;
1061		mMeshHeader[mesh_id] = header;
1062		mHeaderMutex->unlock();
1063
1064		//check for pending requests
1065		pending_lod_map::iterator iter = mPendingLOD.find(mesh_params);
1066		if (iter != mPendingLOD.end())
1067		{
1068			LLMutexLock lock(mMutex);
1069			for (U32 i = 0; i < iter->second.size(); ++i)
1070			{
1071				LODRequest req(mesh_params, iter->second[i]);
1072				mLODReqQ.push(req);
1073			}
1074		}
1075		mPendingLOD.erase(iter);
1076	}
1077
1078	return true;
1079}
1080
1081bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)
1082{
1083	LLVolume* volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
1084	std::string mesh_string((char*) data, data_size);
1085	std::istringstream stream(mesh_string);
1086
1087	if (volume->unpackVolumeFaces(stream, data_size))
1088	{
1089		LoadedMesh mesh(volume, mesh_params, lod);
1090		if (volume->getNumFaces() > 0)
1091		{
1092			LLMutexLock lock(mMutex);
1093			mLoadedQ.push(mesh);
1094			return true;
1095		}
1096	}
1097
1098	return false;
1099}
1100
1101bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
1102{
1103	LLSD skin;
1104
1105	if (data_size > 0)
1106	{
1107		std::string res_str((char*) data, data_size);
1108
1109		std::istringstream stream(res_str);
1110
1111		if (!unzip_llsd(skin, stream, data_size))
1112		{
1113			llwarns << "Mesh skin info parse error.  Not a valid mesh asset!" << llendl;
1114			return false;
1115		}
1116	}
1117	
1118	{
1119		LLMeshSkinInfo info(skin);
1120		info.mMeshID = mesh_id;
1121
1122		//llinfos<<"info pelvis offset"<<info.mPelvisOffset<<llendl;
1123		mSkinInfoQ.push(info);
1124	}
1125
1126	return true;
1127}
1128
1129bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
1130{
1131	LLSD decomp;
1132
1133	if (data_size > 0)
1134	{ 
1135		std::string res_str((char*) data, data_size);
1136
1137		std::istringstream stream(res_str);
1138
1139		if (!unzip_llsd(decomp, stream, data_size))
1140		{
1141			llwarns << "Mesh decomposition parse error.  Not a valid mesh asset!" << llendl;
1142			return false;
1143		}
1144	}
1145	
1146	{
1147		LLModel::Decomposition* d = new LLModel::Decomposition(decomp);
1148		d->mMeshID = mesh_id;
1149		mDecompositionQ.push(d);
1150	}
1151
1152	return true;
1153}
1154
1155bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
1156{
1157	LLSD physics_shape;
1158
1159	LLModel::Decomposition* d = new LLModel::Decomposition();
1160	d->mMeshID = mesh_id;
1161
1162	if (data == NULL)
1163	{ //no data, no physics shape exists
1164		d->mPhysicsShapeMesh.clear();
1165	}
1166	else
1167	{
1168		LLVolumeParams volume_params;
1169		volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
1170		volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH);
1171		LLPointer<LLVolume> volume = new LLVolume(volume_params,0);
1172		std::string mesh_string((char*) data, data_size);
1173		std::istringstream stream(mesh_string);
1174
1175		if (volume->unpackVolumeFaces(stream, data_size))
1176		{
1177			//load volume faces into decomposition buffer
1178			S32 vertex_count = 0;
1179			S32 index_count = 0;
1180
1181			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
1182			{
1183				const LLVolumeFace& face = volume->getVolumeFace(i);
1184				vertex_count += face.mNumVertices;
1185				index_count += face.mNumIndices;
1186			}
1187
1188			d->mPhysicsShapeMesh.clear();
1189
1190			std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
1191			std::vector<LLVector3>& norm = d->mPhysicsShapeMesh.mNormals;
1192
1193			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
1194			{
1195				const LLVolumeFace& face = volume->getVolumeFace(i);
1196			
1197				for (S32 i = 0; i < face.mNumIndices; ++i)
1198				{
1199					U16 idx = face.mIndices[i];
1200
1201					pos.push_back(LLVector3(face.mPositions[idx].getF32ptr()));
1202					norm.push_back(LLVector3(face.mNormals[idx].getF32ptr()));				
1203				}			
1204			}
1205		}
1206	}
1207
1208	mDecompositionQ.push(d);
1209	return true;
1210}
1211
1212LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
1213										bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
1214					   LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
1215: LLThread("mesh upload"),
1216	mDiscarded(FALSE),
1217	mDoUpload(do_upload),
1218	mWholeModelUploadURL(upload_url),
1219	mFeeObserverHandle(fee_observer),
1220	mUploadObserverHandle(upload_observer)
1221{
1222	mInstanceList = data;
1223	mUploadTextures = upload_textures;
1224	mUploadSkin = upload_skin;
1225	mUploadJoints = upload_joints;
1226	mMutex = new LLMutex(NULL);
1227	mCurlRequest = NULL;
1228	mPendingUploads = 0;
1229	mFinished = false;
1230	mOrigin = gAgent.getPositionAgent();
1231	mHost = gAgent.getRegionHost();
1232	
1233	mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory");
1234
1235	mOrigin += gAgent.getAtAxis() * scale.magVec();
1236
1237	mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ;
1238}
1239
1240LLMeshUploadThread::~LLMeshUploadThread()
1241{
1242
1243}
1244
1245LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread)
1246{
1247	mStage = "single_hull";
1248	mModel = mdl;
1249	mDecompID = &mdl->mDecompID;
1250	mBaseModel = base_model;
1251	mThread = thread;
1252	
1253	//copy out positions and indices
1254	assignData(mdl) ;	
1255
1256	mThread->mFinalDecomp = this;
1257	mThread->mPhysicsComplete = false;
1258}
1259
1260void LLMeshUploadThread::DecompRequest::completed()
1261{
1262	if (mThread->mFinalDecomp == this)
1263	{
1264		mThread->mPhysicsComplete = true;
1265	}
1266
1267	llassert(mHull.size() == 1);
1268	
1269	mThread->mHullMap[mBaseModel] = mHull[0];
1270}
1271
1272//called in the main thread.
1273void LLMeshUploadThread::preStart()
1274{
1275	//build map of LLModel refs to instances for callbacks
1276	for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter)
1277	{
1278		mInstance[iter->mModel].push_back(*iter);
1279	}
1280}
1281
1282void LLMeshUploadThread::discard()
1283{
1284	LLMutexLock lock(mMutex) ;
1285	mDiscarded = TRUE ;
1286}
1287
1288BOOL LLMeshUploadThread::isDiscarded()
1289{
1290	LLMutexLock lock(mMutex) ;
1291	return mDiscarded ;
1292}
1293
1294void LLMeshUploadThread::run()
1295{
1296	if (mDoUpload)
1297	{
1298		doWholeModelUpload();
1299	}
1300	else
1301	{
1302		requestWholeModelFee();
1303	}
1304}
1305
1306void dump_llsd_to_file(const LLSD& content, std::string filename)
1307{
1308	if (gSavedSettings.getBOOL("MeshUploadLogXML"))
1309	{
1310		std::ofstream of(filename.c_str());
1311		LLSDSerialize::toPrettyXML(content,of);
1312	}
1313}
1314
1315LLSD llsd_from_file(std::string filename)
1316{
1317	std::ifstream ifs(filename.c_str());
1318	LLSD result;
1319	LLSDSerialize::fromXML(result,ifs);
1320	return result;
1321}
1322
1323void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
1324{
1325	LLSD result;
1326
1327	LLSD res;
1328	result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
1329	result["texture_folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE);
1330	result["asset_type"] = "mesh";
1331	result["inventory_type"] = "object";
1332	result["description"] = "(No Description)";
1333	result["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms());
1334	result["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms());
1335	result["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms());
1336
1337	res["mesh_list"] = LLSD::emptyArray();
1338	res["texture_list"] = LLSD::emptyArray();
1339	res["instance_list"] = LLSD::emptyArray();
1340	S32 mesh_num = 0;
1341	S32 texture_num = 0;
1342	
1343	std::set<LLViewerTexture* > textures;
1344	std::map<LLViewerTexture*,S32> texture_index;
1345
1346	std::map<LLModel*,S32> mesh_index;
1347	std::string model_name;
1348	std::string model_metric;
1349
1350	S32 instance_num = 0;
1351	
1352	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
1353	{
1354		LLMeshUploadData data;
1355		data.mBaseModel = iter->first;
1356		LLModelInstance& first_instance = *(iter->second.begin());
1357		for (S32 i = 0; i < 5; i++)
1358		{
1359			data.mModel[i] = first_instance.mLOD[i];
1360		}
1361
1362		if (mesh_index.find(data.mBaseModel) == mesh_index.end())
1363		{
1364			// Have not seen this model before - create a new mesh_list entry for it.
1365			if (model_name.empty())
1366			{
1367				model_name = data.mBaseModel->getName();
1368			}
1369
1370			if (model_metric.empty())
1371			{
1372				model_metric = data.mBaseModel->getMetric();
1373			}
1374
1375			std::stringstream ostr;
1376			
1377			LLModel::Decomposition& decomp =
1378				data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
1379				data.mModel[LLModel::LOD_PHYSICS]->mPhysics : 
1380				data.mBaseModel->mPhysics;
1381
1382			decomp.mBaseHull = mHullMap[data.mBaseModel];
1383
1384			LLSD mesh_header = LLModel::writeModel(
1385				ostr,  
1386				data.mModel[LLModel::LOD_PHYSICS],
1387				data.mModel[LLModel::LOD_HIGH],
1388				data.mModel[LLModel::LOD_MEDIUM],
1389				data.mModel[LLModel::LOD_LOW],
1390				data.mModel[LLModel::LOD_IMPOSTOR], 
1391				decomp,
1392				mUploadSkin,
1393				mUploadJoints);
1394
1395			data.mAssetData = ostr.str();
1396			std::string str = ostr.str();
1397
1398			res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end()); 
1399			mesh_index[data.mBaseModel] = mesh_num;
1400			mesh_num++;
1401		}
1402
1403		// For all instances that use this model
1404		for (instance_list::iterator instance_iter = iter->second.begin();
1405			 instance_iter != iter->second.end();
1406			 ++instance_iter)
1407		{
1408
1409			LLModelInstance& instance = *instance_iter;
1410		
1411			LLSD instance_entry;
1412		
1413			for (S32 i = 0; i < 5; i++)
1414			{
1415				data.mModel[i] = instance.mLOD[i];
1416			}
1417		
1418			LLVector3 pos, scale;
1419			LLQuaternion rot;
1420			LLMatrix4 transformation = instance.mTransform;
1421			decomposeMeshMatrix(transformation,pos,rot,scale);
1422			instance_entry["position"] = ll_sd_from_vector3(pos);
1423			instance_entry["rotation"] = ll_sd_from_quaternion(rot);
1424			instance_entry["scale"] = ll_sd_from_vector3(scale);
1425		
1426			instance_entry["material"] = LL_MCODE_WOOD;
1427			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
1428			instance_entry["mesh"] = mesh_index[data.mBaseModel];
1429
1430			instance_entry["face_list"] = LLSD::emptyArray();
1431
1432			S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ;
1433			for (S32 face_num = 0; face_num < end; face_num++)
1434			{
1435				LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
1436				LLSD face_entry = LLSD::emptyMap();
1437				LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
1438				
1439				if ((texture != NULL) &&
1440					(textures.find(texture) == textures.end()))
1441				{
1442					textures.insert(texture);
1443				}
1444
1445				std::stringstream texture_str;
1446				if (texture != NULL && include_textures && mUploadTextures)
1447				{
1448					if(texture->hasSavedRawImage())
1449					{											
1450						LLPointer<LLImageJ2C> upload_file =
1451							LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
1452						texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
1453					}
1454				}
1455
1456				if (texture != NULL &&
1457					mUploadTextures &&
1458					texture_index.find(texture) == texture_index.end())
1459				{
1460					texture_index[texture] = texture_num;
1461					std::string str = texture_str.str();
1462					res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
1463					texture_num++;
1464				}
1465
1466				// Subset of TextureEntry fields.
1467				if (texture != NULL && mUploadTextures)
1468				{
1469					face_entry["image"] = texture_index[texture];
1470					face_entry["scales"] = 1.0;
1471					face_entry["scalet"] = 1.0;
1472					face_entry["offsets"] = 0.0;
1473					face_entry["offsett"] = 0.0;
1474					face_entry["imagerot"] = 0.0;
1475				}
1476				face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
1477				face_entry["fullbright"] = material.mFullbright;
1478				instance_entry["face_list"][face_num] = face_entry;
1479		    }
1480
1481			res["instance_list"][instance_num] = instance_entry;
1482			instance_num++;
1483		}
1484	}
1485
1486	if (model_name.empty()) model_name = "mesh model";
1487	result["name"] = model_name;
1488	if (model_metric.empty()) model_metric = "MUT_Unspecified";
1489	res["metric"] = model_metric;
1490	result["asset_resources"] = res;
1491	dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num));
1492
1493	dest = result;
1494}
1495
1496void LLMeshUploadThread::generateHulls()
1497{
1498	bool has_valid_requests = false ;
1499
1500	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
1501	{
1502		LLMeshUploadData data;
1503		data.mBaseModel = iter->first;
1504
1505		LLModelInstance& instance = *(iter->second.begin());
1506
1507		for (S32 i = 0; i < 5; i++)
1508		{
1509			data.mModel[i] = instance.mLOD[i];
1510		}
1511
1512		//queue up models for hull generation
1513		LLModel* physics = NULL;
1514
1515		if (data.mModel[LLModel::LOD_PHYSICS].notNull())
1516		{
1517			physics = data.mModel[LLModel::LOD_PHYSICS];
1518		}
1519		else if (data.mModel[LLModel::LOD_LOW].notNull())
1520		{
1521			physics = data.mModel[LLModel::LOD_LOW];
1522		}
1523		else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
1524		{
1525			physics = data.mModel[LLModel::LOD_MEDIUM];
1526		}
1527		else
1528		{
1529			physics = data.mModel[LLModel::LOD_HIGH];
1530		}
1531
1532		llassert(physics != NULL);
1533
1534		DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
1535		if(request->isValid())
1536		{
1537			gMeshRepo.mDecompThread->submitRequest(request);
1538			has_valid_requests = true ;
1539		}
1540	}
1541		
1542	if(has_valid_requests)
1543	{
1544		while (!mPhysicsComplete)
1545		{
1546			apr_sleep(100);
1547		}
1548	}	
1549}
1550
1551void LLMeshUploadThread::doWholeModelUpload()
1552{
1553	mCurlRequest = new LLCurlRequest();
1554
1555	if (mWholeModelUploadURL.empty())
1556	{
1557		llinfos << "unable to upload, fee request failed" << llendl;
1558	}
1559	else
1560	{
1561		generateHulls();
1562
1563		LLSD full_model_data;
1564		wholeModelToLLSD(full_model_data, true);
1565		LLSD body = full_model_data["asset_resources"];
1566		dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num));
1567		LLCurlRequest::headers_t headers;
1568
1569		{
1570			LLCurl::ResponderPtr responder = new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle) ;
1571
1572			while(!mCurlRequest->post(mWholeModelUploadURL, headers, body, responder, mMeshUploadTimeOut))
1573			{
1574				//sleep for 10ms to prevent eating a whole core
1575				apr_sleep(10000);
1576			}
1577		}
1578
1579		do
1580		{
1581			mCurlRequest->process();
1582			//sleep for 10ms to prevent eating a whole core
1583			apr_sleep(10000);
1584		} while (mCurlRequest->getQueued() > 0);
1585	}
1586
1587	delete mCurlRequest;
1588	mCurlRequest = NULL;
1589
1590	// Currently a no-op.
1591	mFinished = true;
1592}
1593
1594void LLMeshUploadThread::requestWholeModelFee()
1595{
1596	dump_num++;
1597
1598	mCurlRequest = new LLCurlRequest();
1599
1600	generateHulls();
1601
1602	LLSD model_data;
1603	wholeModelToLLSD(model_data,false);
1604	dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num));
1605
1606	mPendingUploads++;
1607	LLCurlRequest::headers_t headers;
1608
1609	{
1610		LLCurl::ResponderPtr responder = new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle) ;
1611		while(!mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, responder, mMeshUploadTimeOut))
1612		{
1613			//sleep for 10ms to prevent eating a whole core
1614			apr_sleep(10000);
1615		}
1616	}
1617
1618	do
1619	{
1620		mCurlRequest->process();
1621		//sleep for 10ms to prevent eating a whole core
1622		apr_sleep(10000);
1623	} while (mCurlRequest->getQueued() > 0);
1624
1625	delete mCurlRequest;
1626	mCurlRequest = NULL;
1627
1628	// Currently a no-op.
1629	mFinished = true;
1630}
1631
1632void LLMeshRepoThread::notifyLoadedMeshes()
1633{
1634	while (!mLoadedQ.empty())
1635	{
1636		mMutex->lock();
1637		LoadedMesh mesh = mLoadedQ.front();
1638		mLoadedQ.pop();
1639		mMutex->unlock();
1640		
1641		if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0)
1642		{
1643			gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume);
1644		}
1645		else
1646		{
1647			gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, 
1648				LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail()));
1649		}
1650	}
1651
1652	while (!mUnavailableQ.empty())
1653	{
1654		mMutex->lock();
1655		LODRequest req = mUnavailableQ.front();
1656		mUnavailableQ.pop();
1657		mMutex->unlock();
1658		
1659		gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
1660	}
1661
1662	while (!mSkinInfoQ.empty())
1663	{
1664		gMeshRepo.notifySkinInfoReceived(mSkinInfoQ.front());
1665		mSkinInfoQ.pop();
1666	}
1667
1668	while (!mDecompositionQ.empty())
1669	{
1670		gMeshRepo.notifyDecompositionReceived(mDecompositionQ.front());
1671		mDecompositionQ.pop();
1672	}
1673}
1674
1675S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod) 
1676{ //only ever called from main thread
1677	LLMutexLock lock(mHeaderMutex);
1678	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
1679
1680	if (iter != mMeshHeader.end())
1681	{
1682		LLSD& header = iter->second;
1683
1684		return LLMeshRepository::getActualMeshLOD(header, lod);
1685	}
1686
1687	return lod;
1688}
1689
1690//static
1691S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
1692{
1693	lod = llclamp(lod, 0, 3);
1694
1695	S32 version = header["version"];
1696
1697	if (header.has("404") || version > MAX_MESH_VERSION)
1698	{
1699		return -1;
1700	}
1701
1702	if (header[header_lod[lod]]["size"].asInteger() > 0)
1703	{
1704		return lod;
1705	}
1706
1707	//search down to find the next available lower lod
1708	for (S32 i = lod-1; i >= 0; --i)
1709	{
1710		if (header[header_lod[i]]["size"].asInteger() > 0)
1711		{
1712			return i;
1713		}
1714	}
1715
1716	//search up to find then ext available higher lod
1717	for (S32 i = lod+1; i < 4; ++i)
1718	{
1719		if (header[header_lod[i]]["size"].asInteger() > 0)
1720		{
1721			return i;
1722		}
1723	}
1724
1725	//header exists and no good lod found, treat as 404
1726	header["404"] = 1;
1727	return -1;
1728}
1729
1730void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
1731{
1732	mThread->mMeshHeader[data.mUUID] = header;
1733
1734	// we cache the mesh for default parameters
1735	LLVolumeParams volume_params;
1736	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
1737	volume_params.setSculptID(data.mUUID, LL_SCULPT_TYPE_MESH);
1738
1739	for (U32 i = 0; i < 4; i++)
1740	{
1741		if (data.mModel[i].notNull())
1742		{
1743			LLPointer<LLVolume> volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i));
1744			volume->copyVolumeFaces(data.mModel[i]);
1745			volume->setMeshAssetLoaded(TRUE);
1746		}
1747	}
1748
1749}
1750
1751void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
1752							  const LLChannelDescriptors& channels,
1753							  const LLIOPipe::buffer_ptr_t& buffer)
1754{
1755
1756	LLMeshRepoThread::sActiveLODRequests--;
1757	S32 data_size = buffer->countAfter(channels.in(), NULL);
1758
1759	if (status < 200 || status > 400)
1760	{
1761		llwarns << status << ": " << reason << llendl;
1762	}
1763
1764	if (data_size < mRequestedBytes)
1765	{
1766		if (status == 499 || status == 503)
1767		{ //timeout or service unavailable, try again
1768			LLMeshRepository::sHTTPRetryCount++;
1769			gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD);
1770		}
1771		else
1772		{
1773			llwarns << "Unhandled status " << status << llendl;
1774		}
1775		return;
1776	}
1777
1778	LLMeshRepository::sBytesReceived += mRequestedBytes;
1779
1780	U8* data = NULL;
1781
1782	if (data_size > 0)
1783	{
1784		data = new U8[data_size];
1785		buffer->readAfter(channels.in(), NULL, data, data_size);
1786	}
1787
1788	if (gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
1789	{
1790		//good fetch from sim, write to VFS for caching
1791		LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
1792
1793		S32 offset = mOffset;
1794		S32 size = mRequestedBytes;
1795
1796		if (file.getSize() >= offset+size)
1797		{
1798			file.seek(offset);
1799			file.write(data, size);
1800			LLMeshRepository::sCacheBytesWritten += size;
1801		}
1802	}
1803
1804	delete [] data;
1805}
1806
1807void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason,
1808							  const LLChannelDescriptors& channels,
1809							  const LLIOPipe::buffer_ptr_t& buffer)
1810{
1811	S32 data_size = buffer->countAfter(channels.in(), NULL);
1812
1813	if (status < 200 || status > 400)
1814	{
1815		llwarns << status << ": " << reason << llendl;
1816	}
1817
1818	if (data_size < mRequestedBytes)
1819	{
1820		if (status == 499 || status == 503)
1821		{ //timeout or service unavailable, try again
1822			LLMeshRepository::sHTTPRetryCount++;
1823			gMeshRepo.mThread->loadMeshSkinInfo(mMeshID);
1824		}
1825		else
1826		{
1827			llwarns << "Unhandled status " << status << llendl;
1828		}
1829		return;
1830	}
1831
1832	LLMeshRepository::sBytesReceived += mRequestedBytes;
1833
1834	U8* data = NULL;
1835
1836	if (data_size > 0)
1837	{
1838		data = new U8[data_size];
1839		buffer->readAfter(channels.in(), NULL, data, data_size);
1840	}
1841
1842	if (gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
1843	{
1844		//good fetch from sim, write to VFS for caching
1845		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
1846
1847		S32 offset = mOffset;
1848		S32 size = mRequestedBytes;
1849
1850		if (file.getSize() >= offset+size)
1851		{
1852			LLMeshRepository::sCacheBytesWritten += size;
1853			file.seek(offset);
1854			file.write(data, size);
1855		}
1856	}
1857
1858	delete [] data;
1859}
1860
1861void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason,
1862							  const LLChannelDescriptors& channels,
1863							  const LLIOPipe::buffer_ptr_t& buffer)
1864{
1865	S32 data_size = buffer->countAfter(channels.in(), NULL);
1866
1867	if (status < 200 || status > 400)
1868	{
1869		llwarns << status << ": " << reason << llendl;
1870	}
1871
1872	if (data_size < mRequestedBytes)
1873	{
1874		if (status == 499 || status == 503)
1875		{ //timeout or service unavailable, try again
1876			LLMeshRepository::sHTTPRetryCount++;
1877			gMeshRepo.mThread->loadMeshDecomposition(mMeshID);
1878		}
1879		else
1880		{
1881			llwarns << "Unhandled status " << status << llendl;
1882		}
1883		return;
1884	}
1885
1886	LLMeshRepository::sBytesReceived += mRequestedBytes;
1887
1888	U8* data = NULL;
1889
1890	if (data_size > 0)
1891	{
1892		data = new U8[data_size];
1893		buffer->readAfter(channels.in(), NULL, data, data_size);
1894	}
1895
1896	if (gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size))
1897	{
1898		//good fetch from sim, write to VFS for caching
1899		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
1900
1901		S32 offset = mOffset;
1902		S32 size = mRequestedBytes;
1903
1904		if (file.getSize() >= offset+size)
1905		{
1906			LLMeshRepository::sCacheBytesWritten += size;
1907			file.seek(offset);
1908			file.write(data, size);
1909		}
1910	}
1911
1912	delete [] data;
1913}
1914
1915void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason,
1916							  const LLChannelDescriptors& channels,
1917							  const LLIOPipe::buffer_ptr_t& buffer)
1918{
1919	S32 data_size = buffer->countAfter(channels.in(), NULL);
1920
1921	if (status < 200 || status > 400)
1922	{
1923		llwarns << status << ": " << reason << llendl;
1924	}
1925
1926	if (data_size < mRequestedBytes)
1927	{
1928		if (status == 499 || status == 503)
1929		{ //timeout or service unavailable, try again
1930			LLMeshRepository::sHTTPRetryCount++;
1931			gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID);
1932		}
1933		else
1934		{
1935			llwarns << "Unhandled status " << status << llendl;
1936		}
1937		return;
1938	}
1939
1940	LLMeshRepository::sBytesReceived += mRequestedBytes;
1941
1942	U8* data = NULL;
1943
1944	if (data_size > 0)
1945	{
1946		data = new U8[data_size];
1947		buffer->readAfter(channels.in(), NULL, data, data_size);
1948	}
1949
1950	if (gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size))
1951	{
1952		//good fetch from sim, write to VFS for caching
1953		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
1954
1955		S32 offset = mOffset;
1956		S32 size = mRequestedBytes;
1957
1958		if (file.getSize() >= offset+size)
1959		{
1960			LLMeshRepository::sCacheBytesWritten += size;
1961			file.seek(offset);
1962			file.write(data, size);
1963		}
1964	}
1965
1966	delete [] data;
1967}
1968
1969void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
1970							  const LLChannelDescriptors& channels,
1971							  const LLIOPipe::buffer_ptr_t& buffer)
1972{
1973	LLMeshRepoThread::sActiveHeaderRequests--;
1974	if (status < 200 || status > 400)
1975	{
1976		//llwarns
1977		//	<< "Header responder failed with status: "
1978		//	<< status << ": " << reason << llendl;
1979
1980		// 503 (service unavailable) or 499 (timeout)
1981		// can be due to server load and can be retried
1982
1983		// TODO*: Add maximum retry logic, exponential backoff
1984		// and (somewhat more optional than the others) retries
1985		// again after some set period of time
1986		if (status == 503 || status == 499)
1987		{ //retry
1988			LLMeshRepo

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