void LLViewerTextureList::doPrefetchImages()
{
	if (LLAppViewer::instance()->getPurgeCache())
	{
		// cache was purged, no point
		return;
	}
	
	// Pre-fetch textures from last logout
	LLSD imagelist;
	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
	llifstream file;
	file.open(filename);
	if (file.is_open())
	{
		LLSDSerialize::fromXML(imagelist, file);
	}
	for (LLSD::array_iterator iter = imagelist.beginArray();
		 iter != imagelist.endArray(); ++iter)
	{
		LLSD imagesd = *iter;
		LLUUID uuid = imagesd["uuid"];
		S32 pixel_area = imagesd["area"];
		S32 texture_type = imagesd["type"];

		if(LLViewerTexture::FETCHED_TEXTURE == texture_type || LLViewerTexture::LOD_TEXTURE == texture_type)
		{
			LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid, MIPMAP_TRUE, LLViewerTexture::BOOST_NONE, texture_type);
			if (image)
			{
				image->addTextureStats((F32)pixel_area);
			}
		}
	}
}
void LocalAssetBrowser::DelBitmap( std::vector<LLScrollListItem*> delete_vector, S32 column )
{
	bool change_happened = false;
	for( std::vector<LLScrollListItem*>::iterator list_iter = delete_vector.begin();
		 list_iter != delete_vector.end(); list_iter++ )
	{
		LLScrollListItem* list_item = *list_iter; 
		if ( list_item )
		{
			LLUUID id = list_item->getColumn(column)->getValue().asUUID();
			for (local_list_iter iter = loaded_bitmaps.begin();
				 iter != loaded_bitmaps.end();)
			{
				if ((*iter).getID() == id)
				{	
					LLViewerFetchedTexture* image = gTextureList.findImage(id);
					gTextureList.deleteImage( image );
					image->unref();
					iter = loaded_bitmaps.erase(iter);
					change_happened = true;
				}
				else
					++iter;
			}
		}
	}

	if (change_happened) onChangeHappened();
}
F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
{
	if (gNoRender || gGLManager.mIsDisabled) return 0.0f;
	
	//
	// Create GL textures for all textures that need them (images which have been
	// decoded, but haven't been pushed into GL).
	//
	LLFastTimer t(LLFastTimer::FTM_IMAGE_CREATE);
	
	LLTimer create_timer;
	image_list_t::iterator enditer = mCreateTextureList.begin();
	for (image_list_t::iterator iter = mCreateTextureList.begin();
		 iter != mCreateTextureList.end();)
	{
		image_list_t::iterator curiter = iter++;
		enditer = iter;
		LLViewerFetchedTexture *imagep = *curiter;
		imagep->createTexture();
		if (create_timer.getElapsedTimeF32() > max_time)
		{
			break;
		}
	}
	mCreateTextureList.erase(mCreateTextureList.begin(), enditer);
	return create_timer.getElapsedTimeF32();
}
Example #4
0
/* [maintenence functions] */
void LocalBitmap::updateSelf()
{
	if ( this->linkstatus == LINK_ON || this->linkstatus == LINK_UPDATING )
	{
		/* making sure file still exists */
		if ( !gDirUtilp->fileExists(this->filename) ) { this->linkstatus = LINK_BROKEN; return; }

		/* exists, let's check if it's lastmod has changed */
		llstat temp_stat;
		LLFile::stat(this->filename, &temp_stat);
		std::time_t temp_time = temp_stat.st_mtime;

		LLSD new_last_modified = asctime( localtime(&temp_time) );
		if ( this->last_modified.asString() == new_last_modified.asString() ) { return; }

		/* here we update the image */
		LLImageRaw* new_imgraw = new LLImageRaw();
		
		if ( !decodeSelf(new_imgraw) ) { this->linkstatus = LINK_UPDATING; return; }
		else { this->linkstatus = LINK_ON; }

		LLViewerFetchedTexture* image = gTextureList.findImage(this->id);
		
		if (!image->forSculpt()) 
		    { image->createGLTexture( LOCAL_DISCARD_LEVEL, new_imgraw ); }
		else
			{ image->setCachedRawImage(-1,new_imgraw); }

		/* finalizing by updating lastmod to current */
		this->last_modified = new_last_modified;

		/* setting unit property to reflect that it has been changed */
		switch (this->bitmap_type)
		{
			case TYPE_TEXTURE:
				  { break; }

			case TYPE_SCULPT:
				  {
					  /* sets a bool to run through all visible sculpts in one go, and update the ones necessary. */
					  this->sculpt_dirty = true;
					  this->volume_dirty = true;
					  gLocalBrowser->setSculptUpdated( true );
					  break;
				  }

			case TYPE_LAYER:
				  {
					  /* sets a bool to rebake layers after the iteration is done with */
					  gLocalBrowser->setLayerUpdated( true );
					  break;
				  }

			default:
				  { break; }

		}
	}

}
void LLViewerTextureList::updateImages(F32 max_time)
{
	LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());

	S32 global_raw_memory;
	{
		global_raw_memory = *AIAccess<S32>(LLImageRaw::sGlobalRawMemory);
	}
	sNumImagesStat.addValue(sNumImages);
	sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
	sGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes));
	sGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes));
	sRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(global_raw_memory));
	sFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory));
	
	updateImagesDecodePriorities();

	F32 total_max_time = max_time;
	max_time -= updateImagesFetchTextures(max_time);
	
	max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time
	max_time -= updateImagesCreateTextures(max_time);
	
	if (!mDirtyTextureList.empty())
	{
		LLFastTimer t(LLFastTimer::FTM_IMAGE_MARK_DIRTY);
		gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
		mDirtyTextureList.clear();
	}
	bool didone = false;
	for (image_list_t::iterator iter = mCallbackList.begin();
		iter != mCallbackList.end(); )
	{
		//trigger loaded callbacks on local textures immediately
		LLViewerFetchedTexture* image = *iter++;
		if (!image->getUrl().empty())
		{
			// Do stuff to handle callbacks, update priorities, etc.
			didone = image->doLoadedCallbacks();
		}
		else if (!didone)
		{
			// Do stuff to handle callbacks, update priorities, etc.
			didone = image->doLoadedCallbacks();
		}
	}
	//Required for old media system
	if (!gNoRender && !gGLManager.mIsDisabled)
	{
		LLViewerMedia::updateMedia();
	}
	updateImagesUpdateStats();
}
Example #6
0
void	LLTextureCtrl::setImageAssetName(const std::string& name)
{
	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);
	if(imagep)
	{
		LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get());
		if(pTexture)
		{
			LLUUID id = pTexture->getID();
			setImageAssetID(id);
		}
	}
}
void LLViewerTextureList::updateImagesUpdateStats()
{
	if (mUpdateStats && mForceResetTextureStats)
	{
		for (image_priority_list_t::iterator iter = mImageList.begin();
			 iter != mImageList.end(); )
		{
			LLViewerFetchedTexture* imagep = *iter++;
			imagep->resetTextureStats();
		}
		mUpdateStats = FALSE;
		mForceResetTextureStats = FALSE;
	}
}
Example #8
0
//static
BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel)
{
	//Note: texture atlas does not support bump texture now.
	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
	if(!tex)
	{
		//if the texture is not a fetched texture
		return FALSE;
	}

	LLViewerTexture* bump = NULL;

	switch( bump_code )
	{
	case BE_NO_BUMP:		
		break;
	case BE_BRIGHTNESS: 
	case BE_DARKNESS:
		bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code );		
		break;

	default:
		if( bump_code < LLStandardBumpmap::sStandardBumpmapCount )
		{
			bump = gStandardBumpmapList[bump_code].mImage;
			gBumpImageList.addTextureStats(bump_code, tex->getID(), vsize);
		}
		break;
	}

	if (bump)
	{
		if (channel == -2)
		{
			gGL.getTexUnit(1)->bind(bump);
			gGL.getTexUnit(0)->bind(bump);
		}
		else
		{
			gGL.getTexUnit(channel)->bind(bump);
		}

		return TRUE;
	}

	return FALSE;
}
// virtual
LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp )
{
	// suppress texlayerset updates while wearables are being imported. Layersets will be updated
	// when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed.
	LLOverrideBakedTextureUpdate stop_bakes(false);

	LLWearable::EImportResult result = LLWearable::importStream(input_stream, avatarp);
	if (LLWearable::FAILURE == result) return result;
	if (LLWearable::BAD_HEADER == result)
	{
		// Shouldn't really log the asset id for security reasons, but
		// we need it in this case.
		llwarns << "Bad Wearable asset header: " << mAssetID << llendl;
		//gVFS->dumpMap();
		return result;
	}

	LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN );
	LLStringUtil::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN );

	te_map_t::const_iterator iter = mTEMap.begin();
	te_map_t::const_iterator end = mTEMap.end();
	for (; iter != end; ++iter)
	{
		S32 te = iter->first;
		LLLocalTextureObject* lto = iter->second;
		LLUUID textureid = LLUUID::null;
		if (lto)
		{
			textureid = lto->getID();
		}

		LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( textureid );
		if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime"))
		{
			image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(textureid, (LLAvatarAppearanceDefines::ETextureIndex)te), NULL);
		}
	}

	return result;
}
// static
void LLInventoryBackup::download(LLInventoryItem* item, LLFloater* floater, loaded_callback_func onImage, LLGetAssetCallback onAsset)
{
	LLInventoryBackup::callbackdata* userdata = new LLInventoryBackup::callbackdata();
	userdata->floater = floater;
	userdata->item = item;
	LLViewerFetchedTexture* imagep;
	
	switch(item->getType())
	{
	case LLAssetType::AT_TEXTURE:
		imagep = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID(), MIPMAP_TRUE, LLViewerTexture::BOOST_UI);
		imagep->setLoadedCallback( onImage, 0, TRUE, FALSE, userdata, NULL ); // was setLoadedCallbackNoAuth
		break;
	case LLAssetType::AT_NOTECARD:
	case LLAssetType::AT_SCRIPT:
	case LLAssetType::AT_LSL_TEXT: // normal script download
	case LLAssetType::AT_LSL_BYTECODE:
		gAssetStorage->getInvItemAsset(LLHost::invalid,
										gAgent.getID(),
										gAgent.getSessionID(),
										item->getPermissions().getOwner(),
										LLUUID::null,
										item->getUUID(),
										item->getAssetUUID(),
										item->getType(),
										onAsset,
										userdata, // user_data
										TRUE);
		break;
	case LLAssetType::AT_SOUND:
	case LLAssetType::AT_CLOTHING:
	case LLAssetType::AT_BODYPART:
	case LLAssetType::AT_ANIMATION:
	case LLAssetType::AT_GESTURE:
	default:
		gAssetStorage->getAssetData(item->getAssetUUID(), item->getType(), onAsset, userdata, TRUE);
		break;
	}
}
void LLViewerTextureList::doPreloadImages()
{
	LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
	
	// Set the "missing asset" image
	LLViewerFetchedTexture::sMissingAssetImagep = LLViewerTextureManager::getFetchedTextureFromFile("missing_asset.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI);
	
	// Set the "white" image
	LLViewerFetchedTexture::sWhiteImagep = LLViewerTextureManager::getFetchedTextureFromFile("white.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI);
	
	LLUIImageList* image_list = LLUIImageList::getInstance();

	image_list->initFromFile();
	
	// turn off clamping and bilinear filtering for uv picking images
	//LLViewerFetchedTexture* uv_test = preloadUIImage("uv_test1.tga", LLUUID::null, FALSE);
	//uv_test->setClamp(FALSE, FALSE);
	//uv_test->setMipFilterNearest(TRUE, TRUE);
	//uv_test = preloadUIImage("uv_test2.tga", LLUUID::null, FALSE);
	//uv_test->setClamp(FALSE, FALSE);
	//uv_test->setMipFilterNearest(TRUE, TRUE);

	// prefetch specific UUIDs
	LLViewerTextureManager::getFetchedTexture(IMG_SHOT, TRUE);
	LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF, TRUE);
	LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
	if (image) 
	{
		image->setAddressMode(LLTexUnit::TAM_WRAP);
		mImagePreloads.insert(image);
	}
	image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
	if (image) 
	{
		image->setAddressMode(LLTexUnit::TAM_WRAP);	
		mImagePreloads.insert(image);
	}
	image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
	if (image) 
	{
		image->setAddressMode(LLTexUnit::TAM_WRAP);
		mImagePreloads.insert(image);
	}
	image = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
	if (image) 
	{
		image->setAddressMode(LLTexUnit::TAM_WRAP);	
		mImagePreloads.insert(image);
	}
	image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE,
		0,0,LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"));
	if (image) 
	{
		image->setAddressMode(LLTexUnit::TAM_WRAP);
		mImagePreloads.insert(image);
	}
	
}
Example #12
0
void LLPanelClassifiedInfo::stretchSnapshot()
{
	// *NOTE dzaporozhan
	// Could be moved to LLTextureCtrl

	LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture();

	if(!texture)
	{
		return;
	}

	if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight())
	{
		// looks like texture is not loaded yet
		return;
	}

	LLRect rc = mSnapshotRect;
	// *HACK dzaporozhan
	// LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes
	// drawn texture to be smaller than expected. (see LLTextureCtrl::draw())
	// Lets increase texture height to force texture look as expected.
	rc.mBottom -= BTN_HEIGHT_SMALL;

	F32 t_width = texture->getFullWidth();
	F32 t_height = texture->getFullHeight();

	F32 ratio = llmin<F32>( (rc.getWidth() / t_width), (rc.getHeight() / t_height) );

	t_width *= ratio;
	t_height *= ratio;

	rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height));
	mSnapshotCtrl->setShape(rc);

	mSnapshotStreched = true;
}
void LLViewerTextureList::dump()
{
	llinfos << "LLViewerTextureList::dump()" << llendl;
	for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
	{
		LLViewerFetchedTexture* image = *it;

		llinfos << "priority " << image->getDecodePriority()
		<< " boost " << image->getBoostLevel()
		<< " size " << image->getWidth() << "x" << image->getHeight()
		<< " discard " << image->getDiscardLevel()
		<< " desired " << image->getDesiredDiscardLevel()
		<< " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
		<< llendl;
	}
}
void LLLocalBitmapBrowser::delBitmap( std::vector<LLScrollListItem*> delete_vector, S32 column )
{
	bool change_happened = false;
	for( std::vector<LLScrollListItem*>::iterator list_iter = delete_vector.begin();
		 list_iter != delete_vector.end(); list_iter++ )
	{
		LLScrollListItem* list_item = *list_iter; 
		if ( list_item )
		{
			LLUUID id = list_item->getColumn(column)->getValue().asUUID();
			for (local_list_iter iter = sLoadedBitmaps.begin();
				 iter != sLoadedBitmaps.end();)
			{
				LLLocalBitmap* unit = (*iter)->getThis();

				if ( unit->getID() == id )
				{	
					LLViewerFetchedTexture* image = gTextureList.findImage(id);
					gTextureList.deleteImage( image );
					image->unref();

					iter = sLoadedBitmaps.erase(iter);
					delete unit;
					unit = NULL;

					change_happened = true;
				}
				else
				{ iter++; }
			}
		}
	}

	if ( change_happened )
	{ onChangeHappened(); }
}
void LLViewerTextureList::decodeAllImages(F32 max_time)
{
	LLTimer timer;
	if(gNoRender) return;
	
	// Update texture stats and priorities
	std::vector<LLPointer<LLViewerFetchedTexture> > image_list;
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); )
	{
		LLViewerFetchedTexture* imagep = *iter++;
		image_list.push_back(imagep);
		imagep->setInImageList(FALSE) ;
	}
	mImageList.clear();
	for (std::vector<LLPointer<LLViewerFetchedTexture> >::iterator iter = image_list.begin();
		 iter != image_list.end(); ++iter)
	{
		LLViewerFetchedTexture* imagep = *iter;
		imagep->processTextureStats();
		F32 decode_priority = imagep->calcDecodePriority();
		imagep->setDecodePriority(decode_priority);
		mImageList.insert(imagep);
		imagep->setInImageList(TRUE) ;
	}
	image_list.clear();
	
	// Update fetch (decode)
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); )
	{
		LLViewerFetchedTexture* imagep = *iter++;
		imagep->updateFetch();
	}
	// Run threads
	S32 fetch_pending = 0;
	while (1)
	{
		LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread
		LLAppViewer::instance()->getImageDecodeThread()->update(1); // unpauses the image thread
		fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1); // unpauses the texture fetch thread
		if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time)
		{
			break;
		}
	}
	// Update fetch again
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); )
	{
		LLViewerFetchedTexture* imagep = *iter++;
		imagep->updateFetch();
	}
	max_time -= timer.getElapsedTimeF32();
	max_time = llmax(max_time, .001f);
	F32 create_time = updateImagesCreateTextures(max_time);
	
	LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. " 
	<< " fetch_pending " << fetch_pending
	<< " create_time " << create_time
	<< LL_ENDL;
}
F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
{
	LLTimer image_op_timer;
	
	// Update the decode priority for N images each frame
	// Make a list with 32 high priority entries + 256 cycled entries
	const size_t max_priority_count = llmin((S32) (256*10.f*gFrameIntervalSeconds)+1, 32);
	const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256);
	
	// 32 high priority entries
	typedef std::vector<LLViewerFetchedTexture*> entries_list_t;
	entries_list_t entries;
	size_t update_counter = llmin(max_priority_count, mImageList.size());
	image_priority_list_t::iterator iter1 = mImageList.begin();
	while(update_counter > 0)
	{
		entries.push_back(*iter1);
		
		++iter1;
		update_counter--;
	}
	
	// 256 cycled entries
	update_counter = llmin(max_update_count, mUUIDMap.size());	
	if(update_counter > 0)
	{
		uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
		uuid_map_t::iterator iter2p = iter2;
		while(update_counter > 0)
		{
			if (iter2 == mUUIDMap.end())
			{
				iter2 = mUUIDMap.begin();
			}
			entries.push_back(iter2->second);
			iter2p = iter2++;
			update_counter--;
		}

		mLastFetchUUID = iter2p->first;
	}
	
	S32 fetch_count = 0;
	S32 min_count = max_priority_count + max_update_count/4;
	for (entries_list_t::iterator iter3 = entries.begin();
		 iter3 != entries.end(); )
	{
		LLViewerFetchedTexture* imagep = *iter3++;
		
		bool fetching = imagep->updateFetch();
		if (fetching)
		{
			fetch_count++;
		}
		if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
		{
			break;
		}
		min_count--;
	}
	//if (fetch_count == 0)
	//{
	//	gDebugTimers[0].pause();
	//}
	//else
	//{
	//	gDebugTimers[0].unpause();
	//}
	return image_op_timer.getElapsedTimeF32();
}
void LLObjectBackup::exportNextTexture()
{
	LLUUID id;
	textures_set_t::iterator iter = mTexturesList.begin();
	while (true)
	{
		if (mTexturesList.empty())
		{
			mCheckNextTexture = true;
			LL_INFOS() << "Finished exporting textures." << LL_ENDL;
			return;
		}
		if (iter == mTexturesList.end())
		{
			// Not yet ready, wait and re-check at next idle callback...
			mCheckNextTexture = true;
			return;
		}

		id = *iter++;
		if (id.isNull())
		{
			// NULL texture id: just remove and ignore.
			mTexturesList.erase(id);
			LL_DEBUGS("ObjectBackup") << "Null texture UUID found, ignoring."
									  << LL_ENDL;
			continue;
		}

		LLViewerTexture* imagep = LLViewerTextureManager::findTexture(id);
		if (imagep)
		{
			if (imagep->getDiscardLevel() > 0)
			{
				// Boost texture loading
				imagep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
				LL_DEBUGS("ObjectBackup") << "Boosting texture: " << id
										  << LL_ENDL;
				LLViewerFetchedTexture* tex;
				tex = LLViewerTextureManager::staticCastToFetchedTexture(imagep);
				if (tex && tex->getDesiredDiscardLevel() > 0)
				{
					// Set min discard level to 0
					tex->setMinDiscardLevel(0);
					LL_DEBUGS("ObjectBackup") << "Min discard level set to 0 for texture: "
											  << id << LL_ENDL;
				}
			}
			else
			{
				// Texture is ready !
				break;
			}
		}
		else
		{
			LL_WARNS() << "We *DON'T* have the texture " << id << LL_ENDL;
			mNonExportedTextures |= TEXTURE_MISSING;
			mTexturesList.erase(id);
		}
	}

	mTexturesList.erase(id);

	LL_INFOS() << "Requesting texture " << id << " from cache." << LL_ENDL;
	LLImageJ2C* mFormattedImage = new LLImageJ2C;
	BackupCacheReadResponder* responder;
	responder = new BackupCacheReadResponder(id, mFormattedImage);
	LLAppViewer::getTextureCache()->readFromCache(id,
												  LLWorkerThread::PRIORITY_HIGH,
												  0, 999999, responder);
}
/* [maintenence functions] */
void LLLocalBitmap::updateSelf()
{
	if ( this->mLinkStatus == LS_ON || this->mLinkStatus == LS_UPDATING )
	{
		/* making sure file still exists */
		if ( !gDirUtilp->fileExists(this->mFilename) )
			{ 
				this->mLinkStatus = LS_BROKEN;
				LLFloaterLocalBitmapBrowser::updateRightSide();
				return; 
			}

		/* exists, let's check if it's lastmod has changed */
		const std::time_t temp_time = boost::filesystem::last_write_time( boost::filesystem::path( this->mFilename ) );
		LLSD new_last_modified = asctime( localtime(&temp_time) );
		if ( this->mLastModified.asString() == new_last_modified.asString() ) { return; }

		/* here we update the image */
		LLImageRaw* new_imgraw = new LLImageRaw();
		
		if ( !decodeSelf(new_imgraw) ) { this->mLinkStatus = LS_UPDATING; return; }
		else { this->mLinkStatus = LS_ON; }

		LLViewerFetchedTexture* image = gTextureList.findImage(this->mId);
		
		// here was a check if isForSculptOnly, but it appears the function is broken.
		image->createGLTexture( LOCAL_DISCARD_LEVEL, new_imgraw );
		image->setCachedRawImage( LOCAL_DISCARD_LEVEL, new_imgraw );

		/* finalizing by updating lastmod to current */
		this->mLastModified = new_last_modified;

		/* setting unit property to reflect that it has been changed */
		switch (this->mBitmapType)
		{
			case BT_TEXTURE:
				  { break; }

			case BT_SCULPT:
				  {
					  /* sets a bool to run through all visible sculpts in one go, and update the ones necessary. */
					  this->mSculptDirty = true;
					  this->mVolumeDirty = true;
					  gLocalBrowser->setSculptUpdated( true );
					  break;
				  }

			case BT_LAYER:
				  {
					  /* sets a bool to rebake layers after the iteration is done with */
					  gLocalBrowser->setLayerUpdated( true );
					  break;
				  }

			default:
				  { break; }

		}
	}

}
void LLViewerTextureList::shutdown()
{
	// clear out preloads
	mImagePreloads.clear();

	// Write out list of currently loaded textures for precaching on startup
	typedef std::set<std::pair<S32,LLViewerFetchedTexture*> > image_area_list_t;
	image_area_list_t image_area_list;
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); ++iter)
	{
		LLViewerFetchedTexture* image = *iter;
		if (!image->hasGLTexture() ||
			!image->getUseDiscard() ||
			image->needsAux() ||
			image->getTargetHost() != LLHost::invalid)
		{
			continue; // avoid UI, baked, and other special images
		}
		if(!image->getBoundRecently())
		{
			continue ;
		}
		S32 desired = image->getDesiredDiscardLevel();
		if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
		{
			S32 pixel_area = image->getWidth(desired) * image->getHeight(desired);
			image_area_list.insert(std::make_pair(pixel_area, image));
		}
	}
	
	LLSD imagelist;
	const S32 max_count = 1000;
	S32 count = 0;
	S32 image_type ;
	for (image_area_list_t::reverse_iterator riter = image_area_list.rbegin();
		 riter != image_area_list.rend(); ++riter)
	{
		LLViewerFetchedTexture* image = riter->second;
		image_type = (S32)image->getType() ;
		imagelist[count]["area"] = riter->first;
		imagelist[count]["uuid"] = image->getID();
		imagelist[count]["type"] = image_type;
		if (++count >= max_count)
			break;
	}

	if (count > 0 && !gDirUtilp->getLindenUserDir(true).empty())
	{
		std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
		llofstream file;
		file.open(filename);
		LLSDSerialize::toPrettyXML(imagelist, file);
	}
	
	//
	// Clean up "loaded" callbacks.
	//
	mCallbackList.clear();
	
	// Flush all of the references
	mLoadingStreamList.clear();
	mCreateTextureList.clear();
	
	mUUIDMap.clear();
	
	mImageList.clear();

	mInitialized = FALSE ; //prevent loading textures again.
}
void FSFloaterObjectExport::onIdle()
{
	switch(mExportState)
	{
	case IDLE:
		break;
	case INVENTORY_DOWNLOAD:
		if (gDisconnected)
		{
			return;
		}
		
		if (mInventoryRequests.empty())
		{
			mLastRequest = mAssetRequests.size();
			mWaitTimer.start();
			mExportState = ASSET_DOWNLOAD;
		}
		else if (mLastRequest != mInventoryRequests.size())
		{
			mWaitTimer.start();
			mLastRequest = mInventoryRequests.size();
			updateTitleProgress(INVENTORY_DOWNLOAD);
		}
		else if (mWaitTimer.getElapsedTimeF32() > MAX_INVENTORY_WAIT_TIME)
		{
			mWaitTimer.start();
			for (uuid_vec_t::const_iterator iter = mInventoryRequests.begin(); iter != mInventoryRequests.end(); ++iter)
			{
				LLViewerObject* object = gObjectList.findObject((*iter));
				object->dirtyInventory();
				object->requestInventory();
				
				LL_DEBUGS("export") << "re-requested inventory of " << (*iter).asString() << LL_ENDL;
			}
		}
		break;
	case ASSET_DOWNLOAD:
		if (gDisconnected)
		{
			return;
		}
		
		if (mAssetRequests.empty())
		{
			mLastRequest = mRequestedTexture.size();
			mWaitTimer.start();
			mExportState = TEXTURE_DOWNLOAD;
		}
		else if (mLastRequest != mAssetRequests.size())
		{
			mWaitTimer.start();
			mLastRequest = mAssetRequests.size();
			updateTitleProgress(ASSET_DOWNLOAD);
		}
		else if (mWaitTimer.getElapsedTimeF32() > MAX_ASSET_WAIT_TIME)
		{
			//abort for now
			LL_DEBUGS("export") << "Asset timeout with " << (S32)mAssetRequests.size() << " requests left." << LL_ENDL;
			for (uuid_vec_t::iterator iter = mAssetRequests.begin(); iter != mAssetRequests.end(); ++iter)
			{
				LL_DEBUGS("export") << "Asset: " << (*iter).asString() << LL_ENDL;
			}
			mAssetRequests.clear();
		}
		break;
	case TEXTURE_DOWNLOAD:
		if (gDisconnected)
		{
			return;
		}

		if(mRequestedTexture.empty())
		{
			mExportState = IDLE;
			if (!gIdleCallbacks.deleteFunction(onIdle, this))
			{
				LL_WARNS("export") << "Failed to delete idle callback" << LL_ENDL;
			}
			mWaitTimer.stop();

			llofstream file;
			file.open(mFilename.c_str(), std::ios_base::out | std::ios_base::binary);
			std::string zip_data = zip_llsd(mManifest);
			file.write(zip_data.data(), zip_data.size());
			file.close();
			LL_DEBUGS("export") << "Export finished and written to " << mFilename << LL_ENDL;
			
			LLSD args;
			args["FILENAME"] = mFilename;
			LLNotificationsUtil::add("ExportFinished", args);
			closeFloater();
		}
		else if (mLastRequest != mRequestedTexture.size())
		{
			mWaitTimer.start();
			mLastRequest = mRequestedTexture.size();
			updateTitleProgress(TEXTURE_DOWNLOAD);
		}
		else if (mWaitTimer.getElapsedTimeF32() > MAX_TEXTURE_WAIT_TIME)
		{
			mWaitTimer.start();
			for (std::map<LLUUID, FSAssetResourceData>::iterator iter = mRequestedTexture.begin(); iter != mRequestedTexture.end(); ++iter)
			{
				LLUUID texture_id = iter->first;
				LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_id, FTT_DEFAULT, MIPMAP_TRUE);
				image->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL);
				image->forceToSaveRawImage(0);
				image->setLoadedCallback(FSFloaterObjectExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList);

				LL_DEBUGS("export") << "re-requested texture " << texture_id.asString() << LL_ENDL;
			}
		}
		break;
	default:
		break;
	}
}
bool FSFloaterObjectExport::exportTexture(const LLUUID& texture_id)
{
	if(texture_id.isNull())
	{
		LL_WARNS("export") << "Attempted to export NULL texture." << LL_ENDL;
		return false;
	}
	
	if (mTextureChecked.count(texture_id) != 0)
	{
		return mTextureChecked[texture_id];
	}
	
	if (gAssetStorage->mStaticVFS->getExists(texture_id, LLAssetType::AT_TEXTURE))
	{
		LL_DEBUGS("export") << "Texture " << texture_id.asString() << " is local static." << LL_ENDL;
		// no need to save the texture data as the viewer already has it in a local file.
		mTextureChecked[texture_id] = true;
		return true;
	}
	
	//TODO: check for local file static texture. The above will only get the static texture in the static db, not individual textures.

	LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(texture_id);
	bool texture_export = false;
	std::string name;
	std::string description;
	
	if (LLGridManager::getInstance()->isInSecondLife())
	{
		if (imagep->mComment.find("a") != imagep->mComment.end())
		{
			if (LLUUID(imagep->mComment["a"]) == gAgentID)
			{
				texture_export = true;
				LL_DEBUGS("export") << texture_id <<  " pass texture export comment check." << LL_ENDL;
			}
		}
	}

	if (texture_export)
	{
		FSExportPermsCheck::canExportAsset(texture_id, &name, &description);
	}
	else
	{
		texture_export = FSExportPermsCheck::canExportAsset(texture_id, &name, &description);
	}

	mTextureChecked[texture_id] = texture_export;
	
	if (!texture_export)
	{
		LL_DEBUGS("export") << "Texture " << texture_id << " failed export check." << LL_ENDL;
		return false;
	}

	LL_DEBUGS("export") << "Loading image texture " << texture_id << LL_ENDL;
	mRequestedTexture[texture_id].name = name;
	mRequestedTexture[texture_id].description = description;
	LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_id, FTT_DEFAULT, MIPMAP_TRUE);
	image->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL);
	image->forceToSaveRawImage(0);
	image->setLoadedCallback(FSFloaterObjectExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList);

	return true;
}
BOOL LLWearable::importFile( LLFILE* file )
{
	// *NOTE: changing the type or size of this buffer will require
	// changes in the fscanf() code below. You would be better off
	// rewriting this to use streams and not require an open FILE.
	char text_buffer[2048];		/* Flawfinder: ignore */
	S32 fields_read = 0;

	// suppress texlayerset updates while wearables are being imported. Layersets will be updated
	// when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed.
	LLOverrideBakedTextureUpdate stop_bakes(false);

	// read header and version 
	fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion );
	if( fields_read != 1 )
	{
		// Shouldn't really log the asset id for security reasons, but
		// we need it in this case.
		llwarns << "Bad Wearable asset header: " << mAssetID << llendl;
		//gVFS->dumpMap();
		return FALSE;
	}


	// Temoprary hack to allow wearables with definition version 24 to still load.
	// This should only affect lindens and NDA'd testers who have saved wearables in 2.0
	// the extra check for version == 24 can be removed before release, once internal testers
	// have loaded these wearables again. See hack pt 2 at bottom of function to ensure that
	// these wearables get re-saved with version definition 22.
	if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 )
	{
		llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl;
		return FALSE;
	}

	// name
	int next_char = fgetc( file );		/* Flawfinder: ignore */
	if( '\n' == next_char )
	{
		// no name
		mName = "";
	}
	else
	{
		ungetc( next_char, file );
		fields_read = fscanf(	/* Flawfinder: ignore */
			file,
			"%2047[^\n]",
			text_buffer);
		if( (1 != fields_read) || (fgetc( file ) != '\n') )		/* Flawfinder: ignore */
		{
			llwarns << "Bad Wearable asset: early end of file" << llendl;
			return FALSE;
		}
		mName = text_buffer;
		LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN );
	}

	// description
	next_char = fgetc( file );		/* Flawfinder: ignore */
	if( '\n' == next_char )
	{
		// no description
		mDescription = "";
	}
	else
	{
		ungetc( next_char, file );
		fields_read = fscanf(	/* Flawfinder: ignore */
			file,
			"%2047[^\n]",
			text_buffer );
		if( (1 != fields_read) || (fgetc( file ) != '\n') )		/* Flawfinder: ignore */
		{
			llwarns << "Bad Wearable asset: early end of file" << llendl;
			return FALSE;
		}
		mDescription = text_buffer;
		LLStringUtil::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN );
	}

	// permissions
	S32 perm_version;
	fields_read = fscanf( file, " permissions %d\n", &perm_version );
	if( (fields_read != 1) || (perm_version != 0) )
	{
		llwarns << "Bad Wearable asset: missing permissions" << llendl;
		return FALSE;
	}
	if( !mPermissions.importFile( file ) )
	{
		return FALSE;
	}

	// sale info
	S32 sale_info_version;
	fields_read = fscanf( file, " sale_info %d\n", &sale_info_version );
	if( (fields_read != 1) || (sale_info_version != 0) )
	{
		llwarns << "Bad Wearable asset: missing sale_info" << llendl;
		return FALSE;
	}
	// Sale info used to contain next owner perm. It is now in the
	// permissions. Thus, we read that out, and fix legacy
	// objects. It's possible this op would fail, but it should pick
	// up the vast majority of the tasks.
	BOOL has_perm_mask = FALSE;
	U32 perm_mask = 0;
	if( !mSaleInfo.importFile(file, has_perm_mask, perm_mask) )
	{
		return FALSE;
	}
	if(has_perm_mask)
	{
		// fair use fix.
		if(!(perm_mask & PERM_COPY))
		{
			perm_mask |= PERM_TRANSFER;
		}
		mPermissions.setMaskNext(perm_mask);
	}

	// wearable type
	S32 type = -1;
	fields_read = fscanf( file, "type %d\n", &type );
	if( fields_read != 1 )
	{
		llwarns << "Bad Wearable asset: bad type" << llendl;
		return FALSE;
	}
	if( 0 <= type && type < LLWearableType::WT_COUNT )
	{
		setType((LLWearableType::EType)type);
	}
	else
	{
		mType = LLWearableType::WT_COUNT;
		llwarns << "Bad Wearable asset: bad type #" << type <<  llendl;
		return FALSE;
	}

	// parameters header
	S32 num_parameters = 0;
	fields_read = fscanf( file, "parameters %d\n", &num_parameters );
	if( fields_read != 1 )
	{
		llwarns << "Bad Wearable asset: missing parameters block" << llendl;
		return FALSE;
	}

	if( num_parameters != mVisualParamIndexMap.size() )
	{
		llwarns << "Wearable parameter mismatch. Reading in " << num_parameters << " from file, but created " << mVisualParamIndexMap.size() << " from avatar parameters. type: " <<  mType << llendl;
	}

	// parameters
	S32 i;
	for( i = 0; i < num_parameters; i++ )
	{
		S32 param_id = 0;
		F32 param_weight = 0.f;
		fields_read = fscanf( file, "%d %f\n", &param_id, &param_weight );
		if( fields_read != 2 )
		{
			llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl;
			return FALSE;
		}
		mSavedVisualParamMap[param_id] = param_weight;
	}

	// textures header
	S32 num_textures = 0;
	fields_read = fscanf( file, "textures %d\n", &num_textures);
	if( fields_read != 1 )
	{
		llwarns << "Bad Wearable asset: missing textures block" << llendl;
		return FALSE;
	}

	// textures
	for( i = 0; i < num_textures; i++ )
	{
		S32 te = 0;
		fields_read = fscanf(	/* Flawfinder: ignore */
			file,
			"%d %2047s\n",
			&te, text_buffer);
		if( fields_read != 2 )
		{
			llwarns << "Bad Wearable asset: bad texture, #" << i << llendl;
			return FALSE;
		}

		if( !LLUUID::validate( text_buffer ) )
		{
			llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl;
			return FALSE;
		}
		LLUUID id = LLUUID(text_buffer);
		LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( id );
		if( mTEMap.find(te) != mTEMap.end() )
		{
			delete mTEMap[te];
		}
		if( mSavedTEMap.find(te) != mSavedTEMap.end() )
		{
			delete mSavedTEMap[te];
		}

		if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime"))
		{
			image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), NULL);
		}
		LLUUID textureid(text_buffer);
		mTEMap[te] = new LLLocalTextureObject(image, textureid);
		mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
		createLayers(te);
	}

	// copy all saved param values to working params
	revertValues();

	return TRUE;
}
Example #23
0
LLSD JCExportTracker::subserialize(LLViewerObject* linkset)
{
	//Chalice - Changed to support exporting linkset groups.
	LLViewerObject* object = linkset;
	//if(!linkset)return LLSD();
	
	// Create an LLSD object that will hold the entire tree structure that can be serialized to a file
	LLSD llsd;

	//if (!node)
	//	return llsd;

	//object = root_object = node->getObject();
	
	if (!object)
		return llsd;
	if(!(!object->isAvatar() && object->permYouOwner() && object->permModify() && object->permCopy() && object->permTransfer() && !gAgent.getGodLevel()))
		return llsd;
	// Build a list of everything that we'll actually be exporting
	LLDynamicArray<LLViewerObject*> export_objects;
	
	// Add the root object to the export list
	export_objects.put(object);
	
	// Iterate over all of this objects children
	LLViewerObject::child_list_t child_list = object->getChildren();
	
	for (LLViewerObject::child_list_t::iterator i = child_list.begin(); i != child_list.end(); ++i)
	{
		LLViewerObject* child = *i;
		if(!child->isAvatar())
		{
			// Put the child objects on the export list
			export_objects.put(child);
		}
	}
		
	S32 object_index = 0;
	
	while ((object_index < export_objects.count()))
	{
		object = export_objects.get(object_index++);
		LLUUID id = object->getID();
	
		llinfos << "Exporting prim " << object->getID().asString() << llendl;
	
		// Create an LLSD object that represents this prim. It will be injected in to the overall LLSD
		// tree structure
		LLSD prim_llsd;
	
		if (object_index == 1)
		{
			LLVOAvatar* avatar = find_avatar_from_object(object);
			if (avatar)
			{
				LLViewerJointAttachment* attachment = avatar->getTargetAttachmentPoint(object);
				U8 attachment_id = 0;
				
				if (attachment)
				{
					for (LLVOAvatar::attachment_map_t::iterator iter = avatar->mAttachmentPoints.begin();
										iter != avatar->mAttachmentPoints.end(); ++iter)
					{
						if (iter->second == attachment)
						{
							attachment_id = iter->first;
							break;
						}
					}
				}
				else
				{
					// interpret 0 as "default location"
					attachment_id = 0;
				}
				
				prim_llsd["Attachment"] = attachment_id;
				prim_llsd["attachpos"] = object->getPosition().getValue();
				prim_llsd["attachrot"] = ll_sd_from_quaternion(object->getRotation());
			}
			
			prim_llsd["position"] = LLVector3(0, 0, 0).getValue();
			prim_llsd["rotation"] = ll_sd_from_quaternion(object->getRotation());
		}
		else
		{
			prim_llsd["position"] = object->getPosition().getValue();
			prim_llsd["rotation"] = ll_sd_from_quaternion(object->getRotation());
		}
		//prim_llsd["name"] = "";//node->mName;
		//prim_llsd["description"] = "";//node->mDescription;
		// Transforms
		prim_llsd["scale"] = object->getScale().getValue();
		// Flags
		prim_llsd["shadows"] = object->flagCastShadows();
		prim_llsd["phantom"] = object->flagPhantom();
		prim_llsd["physical"] = (BOOL)(object->mFlags & FLAGS_USE_PHYSICS);
		LLVolumeParams params = object->getVolume()->getParams();
		prim_llsd["volume"] = params.asLLSD();
		if (object->isFlexible())
		{
			LLFlexibleObjectData* flex = (LLFlexibleObjectData*)object->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
			prim_llsd["flexible"] = flex->asLLSD();
		}
		if (object->getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT))
		{
			LLLightParams* light = (LLLightParams*)object->getParameterEntry(LLNetworkData::PARAMS_LIGHT);
			prim_llsd["light"] = light->asLLSD();
		}
		if (object->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
		{
			LLSculptParams* sculpt = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
			prim_llsd["sculpt"] = sculpt->asLLSD();
		}

		// Textures
		LLSD te_llsd;
		U8 te_count = object->getNumTEs();
		
		for (U8 i = 0; i < te_count; i++)
		{
			te_llsd.append(object->getTE(i)->asLLSD());
		}

		if(export_textures)
		{
			std::string path = asset_dir + gDirUtilp->getDirDelimiter();
			for (U8 i = 0; i < te_count; i++)
			{
				LLUUID asset_id = object->getTE(i)->getID();
				JCAssetInfo* info = new JCAssetInfo;
				info->path = path + asset_id.asString() + ".j2c";
				info->name = "Prim Texture";
				//gAssetStorage->getAssetData(asset_id, LLAssetType::AT_TEXTURE, JCAssetExportCallback, info,1);
				if(requested_textures.count(asset_id) == 0)
				{
					requested_textures.insert(asset_id);
					LLViewerFetchedTexture* img = LLViewerTextureManager::getFetchedTexture(asset_id, MIPMAP_TRUE);
					img->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL);
					img->setLoadedCallback( JCExportTracker::onFileLoadedForSave, 
									0, TRUE, FALSE, info, &mCallbackTextureList);
					llinfos << "Requesting texture " << asset_id.asString() << llendl;
				}
			}
		}

		//JCExportTracker::mirror(asset, obj, asset_dir, asset->getUUID().asString());
		
		prim_llsd["textures"] = te_llsd;

		prim_llsd["id"] = object->getID().asString();
		if(export_properties)
		{
			////cmdline_printchat(llformat("yes %d",export_properties));
			propertyqueries += 1;
			gMessageSystem->newMessageFast(_PREHASH_ObjectSelect);
			gMessageSystem->nextBlockFast(_PREHASH_AgentData);
			gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
			gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());

			gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
            gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
            
            gMessageSystem->sendReliable(gAgent.getRegionHost());

			if(export_inventory)
			{
				object->registerInventoryListener(sInstance,NULL);
				object->dirtyInventory();
				object->requestInventory();
				invqueries += 1;
			}
		}//else //cmdline_printchat(llformat("no %d",export_properties));
		totalprims += 1;

		// Changed to use link numbers zero-indexed.
		llsd[object_index - 1] = prim_llsd;
	}
	return llsd;
}