/* * Copyright (c) 2007, Second Life Reverse Engineering Team * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the Second Life Reverse Engineering Team nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Drawing; using System.Drawing.Imaging; using System.Collections.Generic; using System.IO; using System.Reflection; namespace libsecondlife { /// /// A set of textures that are layered on top of each other and "baked" /// in to a single texture, for avatar appearances /// public class BakeLayer { public enum BakeOrder { Unknown = -1, HeadBodypaint = 0, Hair, EyesIris, UpperBodypaint, UpperUndershirt, UpperShirt, UpperJacket, LowerBodypaint, LowerUnderpants, LowerSocks, LowerShoes, LowerPants, LowerJacket, Skirt } /// 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; /// Reference to the SecondLife client protected SecondLife Client; /// Total number of textures in this bake protected int TotalLayers; /// Appearance parameters the drive the baking process protected Dictionary ParamValues; /// GDI+ image that textures are composited to protected Bitmap Scratchpad; /// List of textures sorted by their baking order protected SortedList Textures = new SortedList(WEARABLES_PER_LAYER); /// Width of the final baked image and scratchpad protected int BakeWidth = 512; /// Height of the final baked image and scratchpad protected int BakeHeight = 512; private Assembly assembly = null; /// /// Default constructor /// /// Reference to the SecondLife client /// Total number of layers this bake set is /// composed of /// Appearance parameters the drive the /// baking process public BakeLayer(SecondLife client, int totalLayers, Dictionary paramValues) { Client = client; TotalLayers = totalLayers; ParamValues = paramValues; } /// /// Default constructor /// /// Reference to the SecondLife client /// Total number of layers this bake set is /// composed of /// Appearance parameters the drive the /// baking process /// Width of the final baked image /// Height of the final baked image public BakeLayer(SecondLife client, int totalLayers, Dictionary paramValues, int width, int height) { Client = client; TotalLayers = totalLayers; ParamValues = paramValues; BakeWidth = width; BakeHeight = height; } /// /// Adds an image to this baking layer and potentially processes it, or /// stores it for processing later /// /// The baking layer index of the image to be added /// JPEG2000 compressed image to be added to the /// baking layer /// True if this layer is completely baked and JPEG2000 data /// is available, otherwise false public bool AddImage(BakeOrder index, byte[] jp2data) { lock (Textures) { Textures.Add(index, jp2data); if (Textures.Count == TotalLayers) { // All of the layers are in place, we can bake Bake(); Finished = true; return true; } } return false; } /// /// Create the various dynamic alpha masks, apply them to the affected /// textures, and composite all of the textures in to the final scratch /// pad /// protected void Bake() { if (TotalLayers == 1) { // FIXME: Create a properly formatted JP2 bake (5 comps) } else { Client.Log("Too many layers for the null baking code!", Helpers.LogLevel.Error); } } private StreamReader GetResource(string resourceName) { if (assembly == null) assembly = Assembly.GetExecutingAssembly(); return new StreamReader(assembly.GetManifestResourceStream(String.Format("libsecondlife.Resources.{0}", resourceName))); } } /// /// /// public class UpperBakeLayer : BakeLayer { /// /// Default constructor /// /// Reference to the SecondLife client /// Total number of layers this bake set is /// composed of /// Appearance parameters the drive the /// baking process public UpperBakeLayer(SecondLife client, int totalLayers, Dictionary paramValues) : base(client, totalLayers, paramValues) { } /// /// /// protected new void Bake() { // FIXME: Iterate through each texture, generate the alpha masks and apply them, // and combine the masked texture in to the final scratch pad } } /// /// /// public class LowerBakeLayer : BakeLayer { /// /// Default constructor /// /// Reference to the SecondLife client /// Total number of layers this bake set is /// composed of /// Appearance parameters the drive the /// baking process public LowerBakeLayer(SecondLife client, int totalLayers, Dictionary paramValues) : base(client, totalLayers, paramValues) { } /// /// /// protected new void Bake() { // FIXME: Iterate through each texture, generate the alpha masks and apply them, // and combine the masked texture in to the final scratch pad } } }