From e1157504acb35deb3974fc2840ded0f1b1f14e42 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 23 Feb 2007 02:23:30 +0000 Subject: [PATCH] * 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 --- libsecondlife-cs/BakeLayer.cs | 4 +- .../libsecondlife.Utilities/Appearance.cs | 198 ++++++++++++++---- 2 files changed, 159 insertions(+), 43 deletions(-) diff --git a/libsecondlife-cs/BakeLayer.cs b/libsecondlife-cs/BakeLayer.cs index a26a623e..7a3a497a 100644 --- a/libsecondlife-cs/BakeLayer.cs +++ b/libsecondlife-cs/BakeLayer.cs @@ -61,6 +61,8 @@ namespace libsecondlife /// Maximum number of wearables for any baked layer public const int WEARABLES_PER_LAYER = 7; + /// Final compressed JPEG2000 data + public byte[] FinalData = new byte[0]; /// Whether this bake is complete or not public bool Finished = false; @@ -74,8 +76,6 @@ namespace libsecondlife protected Bitmap Scratchpad; /// List of textures sorted by their baking order protected SortedList Textures = new SortedList(WEARABLES_PER_LAYER); - /// Final compressed JPEG2000 data - protected byte[] FinalData = new byte[0]; /// Width of the final baked image and scratchpad protected int BakeWidth = 512; /// Height of the final baked image and scratchpad diff --git a/libsecondlife-cs/libsecondlife.Utilities/Appearance.cs b/libsecondlife-cs/libsecondlife.Utilities/Appearance.cs index 35f965e2..9fecc27d 100644 --- a/libsecondlife-cs/libsecondlife.Utilities/Appearance.cs +++ b/libsecondlife-cs/libsecondlife.Utilities/Appearance.cs @@ -456,14 +456,16 @@ namespace libsecondlife.Utilities.Appearance private AssetManager Assets; private Dictionary Wearables = new Dictionary(); // As wearable assets are downloaded and decoded, the textures are added to this list - private Dictionary AgentTextures = new Dictionary(); + private Dictionary AgentTextures = new Dictionary(); // Wearable assets are downloaded one at a time, a new request is pulled off the queue // and started when the previous one completes private Queue> DownloadQueue = new Queue>(); // A list of all the images we are currently downloading, prior to baking private Dictionary ImageDownloads = new Dictionary(); // A list of all the bakes we need to complete - private List PendingBakes = new List(BAKED_TEXTURE_COUNT); + private Dictionary PendingBakes = new Dictionary(BAKED_TEXTURE_COUNT); + // A list of all the uploads that are in progress + private Dictionary PendingUploads = new Dictionary(BAKED_TEXTURE_COUNT); // Whether the handler for our current wearable list should automatically start downloading the assets private bool DownloadWearables = false; private int CacheCheckSerialNum = 0; @@ -608,12 +610,12 @@ namespace libsecondlife.Utilities.Appearance DownloadWearables = true; // Register an asset download callback to get wearable data - AssetManager.AssetReceivedCallback assetCallback = - new AssetManager.AssetReceivedCallback(Assets_OnAssetReceived); - AssetManager.ImageReceivedCallback imageCallback = - new AssetManager.ImageReceivedCallback(Assets_OnImageReceived); + AssetManager.AssetReceivedCallback assetCallback = new AssetManager.AssetReceivedCallback(Assets_OnAssetReceived); + AssetManager.ImageReceivedCallback imageCallback = new AssetManager.ImageReceivedCallback(Assets_OnImageReceived); + AssetManager.AssetUploadedCallback uploadCallback = new AssetManager.AssetUploadedCallback(Assets_OnAssetUploaded); Assets.OnAssetReceived += assetCallback; Assets.OnImageReceived += imageCallback; + Assets.OnAssetUploaded += uploadCallback; // Ask the server what we are currently wearing RequestAgentWearables(); @@ -633,8 +635,9 @@ namespace libsecondlife.Utilities.Appearance CachedResponseEvent.WaitOne(); - // Unregister the image download callback + // Unregister the image download and asset upload callbacks Assets.OnImageReceived -= imageCallback; + Assets.OnAssetUploaded -= uploadCallback; Client.DebugLog("CachedResponseEvent completed"); @@ -690,7 +693,7 @@ namespace libsecondlife.Utilities.Appearance // Put our AgentTextures dictionary in to TextureEntry lock (AgentTextures) { - foreach (KeyValuePair texture in AgentTextures) + foreach (KeyValuePair texture in AgentTextures) { LLObject.TextureEntryFace face = te.CreateFace((uint)texture.Key); face.TextureID = texture.Value; @@ -775,22 +778,22 @@ namespace libsecondlife.Utilities.Appearance Client.Network.SendPacket(wearing); } - private int BakedIndexToAgentTextureIndex(int index) + private TextureIndex BakedIndexToAgentTextureIndex(BakeType index) { - switch ((BakeType)index) + switch (index) { case BakeType.Head: - return 8; + return TextureIndex.HeadBaked; case BakeType.UpperBody: - return 9; + return TextureIndex.UpperBaked; case BakeType.LowerBody: - return 10; + return TextureIndex.LowerBaked; case BakeType.Eyes: - return 11; + return TextureIndex.EyesBaked; case BakeType.Skirt: - return 19; + return TextureIndex.SkirtBaked; default: - return (int)TextureIndex.Unknown; + return TextureIndex.Unknown; } } @@ -903,7 +906,7 @@ namespace libsecondlife.Utilities.Appearance // Convert the baked index to an AgentTexture index if (block.TextureID != LLUUID.Zero && host.Length == 0) { - int index = BakedIndexToAgentTextureIndex(block.TextureIndex); + TextureIndex index = BakedIndexToAgentTextureIndex((BakeType)block.TextureIndex); AgentTextures[index] = block.TextureID; } else @@ -915,39 +918,39 @@ namespace libsecondlife.Utilities.Appearance case BakeType.Head: lock (ImageDownloads) { - PendingBakes.Add(new BakeLayer(Client, 2, paramValues)); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.HeadBodypaint], TextureIndex.HeadBodypaint); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.Hair], TextureIndex.Hair); + PendingBakes.Add(BakeType.Head, new BakeLayer(Client, 2, paramValues)); + ImageDownloads.Add(AgentTextures[TextureIndex.HeadBodypaint], TextureIndex.HeadBodypaint); + ImageDownloads.Add(AgentTextures[TextureIndex.Hair], TextureIndex.Hair); } break; case BakeType.UpperBody: lock (ImageDownloads) { - PendingBakes.Add(new BakeLayer(Client, 4, paramValues)); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperBodypaint], TextureIndex.UpperBodypaint); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperUndershirt], TextureIndex.UpperUndershirt); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperShirt], TextureIndex.UpperShirt); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.UpperJacket], TextureIndex.UpperJacket); + PendingBakes.Add(BakeType.UpperBody, new BakeLayer(Client, 4, paramValues)); + ImageDownloads.Add(AgentTextures[TextureIndex.UpperBodypaint], TextureIndex.UpperBodypaint); + ImageDownloads.Add(AgentTextures[TextureIndex.UpperUndershirt], TextureIndex.UpperUndershirt); + ImageDownloads.Add(AgentTextures[TextureIndex.UpperShirt], TextureIndex.UpperShirt); + ImageDownloads.Add(AgentTextures[TextureIndex.UpperJacket], TextureIndex.UpperJacket); // TODO: Where are the gloves? } break; case BakeType.LowerBody: lock (ImageDownloads) { - PendingBakes.Add(new BakeLayer(Client, 6, paramValues)); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerBodypaint], TextureIndex.LowerBodypaint); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerUnderpants], TextureIndex.LowerUnderpants); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerSocks], TextureIndex.LowerSocks); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerShoes], TextureIndex.LowerShoes); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerPants], TextureIndex.LowerPants); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.LowerJacket], TextureIndex.LowerJacket); + PendingBakes.Add(BakeType.LowerBody, new BakeLayer(Client, 6, paramValues)); + ImageDownloads.Add(AgentTextures[TextureIndex.LowerBodypaint], TextureIndex.LowerBodypaint); + ImageDownloads.Add(AgentTextures[TextureIndex.LowerUnderpants], TextureIndex.LowerUnderpants); + ImageDownloads.Add(AgentTextures[TextureIndex.LowerSocks], TextureIndex.LowerSocks); + ImageDownloads.Add(AgentTextures[TextureIndex.LowerShoes], TextureIndex.LowerShoes); + ImageDownloads.Add(AgentTextures[TextureIndex.LowerPants], TextureIndex.LowerPants); + ImageDownloads.Add(AgentTextures[TextureIndex.LowerJacket], TextureIndex.LowerJacket); } break; case BakeType.Eyes: lock (ImageDownloads) { - PendingBakes.Add(new BakeLayer(Client, 1, paramValues)); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.EyesIris], TextureIndex.EyesIris); + PendingBakes.Add(BakeType.Eyes, new BakeLayer(Client, 1, paramValues)); + ImageDownloads.Add(AgentTextures[TextureIndex.EyesIris], TextureIndex.EyesIris); } break; case BakeType.Skirt: @@ -955,8 +958,8 @@ namespace libsecondlife.Utilities.Appearance { lock (ImageDownloads) { - PendingBakes.Add(new BakeLayer(Client, 1, paramValues)); - ImageDownloads.Add(AgentTextures[(int)TextureIndex.Skirt], TextureIndex.Skirt); + PendingBakes.Add(BakeType.Skirt, new BakeLayer(Client, 1, paramValues)); + ImageDownloads.Add(AgentTextures[TextureIndex.Skirt], TextureIndex.Skirt); } } break; @@ -1007,7 +1010,7 @@ namespace libsecondlife.Utilities.Appearance lock (AgentTextures) { foreach (KeyValuePair 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()); @@ -1050,11 +1053,92 @@ namespace libsecondlife.Utilities.Appearance if (ImageDownloads.ContainsKey(image.ID)) { TextureIndex index = ImageDownloads[image.ID]; + BakeType type = BakeType.Head; + BakeLayer.BakeOrder order = BakeLayer.BakeOrder.HeadBodypaint; if (image.Success) { - // FIXME: Add this image to a baking layer - // FIXME: If true is returned, the bake is complete and we can fetch the finished jp2 data + // Add this image to a baking layer + 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 { @@ -1064,13 +1148,45 @@ namespace libsecondlife.Utilities.Appearance 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(); } } } } + + 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"); + } + } + } } }