* BakeLayer.FinalData is public now

* Added baked texture uploading support to Utilities.AppearanceManager

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@1004 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2007-02-23 02:23:30 +00:00
parent 636a13f997
commit e1157504ac
2 changed files with 159 additions and 43 deletions

View File

@@ -61,6 +61,8 @@ namespace libsecondlife
/// <summary>Maximum number of wearables for any baked layer</summary> /// <summary>Maximum number of wearables for any baked layer</summary>
public const int WEARABLES_PER_LAYER = 7; public const int WEARABLES_PER_LAYER = 7;
/// <summary>Final compressed JPEG2000 data</summary>
public byte[] FinalData = new byte[0];
/// <summary>Whether this bake is complete or not</summary> /// <summary>Whether this bake is complete or not</summary>
public bool Finished = false; public bool Finished = false;
@@ -74,8 +76,6 @@ namespace libsecondlife
protected Bitmap Scratchpad; protected Bitmap Scratchpad;
/// <summary>List of textures sorted by their baking order</summary> /// <summary>List of textures sorted by their baking order</summary>
protected SortedList<BakeOrder, byte[]> Textures = new SortedList<BakeOrder, byte[]>(WEARABLES_PER_LAYER); protected SortedList<BakeOrder, byte[]> Textures = new SortedList<BakeOrder, byte[]>(WEARABLES_PER_LAYER);
/// <summary>Final compressed JPEG2000 data</summary>
protected byte[] FinalData = new byte[0];
/// <summary>Width of the final baked image and scratchpad</summary> /// <summary>Width of the final baked image and scratchpad</summary>
protected int BakeWidth = 512; protected int BakeWidth = 512;
/// <summary>Height of the final baked image and scratchpad</summary> /// <summary>Height of the final baked image and scratchpad</summary>

View File

