/*
* 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
}
}
}