storm-64: Local Textures
parent
b187aeb8f1
commit
f71ca07998
|
|
@ -1171,6 +1171,8 @@ Unlikely Quintessa
|
|||
UsikuFarasi Kanarik
|
||||
Vadim Bigbear
|
||||
VWR-2681
|
||||
Vaalith Jinn
|
||||
STORM-64
|
||||
Vector Hastings
|
||||
VWR-8726
|
||||
Veritas Raymaker
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ set(viewer_SOURCE_FILES
|
|||
lllistbrowser.cpp
|
||||
lllistcontextmenu.cpp
|
||||
lllistview.cpp
|
||||
lllocalbitmaps.cpp
|
||||
lllocaltextureobject.cpp
|
||||
lllocationhistory.cpp
|
||||
lllocationinputctrl.cpp
|
||||
|
|
@ -859,6 +860,7 @@ set(viewer_HEADER_FILES
|
|||
lllistbrowser.h
|
||||
lllistcontextmenu.h
|
||||
lllistview.h
|
||||
lllocalbitmaps.h
|
||||
lllocaltextureobject.h
|
||||
lllocationhistory.h
|
||||
lllocationinputctrl.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,925 @@
|
|||
/**
|
||||
* @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"
|
||||
|
||||
/*=======================================*/
|
||||
/* 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.
|
||||
true means the unit's update is running for the first time so it will not check
|
||||
for current usage nor will it attempt to replace the old, non existent image */
|
||||
mValid = updateSelf(true);
|
||||
}
|
||||
|
||||
LLLocalBitmap::~LLLocalBitmap()
|
||||
{
|
||||
// replace IDs with defaults, if set to do so.
|
||||
if(LL_LOCAL_REPLACE_ON_DEL)
|
||||
{
|
||||
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(bool first_update)
|
||||
{
|
||||
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 (!first_update && !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 (!first_update)
|
||||
{
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* @file lllocalbitmaps.h
|
||||
* @author Vaalith Jinn
|
||||
* @brief Local Bitmaps header
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LOCALBITMAPS_H
|
||||
#define LL_LOCALBITMAPS_H
|
||||
|
||||
#include "lleventtimer.h"
|
||||
#include "llwearabletype.h"
|
||||
#include "llvoavatardefines.h"
|
||||
|
||||
class LLScrollListCtrl;
|
||||
|
||||
class LLLocalBitmap
|
||||
{
|
||||
public: /* main */
|
||||
LLLocalBitmap(std::string filename);
|
||||
~LLLocalBitmap();
|
||||
bool updateSelf(bool first_update = false);
|
||||
|
||||
public: /* accessors */
|
||||
std::string getFilename();
|
||||
std::string getShortName();
|
||||
LLUUID getTrackingID();
|
||||
LLUUID getWorldID();
|
||||
bool getValid();
|
||||
|
||||
private: /* maintenance */
|
||||
bool decodeBitmap(LLPointer<LLImageRaw> raw);
|
||||
void replaceIDs(LLUUID old_id, LLUUID new_id);
|
||||
|
||||
private: /* id replacement */
|
||||
std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id);
|
||||
void updateUserPrims(LLUUID old_id, LLUUID new_id);
|
||||
void updateUserSculpts(LLUUID old_id, LLUUID new_id);
|
||||
void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type);
|
||||
LLVOAvatarDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLVOAvatarDefines::EBakedTextureIndex baked_texind);
|
||||
|
||||
private: /* enums */
|
||||
enum ELinkStatus
|
||||
{
|
||||
LS_ON,
|
||||
LS_BROKEN,
|
||||
};
|
||||
|
||||
enum EExtension
|
||||
{
|
||||
ET_IMG_BMP,
|
||||
ET_IMG_TGA,
|
||||
ET_IMG_JPG,
|
||||
ET_IMG_PNG
|
||||
};
|
||||
|
||||
private: /* members */
|
||||
std::string mFilename;
|
||||
std::string mShortName;
|
||||
LLUUID mTrackingID;
|
||||
LLUUID mWorldID;
|
||||
bool mValid;
|
||||
LLSD mLastModified;
|
||||
EExtension mExtension;
|
||||
ELinkStatus mLinkStatus;
|
||||
S32 mUpdateRetries;
|
||||
|
||||
};
|
||||
|
||||
class LLLocalBitmapTimer : public LLEventTimer
|
||||
{
|
||||
public:
|
||||
LLLocalBitmapTimer();
|
||||
~LLLocalBitmapTimer();
|
||||
|
||||
public:
|
||||
void startTimer();
|
||||
void stopTimer();
|
||||
bool isRunning();
|
||||
BOOL tick();
|
||||
|
||||
};
|
||||
|
||||
class LLLocalBitmapMgr
|
||||
{
|
||||
public:
|
||||
LLLocalBitmapMgr();
|
||||
~LLLocalBitmapMgr();
|
||||
|
||||
public:
|
||||
static bool addUnit();
|
||||
static void delUnit(LLUUID tracking_id);
|
||||
|
||||
static LLUUID getWorldID(LLUUID tracking_id);
|
||||
static std::string getFilename(LLUUID tracking_id);
|
||||
|
||||
static void feedScrollList(LLScrollListCtrl* ctrl);
|
||||
static void doUpdates();
|
||||
static void setNeedsRebake();
|
||||
static void doRebake();
|
||||
|
||||
private:
|
||||
static std::list<LLLocalBitmap*> sBitmapList;
|
||||
static LLLocalBitmapTimer sTimer;
|
||||
static bool sNeedsRebake;
|
||||
typedef std::list<LLLocalBitmap*>::iterator local_list_iter;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -67,6 +67,9 @@
|
|||
#include "lluictrlfactory.h"
|
||||
#include "lltrans.h"
|
||||
|
||||
#include "llradiogroup.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "lllocalbitmaps.h"
|
||||
|
||||
static const S32 HPAD = 4;
|
||||
static const S32 VPAD = 4;
|
||||
|
|
@ -78,6 +81,8 @@ static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
|
|||
static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
|
||||
static const F32 CONTEXT_FADE_TIME = 0.08f;
|
||||
|
||||
static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
|
||||
|
||||
//static const char CURRENT_IMAGE_NAME[] = "Current Texture";
|
||||
//static const char WHITE_IMAGE_NAME[] = "Blank Texture";
|
||||
//static const char NO_IMAGE_NAME[] = "None";
|
||||
|
|
@ -142,6 +147,12 @@ public:
|
|||
static void onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata);
|
||||
void onTextureSelect( const LLTextureEntry& te );
|
||||
|
||||
static void onModeSelect(LLUICtrl* ctrl, void *userdata);
|
||||
static void onBtnAdd(void* userdata);
|
||||
static void onBtnRemove(void* userdata);
|
||||
static void onBtnUpload(void* userdata);
|
||||
static void onLocalScrollCommit(LLUICtrl* ctrl, void* userdata);
|
||||
|
||||
protected:
|
||||
LLPointer<LLViewerTexture> mTexturep;
|
||||
LLTextureCtrl* mOwner;
|
||||
|
|
@ -169,8 +180,10 @@ protected:
|
|||
BOOL mNoCopyTextureSelected;
|
||||
F32 mContextConeOpacity;
|
||||
LLSaveFolderState mSavedFolderState;
|
||||
|
||||
BOOL mSelectedItemPinned;
|
||||
|
||||
LLRadioGroup* mModeSelector;
|
||||
LLScrollListCtrl* mLocalScrollCtrl;
|
||||
};
|
||||
|
||||
LLFloaterTexturePicker::LLFloaterTexturePicker(
|
||||
|
|
@ -437,6 +450,17 @@ BOOL LLFloaterTexturePicker::postBuild()
|
|||
mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO);
|
||||
}
|
||||
|
||||
mModeSelector = getChild<LLRadioGroup>("mode_selection");
|
||||
mModeSelector->setCommitCallback(onModeSelect, this);
|
||||
mModeSelector->setSelectedIndex(0, 0);
|
||||
|
||||
childSetAction("l_add_btn", LLFloaterTexturePicker::onBtnAdd, this);
|
||||
childSetAction("l_rem_btn", LLFloaterTexturePicker::onBtnRemove, this);
|
||||
childSetAction("l_upl_btn", LLFloaterTexturePicker::onBtnUpload, this);
|
||||
|
||||
mLocalScrollCtrl = getChild<LLScrollListCtrl>("l_name_list");
|
||||
mLocalScrollCtrl->setCommitCallback(onLocalScrollCommit, this);
|
||||
LLLocalBitmapMgr::feedScrollList(mLocalScrollCtrl);
|
||||
|
||||
mNoCopyTextureSelected = FALSE;
|
||||
|
||||
|
|
@ -464,7 +488,6 @@ BOOL LLFloaterTexturePicker::postBuild()
|
|||
// virtual
|
||||
void LLFloaterTexturePicker::draw()
|
||||
{
|
||||
S32 floater_header_size = getHeaderHeight();
|
||||
if (mOwner)
|
||||
{
|
||||
// draw cone of context pointing back to texture swatch
|
||||
|
|
@ -554,10 +577,7 @@ void LLFloaterTexturePicker::draw()
|
|||
}
|
||||
|
||||
// Border
|
||||
LLRect border( BORDER_PAD,
|
||||
getRect().getHeight() - floater_header_size - BORDER_PAD,
|
||||
((getMinWidth() / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD,
|
||||
BORDER_PAD + FOOTER_HEIGHT + (getRect().getHeight() - getMinHeight()));
|
||||
LLRect border = getChildView("preview_widget")->getRect();
|
||||
gl_rect_2d( border, LLColor4::black, FALSE );
|
||||
|
||||
|
||||
|
|
@ -748,7 +768,15 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata)
|
|||
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
|
||||
if (self->mOwner)
|
||||
{
|
||||
self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT);
|
||||
LLUUID local_id = LLUUID::null;
|
||||
|
||||
if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty())
|
||||
{
|
||||
LLUUID temp_id = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID();
|
||||
local_id = LLLocalBitmapMgr::getWorldID(temp_id);
|
||||
}
|
||||
|
||||
self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT, local_id);
|
||||
}
|
||||
self->closeFloater();
|
||||
}
|
||||
|
|
@ -791,6 +819,112 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata)
|
||||
{
|
||||
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
|
||||
bool mode = (self->mModeSelector->getSelectedIndex() == 0);
|
||||
|
||||
self->getChild<LLButton>("Default")->setVisible(mode);
|
||||
self->getChild<LLButton>("Blank")->setVisible(mode);
|
||||
self->getChild<LLButton>("None")->setVisible(mode);
|
||||
self->getChild<LLButton>("Pipette")->setVisible(mode);
|
||||
self->getChild<LLFilterEditor>("inventory search editor")->setVisible(mode);
|
||||
self->getChild<LLInventoryPanel>("inventory panel")->setVisible(mode);
|
||||
|
||||
/*self->getChild<LLCheckBox>("show_folders_check")->setVisible(mode);
|
||||
no idea under which conditions the above is even shown, needs testing. */
|
||||
|
||||
self->getChild<LLButton>("l_add_btn")->setVisible(!mode);
|
||||
self->getChild<LLButton>("l_rem_btn")->setVisible(!mode);
|
||||
self->getChild<LLButton>("l_upl_btn")->setVisible(!mode);
|
||||
self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(!mode);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterTexturePicker::onBtnAdd(void* userdata)
|
||||
{
|
||||
if (LLLocalBitmapMgr::addUnit() == true)
|
||||
{
|
||||
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
|
||||
LLLocalBitmapMgr::feedScrollList(self->mLocalScrollCtrl);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterTexturePicker::onBtnRemove(void* userdata)
|
||||
{
|
||||
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
|
||||
std::vector<LLScrollListItem*> selected_items = self->mLocalScrollCtrl->getAllSelected();
|
||||
|
||||
if (!selected_items.empty())
|
||||
{
|
||||
for(std::vector<LLScrollListItem*>::iterator iter = selected_items.begin();
|
||||
iter != selected_items.end(); iter++)
|
||||
{
|
||||
LLScrollListItem* list_item = *iter;
|
||||
if (list_item)
|
||||
{
|
||||
LLUUID tracking_id = list_item->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID();
|
||||
LLLocalBitmapMgr::delUnit(tracking_id);
|
||||
}
|
||||
}
|
||||
|
||||
self->getChild<LLButton>("l_rem_btn")->setEnabled(false);
|
||||
self->getChild<LLButton>("l_upl_btn")->setEnabled(false);
|
||||
LLLocalBitmapMgr::feedScrollList(self->mLocalScrollCtrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterTexturePicker::onBtnUpload(void* userdata)
|
||||
{
|
||||
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
|
||||
std::vector<LLScrollListItem*> selected_items = self->mLocalScrollCtrl->getAllSelected();
|
||||
|
||||
if (selected_items.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* currently only allows uploading one by one, picks the first item from the selection list. (not the vector!)
|
||||
in the future, it might be a good idea to check the vector size and if more than one units is selected - opt for multi-image upload. */
|
||||
|
||||
LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN);
|
||||
std::string filename = LLLocalBitmapMgr::getFilename(tracking_id);
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
LLFloaterReg::showInstance("upload_image", LLSD(filename));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata)
|
||||
{
|
||||
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
|
||||
std::vector<LLScrollListItem*> selected_items = self->mLocalScrollCtrl->getAllSelected();
|
||||
bool has_selection = !selected_items.empty();
|
||||
|
||||
self->getChild<LLButton>("l_rem_btn")->setEnabled(has_selection);
|
||||
self->getChild<LLButton>("l_upl_btn")->setEnabled(has_selection && (selected_items.size() < 2));
|
||||
/* since multiple-localbitmap upload is not implemented, upl button gets disabled if more than one is selected. */
|
||||
|
||||
if (has_selection)
|
||||
{
|
||||
LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN);
|
||||
LLUUID inworld_id = LLLocalBitmapMgr::getWorldID(tracking_id);
|
||||
self->mOwner->setImageAssetID(inworld_id);
|
||||
|
||||
if (self->childGetValue("apply_immediate_check").asBoolean())
|
||||
{
|
||||
self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE, inworld_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterTexturePicker::onShowFolders(LLUICtrl* ctrl, void *user_data)
|
||||
{
|
||||
|
|
@ -1126,7 +1260,7 @@ void LLTextureCtrl::onFloaterClose()
|
|||
mFloaterHandle.markDead();
|
||||
}
|
||||
|
||||
void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
|
||||
void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
|
||||
{
|
||||
LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
|
||||
|
||||
|
|
@ -1139,14 +1273,24 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
|
|||
// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
|
||||
else if (mCommitOnSelection || op == TEXTURE_SELECT)
|
||||
mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
|
||||
|
||||
if( floaterp->isDirty() )
|
||||
|
||||
if(floaterp->isDirty() || id.notNull()) // mModelView->setDirty does not work.
|
||||
{
|
||||
setTentative( FALSE );
|
||||
mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
|
||||
lldebugs << "mImageItemID: " << mImageItemID << llendl;
|
||||
mImageAssetID = floaterp->getAssetID();
|
||||
lldebugs << "mImageAssetID: " << mImageAssetID << llendl;
|
||||
|
||||
if (id.notNull())
|
||||
{
|
||||
mImageItemID = id;
|
||||
mImageAssetID = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
|
||||
lldebugs << "mImageItemID: " << mImageItemID << llendl;
|
||||
mImageAssetID = floaterp->getAssetID();
|
||||
lldebugs << "mImageAssetID: " << mImageAssetID << llendl;
|
||||
}
|
||||
|
||||
if (op == TEXTURE_SELECT && mOnSelectCallback)
|
||||
{
|
||||
mOnSelectCallback( this, LLSD() );
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ public:
|
|||
void closeDependentFloater();
|
||||
|
||||
void onFloaterClose();
|
||||
void onFloaterCommit(ETexturePickOp op);
|
||||
void onFloaterCommit(ETexturePickOp op, LLUUID id = LLUUID::null);
|
||||
|
||||
// This call is returned when a drag is detected. Your callback
|
||||
// should return TRUE if the drag is acceptable.
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ class LLViewerTextureList
|
|||
|
||||
friend class LLTextureView;
|
||||
friend class LLViewerTextureManager;
|
||||
friend class LLLocalBitmap;
|
||||
|
||||
public:
|
||||
static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec);
|
||||
|
|
|
|||
|
|
@ -810,6 +810,20 @@ const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
|
|||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
|
||||
{
|
||||
std::vector<LLLocalTextureObject*> result;
|
||||
|
||||
for(te_map_t::const_iterator iter = mTEMap.begin();
|
||||
iter != mTEMap.end(); iter++)
|
||||
{
|
||||
LLLocalTextureObject* lto = iter->second;
|
||||
result.push_back(lto);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o)
|
||||
{
|
||||
if( mTEMap.find(index) != mTEMap.end() )
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ public:
|
|||
|
||||
LLLocalTextureObject* getLocalTextureObject(S32 index);
|
||||
const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
|
||||
std::vector<LLLocalTextureObject*> getLocalTextureListSeq();
|
||||
|
||||
void setLocalTextureObject(S32 index, LLLocalTextureObject <o);
|
||||
void addVisualParam(LLVisualParam *param);
|
||||
|
|
|
|||
|
|
@ -3,15 +3,17 @@
|
|||
legacy_header_height="18"
|
||||
can_minimize="false"
|
||||
can_resize="true"
|
||||
height="290"
|
||||
height="330"
|
||||
layout="topleft"
|
||||
min_height="290"
|
||||
min_height="330"
|
||||
min_width="410"
|
||||
name="texture picker"
|
||||
help_topic="texture_picker"
|
||||
title="PICK: TEXTURE"
|
||||
width="410">
|
||||
<floater.string
|
||||
|
||||
<!-- top static -->
|
||||
<floater.string
|
||||
name="choose_picture">
|
||||
Click to choose a picture
|
||||
</floater.string>
|
||||
|
|
@ -19,6 +21,16 @@
|
|||
name="pick title">
|
||||
Pick:
|
||||
</floater.string>
|
||||
|
||||
<view
|
||||
left="4"
|
||||
top="20"
|
||||
name="preview_widget"
|
||||
height="165"
|
||||
width="165"
|
||||
follows="left|top"
|
||||
/>
|
||||
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
|
|
@ -34,70 +46,94 @@
|
|||
width="163">
|
||||
Multiple textures
|
||||
</text>
|
||||
|
||||
<!-- mode selector -->
|
||||
<radio_group
|
||||
control_name="mode_selection"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left="18"
|
||||
top_pad="80"
|
||||
name="mode_selection"
|
||||
follows="left|top">
|
||||
<radio_item
|
||||
label="Inventory"
|
||||
name="inventory"
|
||||
top_delta="20"
|
||||
layout="topleft"
|
||||
height="16"
|
||||
left="0"
|
||||
value="0"
|
||||
width="80" />
|
||||
<radio_item
|
||||
label="Local"
|
||||
left_pad="0"
|
||||
layout="topleft"
|
||||
top_delta="0"
|
||||
height="16"
|
||||
name="local"
|
||||
value="1"
|
||||
width="75" />
|
||||
</radio_group>
|
||||
<!-- -->
|
||||
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
follows="left|top"
|
||||
height="14"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
left_delta="-12"
|
||||
name="unknown"
|
||||
top_pad="80"
|
||||
width="163">
|
||||
top_pad="4"
|
||||
width="">
|
||||
Size: [DIMENSIONS]
|
||||
</text>
|
||||
|
||||
<!-- middle: inventory mode -->
|
||||
|
||||
<button
|
||||
enabled="false"
|
||||
follows="left|bottom"
|
||||
height="20"
|
||||
follows="left|top"
|
||||
height="18"
|
||||
label="Default"
|
||||
label_selected="Default"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="Default"
|
||||
top_pad="4"
|
||||
width="80" />
|
||||
width="73"
|
||||
left="94"
|
||||
top="215"/>
|
||||
<button
|
||||
enabled="false"
|
||||
follows="left|bottom"
|
||||
height="20"
|
||||
label="None"
|
||||
label_selected="None"
|
||||
layout="topleft"
|
||||
left_pad="4"
|
||||
name="None"
|
||||
top_delta="0"
|
||||
width="80" />
|
||||
<button
|
||||
follows="left|bottom"
|
||||
follows="left|top"
|
||||
height="20"
|
||||
label="Blank"
|
||||
label_selected="Blank"
|
||||
layout="topleft"
|
||||
left="4"
|
||||
left_delta="0"
|
||||
name="Blank"
|
||||
top_pad="5"
|
||||
width="80" />
|
||||
<button
|
||||
follows="left|bottom"
|
||||
width="73" />
|
||||
<button
|
||||
enabled="false"
|
||||
follows="left|top"
|
||||
height="20"
|
||||
label="None"
|
||||
label_selected="None"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="None"
|
||||
top_pad="5"
|
||||
width="73" />
|
||||
<button
|
||||
follows="left|top"
|
||||
height="28"
|
||||
image_selected="eye_button_active.tga"
|
||||
image_unselected="eye_button_inactive.tga"
|
||||
layout="topleft"
|
||||
left_pad="50"
|
||||
top_delta="3"
|
||||
left_delta="-80"
|
||||
top_delta="-25"
|
||||
name="Pipette"
|
||||
width="28" />
|
||||
<check_box
|
||||
follows="left|bottom"
|
||||
height="20"
|
||||
initial_value="true"
|
||||
label="Apply now"
|
||||
layout="topleft"
|
||||
left="4"
|
||||
name="apply_immediate_check"
|
||||
top="262"
|
||||
width="120" />
|
||||
<filter_editor
|
||||
follows="left|top|right"
|
||||
height="23"
|
||||
|
|
@ -113,7 +149,7 @@
|
|||
bg_alpha_color="DkGray2"
|
||||
border="false"
|
||||
follows="all"
|
||||
height="200"
|
||||
height="233"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="inventory panel"
|
||||
|
|
@ -128,23 +164,89 @@
|
|||
top_pad="0"
|
||||
left_delta="-3"
|
||||
width="200" />
|
||||
<button
|
||||
follows="right|bottom"
|
||||
|
||||
<!-- middle: local mode -->
|
||||
<button
|
||||
follows="left|top"
|
||||
height="18"
|
||||
label="Add"
|
||||
label_selected="Add"
|
||||
layout="topleft"
|
||||
left="94"
|
||||
top="215"
|
||||
name="l_add_btn"
|
||||
width="73"
|
||||
visible="false"/>
|
||||
<button
|
||||
enabled="false"
|
||||
follows="left|top"
|
||||
height="20"
|
||||
label="Remove"
|
||||
label_selected="Remove"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="l_rem_btn"
|
||||
top_pad="5"
|
||||
width="73"
|
||||
visible="false"/>
|
||||
<button
|
||||
enabled="false"
|
||||
follows="left|top"
|
||||
height="20"
|
||||
label="Upload"
|
||||
label_selected="Upload"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="l_upl_btn"
|
||||
top_pad="5"
|
||||
width="73"
|
||||
visible="false"/>
|
||||
<scroll_list
|
||||
name="l_name_list"
|
||||
left="170"
|
||||
top="22"
|
||||
width="235"
|
||||
height="260"
|
||||
follows="left|top|right|bottom"
|
||||
column_padding="0"
|
||||
can_resize="false"
|
||||
draw_heading="true"
|
||||
multi_select="true"
|
||||
search_column="1"
|
||||
visible="false">
|
||||
<column name="unit_name" label="Name" dynamicwidth="true" />
|
||||
<column name="unit_id_HIDDEN" label="ID" width="0" />
|
||||
</scroll_list>
|
||||
|
||||
<!-- bottom static -->
|
||||
<button
|
||||
follows="bottom"
|
||||
height="20"
|
||||
label="OK"
|
||||
label_selected="OK"
|
||||
layout="topleft"
|
||||
right="-120"
|
||||
left="95"
|
||||
top="-30"
|
||||
name="Select"
|
||||
width="100" />
|
||||
<button
|
||||
follows="right|bottom"
|
||||
follows="bottom"
|
||||
height="20"
|
||||
label="Cancel"
|
||||
label_selected="Cancel"
|
||||
layout="topleft"
|
||||
right="-10"
|
||||
left_pad="5"
|
||||
left_delta="120"
|
||||
top_delta="0"
|
||||
name="Cancel"
|
||||
width="100" />
|
||||
<check_box
|
||||
follows="left|bottom"
|
||||
height="20"
|
||||
initial_value="true"
|
||||
label="Apply now"
|
||||
layout="topleft"
|
||||
left="6"
|
||||
name="apply_immediate_check"
|
||||
top_delta="0"
|
||||
width="120" />
|
||||
</floater>
|
||||
|
|
|
|||
Loading…
Reference in New Issue