@@ -456,14 +456,16 @@ namespace libsecondlife.Utilities.Appearance
private AssetManager Assets; private AssetManager Assets;
private Dictionary<Wearable.WearableType, WearableData> Wearables = new Dictionary<Wearable.WearableType, WearableData>(); private Dictionary<Wearable.WearableType, WearableData> Wearables = new Dictionary<Wearable.WearableType, WearableData>();
// As wearable assets are downloaded and decoded, the textures are added to this list // As wearable assets are downloaded and decoded, the textures are added to this list
private Dictionary<int, LLUUID> AgentTextures = new Dictionary<int, LLUUID>(); private Dictionary<TextureIndex, LLUUID> AgentTextures = new Dictionary<TextureIndex, LLUUID>();
// Wearable assets are downloaded one at a time, a new request is pulled off the queue // Wearable assets are downloaded one at a time, a new request is pulled off the queue
// and started when the previous one completes // and started when the previous one completes
private Queue<KeyValuePair<LLUUID, AssetType>> DownloadQueue = new Queue<KeyValuePair<LLUUID, AssetType>>(); private Queue<KeyValuePair<LLUUID, AssetType>> DownloadQueue = new Queue<KeyValuePair<LLUUID, AssetType>>();
// A list of all the images we are currently downloading, prior to baking // A list of all the images we are currently downloading, prior to baking
private Dictionary<LLUUID, TextureIndex> ImageDownloads = new Dictionary<LLUUID, TextureIndex>(); private Dictionary<LLUUID, TextureIndex> ImageDownloads = new Dictionary<LLUUID, TextureIndex>();
// A list of all the bakes we need to complete // A list of all the bakes we need to complete
private List<BakeLayer> PendingBakes = new List<BakeLayer>(BAKED_TEXTURE_COUNT); private Dictionary<BakeType, BakeLayer> PendingBakes = new Dictionary<BakeType, BakeLayer>(BAKED_TEXTURE_COUNT);
// A list of all the uploads that are in progress
private Dictionary<LLUUID, TextureIndex> PendingUploads = new Dictionary<LLUUID, TextureIndex>(BAKED_TEXTURE_COUNT);
// Whether the handler for our current wearable list should automatically start downloading the assets // Whether the handler for our current wearable list should automatically start downloading the assets
private bool DownloadWearables = false; private bool DownloadWearables = false;
private int CacheCheckSerialNum = 0; private int CacheCheckSerialNum = 0;
@@ -608,12 +610,12 @@ namespace libsecondlife.Utilities.Appearance
DownloadWearables = true; DownloadWearables = true;
// Register an asset download callback to get wearable data // Register an asset download callback to get wearable data
AssetManager.AssetReceivedCallback assetCallback = AssetManager.AssetReceivedCallback assetCallback = new AssetManager.AssetReceivedCallback(Assets_OnAssetReceived);
new AssetManager.AssetReceivedCallback(Assets_OnAssetReceived); AssetManager.ImageReceivedCallback imageCallback = new AssetManager.ImageReceivedCallback(Assets_OnImageReceived);
AssetManager.ImageReceivedCallback imageCallback = AssetManager.AssetUploadedCallback uploadCallback = new AssetManager.AssetUploadedCallback(Assets_OnAssetUploaded);
new AssetManager.ImageReceivedCallback(Assets_OnImageReceived);
Assets.OnAssetReceived += assetCallback; Assets.OnAssetReceived += assetCallback;
Assets.OnImageReceived += imageCallback; Assets.OnImageReceived += imageCallback;
Assets.OnAssetUploaded += uploadCallback;
// Ask the server what we are currently wearing // Ask the server what we are currently wearing
RequestAgentWearables(); RequestAgentWearables();
@@ -633,8 +635,9 @@ namespace libsecondlife.Utilities.Appearance
CachedResponseEvent.WaitOne(); CachedResponseEvent.WaitOne();
// Unregister the image download callback // Unregister the image download and asset upload callbacks
Assets.OnImageReceived -= imageCallback; Assets.OnImageReceived -= imageCallback;
Assets.OnAssetUploaded -= uploadCallback;
Client.DebugLog("CachedResponseEvent completed"); Client.DebugLog("CachedResponseEvent completed");
@@ -690,7 +693,7 @@ namespace libsecondlife.Utilities.Appearance
// Put our AgentTextures dictionary in to TextureEntry // Put our AgentTextures dictionary in to TextureEntry
lock (AgentTextures) lock (AgentTextures)
{ {
foreach (KeyValuePair<int, LLUUID> texture in AgentTextures) foreach (KeyValuePair<TextureIndex, LLUUID> texture in AgentTextures)
{ {
LLObject.TextureEntryFace face = te.CreateFace((uint)texture.Key); LLObject.TextureEntryFace face = te.CreateFace((uint)texture.Key);
face.TextureID = texture.Value; face.TextureID = texture.Value;
@@ -775,22 +778,22 @@ namespace libsecondlife.Utilities.Appearance
Client.Network.SendPacket(wearing); Client.Network.SendPacket(wearing);
} }
private int BakedIndexToAgentTextureIndex(int index) private TextureIndex BakedIndexToAgentTextureIndex(BakeType index)
{ {
switch ((BakeType)index) switch (index)
{ {
case BakeType.Head: case BakeType.Head:
return 8; return TextureIndex.HeadBaked;
case BakeType.UpperBody: case BakeType.UpperBody:
return 9; return TextureIndex.UpperBaked;
case BakeType.LowerBody: case BakeType.LowerBody:
return 10; return TextureIndex.LowerBaked;
case BakeType.Eyes: case BakeType.Eyes:
return 11; return TextureIndex.EyesBaked;
case BakeType.Skirt: case BakeType.Skirt:
return 19; return TextureIndex.SkirtBaked;
default: default:
return (int)TextureIndex.Unknown; return TextureIndex.Unknown;
} }
} }
@@ -903,7 +906,7 @@ namespace libsecondlife.Utilities.Appearance
// Convert the baked index to an AgentTexture index // Convert the baked index to an AgentTexture index
if (block.TextureID != LLUUID.Zero && host.Length == 0) if (block.TextureID != LLUUID.Zero && host.Length == 0)
{ {
int index = BakedIndexToAgentTextureIndex(block.TextureIndex); TextureIndex index = BakedIndexToAgentTextureIndex((BakeType)block.TextureIndex);
AgentTextures[index] = block.TextureID; AgentTextures[index] = block.TextureID;
} }
else else
@@ -915,39 +918,39 @@ namespace libsecondlife.Utilities.Appearance
case BakeType.Head: case BakeType.Head:
lock (ImageDownloads) lock (ImageDownloads)
{ {
PendingBakes.Add(new BakeLayer(Client, 2, paramValues)); PendingBakes.Add(BakeType.Head, new BakeLayer(Client, 2, paramValues));
ImageDownloads.Add(AgentTextures[(int)TextureIndex.HeadBodypaint], TextureIndex.HeadBodypaint); ImageDownloads.Add(AgentTextures[TextureIndex.HeadBodypaint], TextureIndex.HeadBodypaint);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.Hair], TextureIndex.Hair); ImageDownloads.Add(AgentTextures[TextureIndex.Hair], TextureIndex.Hair);
} }
break; break;
case BakeType.UpperBody: case BakeType.UpperBody:
lock (ImageDownloads) lock (ImageDownloads)
{ {
PendingBakes.Add(new BakeLayer(Client, 4, paramValues)); PendingBakes.Add(BakeType.UpperBody, new BakeLayer(Client, 4, paramValues));
ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperBodypaint], TextureIndex.UpperBodypaint); ImageDownloads.Add(AgentTextures[TextureIndex.UpperBodypaint], TextureIndex.UpperBodypaint);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperUndershirt], TextureIndex.UpperUndershirt); ImageDownloads.Add(AgentTextures[TextureIndex.UpperUndershirt], TextureIndex.UpperUndershirt);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperShirt], TextureIndex.UpperShirt); ImageDownloads.Add(AgentTextures[TextureIndex.UpperShirt], TextureIndex.UpperShirt);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperJacket], TextureIndex.UpperJacket); ImageDownloads.Add(AgentTextures[TextureIndex.UpperJacket], TextureIndex.UpperJacket);
// TODO: Where are the gloves? // TODO: Where are the gloves?
} }
break; break;
case BakeType.LowerBody: case BakeType.LowerBody:
lock (ImageDownloads) lock (ImageDownloads)
{ {
PendingBakes.Add(new BakeLayer(Client, 6, paramValues)); PendingBakes.Add(BakeType.LowerBody, new BakeLayer(Client, 6, paramValues));
ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerBodypaint], TextureIndex.LowerBodypaint); ImageDownloads.Add(AgentTextures[TextureIndex.LowerBodypaint], TextureIndex.LowerBodypaint);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerUnderpants], TextureIndex.LowerUnderpants); ImageDownloads.Add(AgentTextures[TextureIndex.LowerUnderpants], TextureIndex.LowerUnderpants);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerSocks], TextureIndex.LowerSocks); ImageDownloads.Add(AgentTextures[TextureIndex.LowerSocks], TextureIndex.LowerSocks);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerShoes], TextureIndex.LowerShoes); ImageDownloads.Add(AgentTextures[TextureIndex.LowerShoes], TextureIndex.LowerShoes);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerPants], TextureIndex.LowerPants); ImageDownloads.Add(AgentTextures[TextureIndex.LowerPants], TextureIndex.LowerPants);
ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerJacket], TextureIndex.LowerJacket); ImageDownloads.Add(AgentTextures[TextureIndex.LowerJacket], TextureIndex.LowerJacket);
} }
break; break;
case BakeType.Eyes: case BakeType.Eyes:
lock (ImageDownloads) lock (ImageDownloads)
{ {
PendingBakes.Add(new BakeLayer(Client, 1, paramValues)); PendingBakes.Add(BakeType.Eyes, new BakeLayer(Client, 1, paramValues));
ImageDownloads.Add(AgentTextures[(int)TextureIndex.EyesIris], TextureIndex.EyesIris); ImageDownloads.Add(AgentTextures[TextureIndex.EyesIris], TextureIndex.EyesIris);
} }
break; break;
case BakeType.Skirt: case BakeType.Skirt:
@@ -955,8 +958,8 @@ namespace libsecondlife.Utilities.Appearance
{ {
lock (ImageDownloads) lock (ImageDownloads)
{ {
PendingBakes.Add(new BakeLayer(Client, 1, paramValues)); PendingBakes.Add(BakeType.Skirt, new BakeLayer(Client, 1, paramValues));
ImageDownloads.Add(AgentTextures[(int)TextureIndex.Skirt], TextureIndex.Skirt); ImageDownloads.Add(AgentTextures[TextureIndex.Skirt], TextureIndex.Skirt);
} }
} }
break; break;
@@ -1007,7 +1010,7 @@ namespace libsecondlife.Utilities.Appearance
lock (AgentTextures) lock (AgentTextures)
{ {
foreach (KeyValuePair<int, LLUUID> texture in data.Wearable.Textures) foreach (KeyValuePair<int, LLUUID> texture in data.Wearable.Textures)
AgentTextures[texture.Key] = texture.Value; AgentTextures[(TextureIndex)texture.Key] = texture.Value;
} }
Client.DebugLog("Imported wearable asset " + data.Wearable.Type.ToString()); Client.DebugLog("Imported wearable asset " + data.Wearable.Type.ToString());
@@ -1050,11 +1053,92 @@ namespace libsecondlife.Utilities.Appearance
if (ImageDownloads.ContainsKey(image.ID)) if (ImageDownloads.ContainsKey(image.ID))
{ {
TextureIndex index = ImageDownloads[image.ID]; TextureIndex index = ImageDownloads[image.ID];
BakeType type = BakeType.Head;
BakeLayer.BakeOrder order = BakeLayer.BakeOrder.HeadBodypaint;
if (image.Success) if (image.Success)
{ {
// FIXME: Add this image to a baking layer // Add this image to a baking layer
// FIXME: If true is returned, the bake is complete and we can fetch the finished jp2 data switch (index)
{
case TextureIndex.HeadBodypaint:
type = BakeType.Head;
order = BakeLayer.BakeOrder.HeadBodypaint;
break;
case TextureIndex.Hair:
type = BakeType.Head;
order = BakeLayer.BakeOrder.Hair;
break;
case TextureIndex.UpperBodypaint:
type = BakeType.UpperBody;
order = BakeLayer.BakeOrder.UpperBodypaint;
break;
case TextureIndex.UpperUndershirt:
type = BakeType.UpperBody;
order = BakeLayer.BakeOrder.UpperUndershirt;
break;
case TextureIndex.UpperShirt:
type = BakeType.UpperBody;
order = BakeLayer.BakeOrder.UpperShirt;
break;
case TextureIndex.UpperJacket:
type = BakeType.UpperBody;
order = BakeLayer.BakeOrder.UpperJacket;
break;
case TextureIndex.LowerBodypaint:
type = BakeType.LowerBody;
order = BakeLayer.BakeOrder.LowerBodypaint;
break;
case TextureIndex.LowerUnderpants:
type = BakeType.LowerBody;
order = BakeLayer.BakeOrder.LowerUnderpants;
break;
case TextureIndex.LowerSocks:
type = BakeType.LowerBody;
order = BakeLayer.BakeOrder.LowerSocks;
break;
case TextureIndex.LowerShoes:
type = BakeType.LowerBody;
order = BakeLayer.BakeOrder.LowerShoes;
break;
case TextureIndex.LowerPants:
type = BakeType.LowerBody;
order = BakeLayer.BakeOrder.LowerPants;
break;
case TextureIndex.LowerJacket:
type = BakeType.LowerBody;
order = BakeLayer.BakeOrder.LowerJacket;
break;
case TextureIndex.EyesIris:
type = BakeType.Eyes;
order = BakeLayer.BakeOrder.EyesIris;
break;
case TextureIndex.Skirt:
type = BakeType.Skirt;
order = BakeLayer.BakeOrder.Skirt;
break;
default:
Client.Log("Image downloaded for unknown TextureIndex " + index.ToString(),
Helpers.LogLevel.Warning);
break;
}
if (PendingBakes.ContainsKey(type) && PendingBakes[type].AddImage(order, image.AssetData))
{
// Create a transactionID and assetID for this upload
LLUUID transactionID = LLUUID.Random();
LLUUID assetID = transactionID.Combine(Client.Network.SecureSessionID);
// Upload the completed bake data
Assets.RequestUpload(transactionID, AssetType.Texture, PendingBakes[type].FinalData,
true, true, false);
// Add it to a pending uploads list
lock (PendingUploads) PendingUploads.Add(assetID, index);
// Remove this bake from the pending list
PendingBakes.Remove(type);
}
} }
else else
{ {
@@ -1064,13 +1148,45 @@ namespace libsecondlife.Utilities.Appearance
ImageDownloads.Remove(image.ID); ImageDownloads.Remove(image.ID);
if (ImageDownloads.Count == 0) if (ImageDownloads.Count == 0 && PendingUploads.Count == 0)
{ {
// All the images have been downloaded and the baking is finished // This is a failsafe catch, as the upload completed callback should normally
// be triggering the event
CachedResponseEvent.Set(); CachedResponseEvent.Set();
} }
} }
} }
} }
private void Assets_OnAssetUploaded(AssetUpload upload)
{
lock (PendingUploads)
{
if (PendingUploads.ContainsKey(upload.AssetID))
{
if (upload.Success)
{
// FIXME: Setup the TextureEntry with the new baked upload
}
else
{
Client.Log("Asset upload " + upload.AssetID.ToStringHyphenated() + " failed",
Helpers.LogLevel.Warning);
}
PendingUploads.Remove(upload.AssetID);
if (PendingUploads.Count == 0 && ImageDownloads.Count == 0)
{
CachedResponseEvent.Set();
}
}
else
{
// TEMP
Client.DebugLog("Upload " + upload.AssetID.ToStringHyphenated() + " was not found in PendingUploads");
}
}
}
} }
} }