diff options
author | Kitty Barnett <develop@catznip.com> | 2012-05-20 17:41:00 +0200 |
---|---|---|
committer | Kitty Barnett <develop@catznip.com> | 2012-05-20 17:41:00 +0200 |
commit | 1300f77fdd48d90d09a05058ffdf10df93092391 (patch) | |
tree | 1cefd5cb64be5ae614b4930dcd0a55cf4fc06109 /indra/newview/lllocalbitmaps.cpp | |
parent | 8199cc997aeaccc72b5bd5389ded8afc7b9c379c (diff) | |
parent | aa0a0542a10ba6faeca34afd6e323b505493d8dc (diff) |
Merged with viewer-beta
Diffstat (limited to 'indra/newview/lllocalbitmaps.cpp')
-rw-r--r-- | indra/newview/lllocalbitmaps.cpp | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp new file mode 100644 index 0000000000..459e52c4f4 --- /dev/null +++ b/indra/newview/lllocalbitmaps.cpp @@ -0,0 +1,942 @@ +/** + * @file lllocalbitmaps.cpp + * @author Vaalith Jinn + * @brief Local Bitmaps source + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/* precompiled headers */ +#include "llviewerprecompiledheaders.h" + +/* own header */ +#include "lllocalbitmaps.h" + +/* boost: will not compile unless equivalent is undef'd, beware. */ +#ifdef equivalent +#undef equivalent +#endif +#include <boost/filesystem.hpp> + +/* image compression headers. */ +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +/* time headers */ +#include <time.h> +#include <ctime> + +/* misc headers */ +#include "llscrolllistctrl.h" +#include "llfilepicker.h" +#include "llviewertexturelist.h" +#include "llviewerobjectlist.h" +#include "llviewerobject.h" +#include "llface.h" +#include "llvoavatarself.h" +#include "llwearable.h" +#include "llagentwearables.h" +#include "lltexlayerparams.h" +#include "llvovolume.h" +#include "llnotificationsutil.h" + +/*=======================================*/ +/* Formal declarations, constants, etc. */ +/*=======================================*/ +std::list<LLLocalBitmap*> LLLocalBitmapMgr::sBitmapList; +LLLocalBitmapTimer LLLocalBitmapMgr::sTimer; +bool LLLocalBitmapMgr::sNeedsRebake; + +static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; +static const BOOL LL_LOCAL_USE_MIPMAPS = true; +static const S32 LL_LOCAL_DISCARD_LEVEL = 0; +static const U32 LL_LOCAL_TEXLAYER_FOR_IDX = 0; +static const bool LL_LOCAL_SLAM_FOR_DEBUG = true; +static const bool LL_LOCAL_REPLACE_ON_DEL = true; +static const S32 LL_LOCAL_UPDATE_RETRIES = 5; + +/*=======================================*/ +/* LLLocalBitmap: unit class */ +/*=======================================*/ +LLLocalBitmap::LLLocalBitmap(std::string filename) + : mFilename(filename) + , mShortName(gDirUtilp->getBaseFileName(filename, true)) + , mValid(false) + , mLastModified() + , mLinkStatus(LS_ON) + , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) +{ + mTrackingID.generate(); + + /* extension */ + std::string temp_exten = gDirUtilp->getExtension(mFilename); + + if (temp_exten == "bmp") + { + mExtension = ET_IMG_BMP; + } + else if (temp_exten == "tga") + { + mExtension = ET_IMG_TGA; + } + else if (temp_exten == "jpg" || temp_exten == "jpeg") + { + mExtension = ET_IMG_JPG; + } + else if (temp_exten == "png") + { + mExtension = ET_IMG_PNG; + } + else + { + llwarns << "File of no valid extension given, local bitmap creation aborted." << "\n" + << "Filename: " << mFilename << llendl; + return; // no valid extension. + } + + /* next phase of unit creation is nearly the same as an update cycle. + we're running updateSelf as a special case with the optional UT_FIRSTUSE + which omits the parts associated with removing the outdated texture */ + mValid = updateSelf(UT_FIRSTUSE); +} + +LLLocalBitmap::~LLLocalBitmap() +{ + // replace IDs with defaults, if set to do so. + if(LL_LOCAL_REPLACE_ON_DEL && mValid) // fix for STORM-1837 + { + replaceIDs(mWorldID, IMG_DEFAULT); + LLLocalBitmapMgr::doRebake(); + } + + // delete self from gimagelist + LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID); + gTextureList.deleteImage(image); + + if (image) + { + image->unref(); + } +} + +/* accessors */ +std::string LLLocalBitmap::getFilename() +{ + return mFilename; +} + +std::string LLLocalBitmap::getShortName() +{ + return mShortName; +} + +LLUUID LLLocalBitmap::getTrackingID() +{ + return mTrackingID; +} + +LLUUID LLLocalBitmap::getWorldID() +{ + return mWorldID; +} + +bool LLLocalBitmap::getValid() +{ + return mValid; +} + +/* update functions */ +bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) +{ + bool updated = false; + + if (mLinkStatus == LS_ON) + { + // verifying that the file exists + if (gDirUtilp->fileExists(mFilename)) + { + // verifying that the file has indeed been modified + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); + LLSD new_last_modified = asctime(localtime(&temp_time)); + + if (mLastModified.asString() != new_last_modified.asString()) + { + /* loading the image file and decoding it, here is a critical point which, + if fails, invalidates the whole update (or unit creation) process. */ + LLPointer<LLImageRaw> raw_image = new LLImageRaw(); + if (decodeBitmap(raw_image)) + { + // decode is successful, we can safely proceed. + LLUUID old_id = LLUUID::null; + if (!(optional_firstupdate == UT_FIRSTUSE) && !mWorldID.isNull()) + { + old_id = mWorldID; + } + mWorldID.generate(); + mLastModified = new_last_modified; + + LLPointer<LLViewerFetchedTexture> texture = new LLViewerFetchedTexture + ("file://"+mFilename, mWorldID, LL_LOCAL_USE_MIPMAPS); + + texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image); + texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image); + texture->ref(); + + gTextureList.addImage(texture); + + if (!optional_firstupdate == UT_FIRSTUSE) + { + // seek out everything old_id uses and replace it with mWorldID + replaceIDs(old_id, mWorldID); + + // remove old_id from gimagelist + LLViewerFetchedTexture* image = gTextureList.findImage(old_id); + gTextureList.deleteImage(image); + image->unref(); + } + + mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; + updated = true; + } + + // if decoding failed, we get here and it will attempt to decode it in the next cycles + // until mUpdateRetries runs out. this is done because some software lock the bitmap while writing to it + else + { + if (mUpdateRetries) + { + mUpdateRetries--; + } + else + { + llwarns << "During the update process the following file was found" << "\n" + << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << llendl; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; + LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + } + + } // end if file exists + + else + { + llwarns << "During the update process, the following file was not found." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << llendl; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + + return updated; +} + +bool LLLocalBitmap::decodeBitmap(LLPointer<LLImageRaw> rawimg) +{ + bool decode_successful = false; + + switch (mExtension) + { + case ET_IMG_BMP: + { + LLPointer<LLImageBMP> bmp_image = new LLImageBMP; + if (bmp_image->load(mFilename) && bmp_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_TGA: + { + LLPointer<LLImageTGA> tga_image = new LLImageTGA; + if ((tga_image->load(mFilename) && tga_image->decode(rawimg)) + && ((tga_image->getComponents() == 3) || (tga_image->getComponents() == 4))) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_JPG: + { + LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG; + if (jpeg_image->load(mFilename) && jpeg_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + case ET_IMG_PNG: + { + LLPointer<LLImagePNG> png_image = new LLImagePNG; + if (png_image->load(mFilename) && png_image->decode(rawimg, 0.0f)) + { + rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + decode_successful = true; + } + break; + } + + default: + { + // separating this into -several- llwarns calls because in the extremely unlikely case that this happens + // accessing mFilename and any other object properties might very well crash the viewer. + // getting here should be impossible, or there's been a pretty serious bug. + + llwarns << "During a decode attempt, the following local bitmap had no properly assigned extension." << llendl; + llwarns << "Filename: " << mFilename << llendl; + llwarns << "Disabling further update attempts for this file." << llendl; + mLinkStatus = LS_BROKEN; + } + } + + return decode_successful; +} + +void LLLocalBitmap::replaceIDs(LLUUID old_id, LLUUID new_id) +{ + // checking for misuse. + if (old_id == new_id) + { + llinfos << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" + << "Texture UUID: " << old_id.asString() << llendl; + return; + } + + updateUserPrims(old_id, new_id); + updateUserSculpts(old_id, new_id); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something? + + // default safeguard image for layers + if( new_id == IMG_DEFAULT ) + { + new_id = IMG_DEFAULT_AVATAR; + } + + /* It doesn't actually update all of those, it merely checks if any of them + contain the referenced ID and if so, updates. */ + updateUserLayers(old_id, new_id, LLWearableType::WT_ALPHA); + updateUserLayers(old_id, new_id, LLWearableType::WT_EYES); + updateUserLayers(old_id, new_id, LLWearableType::WT_GLOVES); + updateUserLayers(old_id, new_id, LLWearableType::WT_JACKET); + updateUserLayers(old_id, new_id, LLWearableType::WT_PANTS); + updateUserLayers(old_id, new_id, LLWearableType::WT_SHIRT); + updateUserLayers(old_id, new_id, LLWearableType::WT_SHOES); + updateUserLayers(old_id, new_id, LLWearableType::WT_SKIN); + updateUserLayers(old_id, new_id, LLWearableType::WT_SKIRT); + updateUserLayers(old_id, new_id, LLWearableType::WT_SOCKS); + updateUserLayers(old_id, new_id, LLWearableType::WT_TATTOO); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS); + updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT); +} + +// this function sorts the faces from a getFaceList[getNumFaces] into a list of objects +// in order to prevent multiple sendTEUpdate calls per object during updateUserPrims +std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id) +{ + std::vector<LLViewerObject*> obj_list; + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id); + + for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(); face_iterator++) + { + // getting an object from a face + LLFace* face_to_object = (*old_texture->getFaceList())[face_iterator]; + + if(face_to_object) + { + LLViewerObject* affected_object = face_to_object->getViewerObject(); + + if(affected_object) + { + + // we have an object, we'll take it's UUID and compare it to + // whatever we already have in the returnable object list. + // if there is a match - we do not add (to prevent duplicates) + LLUUID mainlist_obj_id = affected_object->getID(); + bool add_object = true; + + // begin looking for duplicates + std::vector<LLViewerObject*>::iterator objlist_iter = obj_list.begin(); + for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) + { + LLViewerObject* obj = *objlist_iter; + if (obj->getID() == mainlist_obj_id) + { + add_object = false; // duplicate found. + } + } + // end looking for duplicates + + if(add_object) + { + obj_list.push_back(affected_object); + } + + } + + } + + } // end of face-iterating for() + + return obj_list; +} + +void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id) +{ + std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id); + + for(std::vector<LLViewerObject*>::iterator object_iterator = objectlist.begin(); + object_iterator != objectlist.end(); object_iterator++) + { + LLViewerObject* object = *object_iterator; + + if(object) + { + bool update_obj = false; + S32 num_faces = object->getNumFaces(); + + for (U8 face_iter = 0; face_iter < num_faces; face_iter++) + { + if (object->mDrawable) + { + LLFace* face = object->mDrawable->getFace(face_iter); + if (face && face->getTexture() && face->getTexture()->getID() == old_id) + { + object->setTEImage(face_iter, LLViewerTextureManager::getFetchedTexture + (new_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + + update_obj = true; + } + } + } + + if (update_obj) + { + object->sendTEUpdate(); + } + } + } + +} + +void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id) +{ + LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id); + for(U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(); volume_iter++) + { + LLVOVolume* volume_to_object = (*old_texture->getVolumeList())[volume_iter]; + LLViewerObject* object = (LLViewerObject*)volume_to_object; + + if(object) + { + if (object->isSculpted() && object->getVolume() && + object->getVolume()->getParams().getSculptID() == old_id) + { + LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLSculptParams new_params(*old_params); + new_params.setSculptTexture(new_id); + object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE); + } + } + } +} + +void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type) +{ + U32 count = gAgentWearables.getWearableCount(type); + for(U32 wearable_iter = 0; wearable_iter < count; wearable_iter++) + { + LLWearable* wearable = gAgentWearables.getWearable(type, wearable_iter); + if (wearable) + { + std::vector<LLLocalTextureObject*> texture_list = wearable->getLocalTextureListSeq(); + for(std::vector<LLLocalTextureObject*>::iterator texture_iter = texture_list.begin(); + texture_iter != texture_list.end(); texture_iter++) + { + LLLocalTextureObject* lto = *texture_iter; + + if (lto && lto->getID() == old_id) + { + U32 local_texlayer_index = 0; /* can't keep that as static const, gives errors, so i'm leaving this var here */ + LLVOAvatarDefines::EBakedTextureIndex baked_texind = + lto->getTexLayer(local_texlayer_index)->getTexLayerSet()->getBakedTexIndex(); + + LLVOAvatarDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind); + if (reg_texind != LLVOAvatarDefines::TEX_NUM_INDICES) + { + U32 index = gAgentWearables.getWearableIndex(wearable); + gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); + gAgentAvatarp->wearableUpdated(type, FALSE); + + /* telling the manager to rebake once update cycle is fully done */ + LLLocalBitmapMgr::setNeedsRebake(); + } + + } + } + } + } +} + +LLVOAvatarDefines::ETextureIndex LLLocalBitmap::getTexIndex( + LLWearableType::EType type, LLVOAvatarDefines::EBakedTextureIndex baked_texind) +{ + LLVOAvatarDefines::ETextureIndex result = LLVOAvatarDefines::TEX_NUM_INDICES; // using as a default/fail return. + + switch(type) + { + case LLWearableType::WT_ALPHA: + { + switch(baked_texind) + { + case LLVOAvatarDefines::BAKED_EYES: + { + result = LLVOAvatarDefines::TEX_EYES_ALPHA; + break; + } + + case LLVOAvatarDefines::BAKED_HAIR: + { + result = LLVOAvatarDefines::TEX_HAIR_ALPHA; + break; + } + + case LLVOAvatarDefines::BAKED_HEAD: + { + result = LLVOAvatarDefines::TEX_HEAD_ALPHA; + break; + } + + case LLVOAvatarDefines::BAKED_LOWER: + { + result = LLVOAvatarDefines::TEX_LOWER_ALPHA; + break; + } + case LLVOAvatarDefines::BAKED_UPPER: + { + result = LLVOAvatarDefines::TEX_UPPER_ALPHA; + break; + } + + default: + { + break; + } + + } + break; + + } + + case LLWearableType::WT_EYES: + { + if (baked_texind == LLVOAvatarDefines::BAKED_EYES) + { + result = LLVOAvatarDefines::TEX_EYES_IRIS; + } + + break; + } + + case LLWearableType::WT_GLOVES: + { + if (baked_texind == LLVOAvatarDefines::BAKED_UPPER) + { + result = LLVOAvatarDefines::TEX_UPPER_GLOVES; + } + + break; + } + + case LLWearableType::WT_JACKET: + { + if (baked_texind == LLVOAvatarDefines::BAKED_LOWER) + { + result = LLVOAvatarDefines::TEX_LOWER_JACKET; + } + else if (baked_texind == LLVOAvatarDefines::BAKED_UPPER) + { + result = LLVOAvatarDefines::TEX_UPPER_JACKET; + } + + break; + } + + case LLWearableType::WT_PANTS: + { + if (baked_texind == LLVOAvatarDefines::BAKED_LOWER) + { + result = LLVOAvatarDefines::TEX_LOWER_PANTS; + } + + break; + } + + case LLWearableType::WT_SHIRT: + { + if (baked_texind == LLVOAvatarDefines::BAKED_UPPER) + { + result = LLVOAvatarDefines::TEX_UPPER_SHIRT; + } + + break; + } + + case LLWearableType::WT_SHOES: + { + if (baked_texind == LLVOAvatarDefines::BAKED_LOWER) + { + result = LLVOAvatarDefines::TEX_LOWER_SHOES; + } + + break; + } + + case LLWearableType::WT_SKIN: + { + switch(baked_texind) + { + case LLVOAvatarDefines::BAKED_HEAD: + { + result = LLVOAvatarDefines::TEX_HEAD_BODYPAINT; + break; + } + + case LLVOAvatarDefines::BAKED_LOWER: + { + result = LLVOAvatarDefines::TEX_LOWER_BODYPAINT; + break; + } + case LLVOAvatarDefines::BAKED_UPPER: + { + result = LLVOAvatarDefines::TEX_UPPER_BODYPAINT; + break; + } + + default: + { + break; + } + + } + break; + } + + case LLWearableType::WT_SKIRT: + { + if (baked_texind == LLVOAvatarDefines::BAKED_SKIRT) + { + result = LLVOAvatarDefines::TEX_SKIRT; + } + + break; + } + + case LLWearableType::WT_SOCKS: + { + if (baked_texind == LLVOAvatarDefines::BAKED_LOWER) + { + result = LLVOAvatarDefines::TEX_LOWER_SOCKS; + } + + break; + } + + case LLWearableType::WT_TATTOO: + { + switch(baked_texind) + { + case LLVOAvatarDefines::BAKED_HEAD: + { + result = LLVOAvatarDefines::TEX_HEAD_TATTOO; + break; + } + + case LLVOAvatarDefines::BAKED_LOWER: + { + result = LLVOAvatarDefines::TEX_LOWER_TATTOO; + break; + } + case LLVOAvatarDefines::BAKED_UPPER: + { + result = LLVOAvatarDefines::TEX_UPPER_TATTOO; + break; + } + + default: + { + break; + } + + } + break; + } + + case LLWearableType::WT_UNDERPANTS: + { + if (baked_texind == LLVOAvatarDefines::BAKED_LOWER) + { + result = LLVOAvatarDefines::TEX_LOWER_UNDERPANTS; + } + + break; + } + + case LLWearableType::WT_UNDERSHIRT: + { + if (baked_texind == LLVOAvatarDefines::BAKED_UPPER) + { + result = LLVOAvatarDefines::TEX_UPPER_UNDERSHIRT; + } + + break; + } + + default: + { + llwarns << "Unknown wearable type: " << (int)type << "\n" + << "Baked Texture Index: " << (int)baked_texind << "\n" + << "Filename: " << mFilename << "\n" + << "TrackingID: " << mTrackingID << "\n" + << "InworldID: " << mWorldID << llendl; + } + + } + return result; +} + +/*=======================================*/ +/* LLLocalBitmapTimer: timer class */ +/*=======================================*/ +LLLocalBitmapTimer::LLLocalBitmapTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT) +{ +} + +LLLocalBitmapTimer::~LLLocalBitmapTimer() +{ +} + +void LLLocalBitmapTimer::startTimer() +{ + mEventTimer.start(); +} + +void LLLocalBitmapTimer::stopTimer() +{ + mEventTimer.stop(); +} + +bool LLLocalBitmapTimer::isRunning() +{ + return mEventTimer.getStarted(); +} + +BOOL LLLocalBitmapTimer::tick() +{ + LLLocalBitmapMgr::doUpdates(); + return FALSE; +} + +/*=======================================*/ +/* LLLocalBitmapMgr: manager class */ +/*=======================================*/ +LLLocalBitmapMgr::LLLocalBitmapMgr() +{ + // The class is all made of static members, should i even bother instantiating? +} + +LLLocalBitmapMgr::~LLLocalBitmapMgr() +{ +} + +bool LLLocalBitmapMgr::addUnit() +{ + bool add_successful = false; + + LLFilePicker& picker = LLFilePicker::instance(); + if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) + { + sTimer.stopTimer(); + + std::string filename = picker.getFirstFile(); + while(!filename.empty()) + { + LLLocalBitmap* unit = new LLLocalBitmap(filename); + + if (unit->getValid()) + { + sBitmapList.push_back(unit); + add_successful = true; + } + else + { + llwarns << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" + << "Filename: " << filename << llendl; + + LLSD notif_args; + notif_args["FNAME"] = filename; + LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args); + + delete unit; + unit = NULL; + } + + filename = picker.getNextFile(); + } + + sTimer.startTimer(); + } + + return add_successful; +} + +void LLLocalBitmapMgr::delUnit(LLUUID tracking_id) +{ + if (!sBitmapList.empty()) + { + std::vector<LLLocalBitmap*> to_delete; + for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + { /* finding which ones we want deleted and making a separate list */ + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + to_delete.push_back(unit); + } + } + + for(std::vector<LLLocalBitmap*>::iterator del_iter = to_delete.begin(); + del_iter != to_delete.end(); del_iter++) + { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ + LLLocalBitmap* unit = *del_iter; + sBitmapList.remove(unit); + delete unit; + unit = NULL; + } + } +} + +LLUUID LLLocalBitmapMgr::getWorldID(LLUUID tracking_id) +{ + LLUUID world_id = LLUUID::null; + + for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + world_id = unit->getWorldID(); + } + } + + return world_id; +} + +std::string LLLocalBitmapMgr::getFilename(LLUUID tracking_id) +{ + std::string filename = ""; + + for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + { + LLLocalBitmap* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + filename = unit->getFilename(); + } + } + + return filename; +} + +void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) +{ + if (ctrl) + { + ctrl->clearRows(); + + if (!sBitmapList.empty()) + { + for (local_list_iter iter = sBitmapList.begin(); + iter != sBitmapList.end(); iter++) + { + LLSD element; + element["columns"][0]["column"] = "unit_name"; + element["columns"][0]["type"] = "text"; + element["columns"][0]["value"] = (*iter)->getShortName(); + + element["columns"][1]["column"] = "unit_id_HIDDEN"; + element["columns"][1]["type"] = "text"; + element["columns"][1]["value"] = (*iter)->getTrackingID(); + + ctrl->addElement(element); + } + } + } + +} + +void LLLocalBitmapMgr::doUpdates() +{ + // preventing theoretical overlap in cases with huge number of loaded images. + sTimer.stopTimer(); + sNeedsRebake = false; + + for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++) + { + (*iter)->updateSelf(); + } + + doRebake(); + sTimer.startTimer(); +} + +void LLLocalBitmapMgr::setNeedsRebake() +{ + sNeedsRebake = true; +} + +void LLLocalBitmapMgr::doRebake() +{ /* separated that from doUpdates to insure a rebake can be called separately during deletion */ + if (sNeedsRebake) + { + gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); + sNeedsRebake = false; + } +} + |