예제 #1
0
        /// <summary>
        /// Make sure images exist, resize source if needed to match the destination
        /// </summary>
        /// <param name="dest">Destination image</param>
        /// <param name="src">Source image</param>
        /// <returns>Sanitization was succefull</returns>
        private bool SanitizeLayers(ManagedImage dest, ManagedImage src)
        {
            if (dest == null || src == null)
            {
                return(false);
            }

            if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
            {
                dest.ConvertChannels(dest.Channels | ManagedImage.ImageChannels.Alpha);
            }

            if (dest.Width != src.Width || dest.Height != src.Height)
            {
                try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
                catch (Exception) { return(false); }
            }

            return(true);
        }
예제 #2
0
        private void ApplyAlpha(ManagedImage dest, VisualAlphaParam param, float val)
        {
            ManagedImage src = LoadResourceLayer(param.TGAFile);

            if (dest == null || src == null || src.Alpha == null)
            {
                return;
            }

            if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
            {
                dest.ConvertChannels(ManagedImage.ImageChannels.Alpha | dest.Channels);
            }

            if (dest.Width != src.Width || dest.Height != src.Height)
            {
                try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
                catch (Exception) { return; }
            }

            for (int i = 0; i < dest.Alpha.Length; i++)
            {
                byte alpha = src.Alpha[i] <= ((1 - val) * 255) ? (byte)0 : (byte)255;
                if (alpha != 255)
                {
                }
                if (param.MultiplyBlend)
                {
                    dest.Alpha[i] = (byte)((dest.Alpha[i] * alpha) >> 8);
                }
                else
                {
                    if (alpha > dest.Alpha[i])
                    {
                        dest.Alpha[i] = alpha;
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Make sure images exist, resize source if needed to match the destination
        /// </summary>
        /// <param name="dest">Destination image</param>
        /// <param name="src">Source image</param>
        /// <returns>Sanitization was succefull</returns>
        private bool SanitizeLayers(ManagedImage dest, ManagedImage src)
        {
            if (dest == null || src == null) return false;

            if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
            {
                dest.ConvertChannels(dest.Channels | ManagedImage.ImageChannels.Alpha);
            }

            if (dest.Width != src.Width || dest.Height != src.Height)
            {
                try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
                catch (Exception) { return false; }
            }

            return true;
        }
예제 #4
0
        public void Bake()
        {
            bakedTexture = new AssetTexture(new ManagedImage(bakeWidth, bakeHeight,
                                                             ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump));

            // Base color for eye bake is white, color of layer0 for others
            if (bakeType == BakeType.Eyes)
            {
                InitBakedLayerColor(Color4.White);
            }
            else if (textures.Count > 0)
            {
                InitBakedLayerColor(textures[0].Color);
            }

            // Do we have skin texture?
            bool SkinTexture = textures.Count > 0 && textures[0].Texture != null;

            if (bakeType == BakeType.Head)
            {
                DrawLayer(LoadResourceLayer("head_color.tga"), false);
                AddAlpha(bakedTexture.Image, LoadResourceLayer("head_alpha.tga"));
                MultiplyLayerFromAlpha(bakedTexture.Image, LoadResourceLayer("head_skingrain.tga"));
            }

            if (!SkinTexture && bakeType == BakeType.UpperBody)
            {
                DrawLayer(LoadResourceLayer("upperbody_color.tga"), false);
            }

            if (!SkinTexture && bakeType == BakeType.LowerBody)
            {
                DrawLayer(LoadResourceLayer("lowerbody_color.tga"), false);
            }

            ManagedImage alphaWearableTexture = null;

            // Layer each texture on top of one other, applying alpha masks as we go
            for (int i = 0; i < textures.Count; i++)
            {
                // Skip if we have no texture on this layer
                if (textures[i].Texture == null)
                {
                    continue;
                }

                // Is this Alpha wearable and does it have an alpha channel?
                if (textures[i].TextureIndex >= AvatarTextureIndex.LowerAlpha &&
                    textures[i].TextureIndex <= AvatarTextureIndex.HairAlpha)
                {
                    if (textures[i].Texture.Image.Alpha != null)
                    {
                        alphaWearableTexture = textures[i].Texture.Image.Clone();
                    }
                    else if (textures[i].TextureID == IMG_INVISIBLE)
                    {
                        alphaWearableTexture = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha);
                    }
                    continue;
                }

                // Don't draw skin and tattoo on head bake first
                // For head bake the skin and texture are drawn last, go figure
                if (bakeType == BakeType.Head && (i == 0 || i == 1))
                {
                    continue;
                }

                ManagedImage texture = textures[i].Texture.Image.Clone();
                //File.WriteAllBytes(bakeType + "-texture-layer-" + i + ".tga", texture.ExportTGA());

                // Resize texture to the size of baked layer
                // FIXME: if texture is smaller than the layer, don't stretch it, tile it
                if (texture.Width != bakeWidth || texture.Height != bakeHeight)
                {
                    try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
                    catch (Exception) { continue; }
                }

                // Special case for hair layer for the head bake
                // If we don't have skin texture, we discard hair alpha
                // and apply hair(i==2) pattern over the texture
                if (!SkinTexture && bakeType == BakeType.Head && i == 2)
                {
                    if (texture.Alpha != null)
                    {
                        for (int j = 0; j < texture.Alpha.Length; j++)
                        {
                            texture.Alpha[j] = (byte)255;
                        }
                    }
                    MultiplyLayerFromAlpha(texture, LoadResourceLayer("head_hair.tga"));
                }

                // Aply tint and alpha masks except for skin that has a texture
                // on layer 0 which always overrides other skin settings
                if (!(IsSkin && i == 0))
                {
                    ApplyTint(texture, textures[i].Color);

                    // For hair bake, we skip all alpha masks
                    // and use one from the texture, for both
                    // alpha and morph layers
                    if (bakeType == BakeType.Hair)
                    {
                        if (texture.Alpha != null)
                        {
                            bakedTexture.Image.Bump = texture.Alpha;
                        }
                        else
                        {
                            for (int j = 0; j < bakedTexture.Image.Bump.Length; j++)
                            {
                                bakedTexture.Image.Bump[j] = byte.MaxValue;
                            }
                        }
                    }
                    // Apply parametrized alpha masks
                    else if (textures[i].AlphaMasks != null && textures[i].AlphaMasks.Count > 0)
                    {
                        // Combined mask for the layer, fully transparent to begin with
                        ManagedImage combinedMask = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha);

                        int addedMasks = 0;

                        // First add mask in normal blend mode
                        foreach (KeyValuePair <VisualAlphaParam, float> kvp in textures[i].AlphaMasks)
                        {
                            if (!MaskBelongsToBake(kvp.Key.TGAFile))
                            {
                                continue;
                            }

                            if (kvp.Key.MultiplyBlend == false && (kvp.Value > 0f || !kvp.Key.SkipIfZero))
                            {
                                ApplyAlpha(combinedMask, kvp.Key, kvp.Value);
                                //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA());
                                addedMasks++;
                            }
                        }

                        // If there were no mask in normal blend mode make aplha fully opaque
                        if (addedMasks == 0)
                        {
                            for (int l = 0; l < combinedMask.Alpha.Length; l++)
                            {
                                combinedMask.Alpha[l] = 255;
                            }
                        }

                        // Add masks in multiply blend mode
                        foreach (KeyValuePair <VisualAlphaParam, float> kvp in textures[i].AlphaMasks)
                        {
                            if (!MaskBelongsToBake(kvp.Key.TGAFile))
                            {
                                continue;
                            }

                            if (kvp.Key.MultiplyBlend == true && (kvp.Value > 0f || !kvp.Key.SkipIfZero))
                            {
                                ApplyAlpha(combinedMask, kvp.Key, kvp.Value);
                                //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA());
                                addedMasks++;
                            }
                        }

                        if (addedMasks > 0)
                        {
                            // Apply combined alpha mask to the cloned texture
                            AddAlpha(texture, combinedMask);
                        }

                        // Is this layer used for morph mask? If it is, use its
                        // alpha as the morth for the whole bake
                        if (Textures[i].TextureIndex == AppearanceManager.MorphLayerForBakeType(bakeType))
                        {
                            bakedTexture.Image.Bump = texture.Alpha;
                        }

                        //File.WriteAllBytes(bakeType + "-masked-texture-" + i + ".tga", texture.ExportTGA());
                    }
                }

                bool useAlpha = i == 0 && (BakeType == BakeType.Skirt || BakeType == BakeType.Hair);
                DrawLayer(texture, useAlpha);
                //File.WriteAllBytes(bakeType + "-layer-" + i + ".tga", texture.ExportTGA());
            }

            // For head and tattoo, we add skin last
            if (IsSkin && bakeType == BakeType.Head)
            {
                ManagedImage texture;
                if (textures[0].Texture != null)
                {
                    texture = textures[0].Texture.Image.Clone();
                    if (texture.Width != bakeWidth || texture.Height != bakeHeight)
                    {
                        try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
                        catch (Exception) { }
                    }
                    DrawLayer(texture, false);
                }

                // Add head tattoo here (if available, order-dependant)
                if (textures.Count > 1 && textures[1].Texture != null)
                {
                    texture = textures[1].Texture.Image.Clone();
                    if (texture.Width != bakeWidth || texture.Height != bakeHeight)
                    {
                        try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
                        catch (Exception) { }
                    }
                    DrawLayer(texture, false);
                }
            }

            // Apply any alpha wearable textures to make parts of the avatar disappear
            if (alphaWearableTexture != null)
            {
                AddAlpha(bakedTexture.Image, alphaWearableTexture);
            }

            // We are done, encode asset for finalized bake
            bakedTexture.Encode();
            //File.WriteAllBytes(bakeType + ".tga", bakedTexture.Image.ExportTGA());
        }
예제 #5
0
        private bool DrawLayer(ManagedImage source, bool useSourceAlpha)
        {
            bool sourceHasColor;
            bool sourceHasAlpha;
            bool sourceHasBump;
            int  i = 0;

            sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 &&
                              source.Red != null && source.Green != null && source.Blue != null);
            sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null);
            sourceHasBump  = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null);

            useSourceAlpha = (useSourceAlpha && sourceHasAlpha);

            if (source.Width != _bakeWidth || source.Height != _bakeHeight)
            {
                try { source.ResizeNearestNeighbor(_bakeWidth, _bakeHeight); }
                catch { return(false); }
            }

            int alpha = 255;
            //int alphaInv = 255 - alpha;
            int alphaInv = 256 - alpha;

            byte[] bakedRed   = _bakedTexture.Image.Red;
            byte[] bakedGreen = _bakedTexture.Image.Green;
            byte[] bakedBlue  = _bakedTexture.Image.Blue;
            byte[] bakedAlpha = _bakedTexture.Image.Alpha;
            byte[] bakedBump  = _bakedTexture.Image.Bump;

            byte[] sourceRed   = source.Red;
            byte[] sourceGreen = source.Green;
            byte[] sourceBlue  = source.Blue;
            byte[] sourceAlpha = null;
            byte[] sourceBump  = null;

            if (sourceHasAlpha)
            {
                sourceAlpha = source.Alpha;
            }

            if (sourceHasBump)
            {
                sourceBump = source.Bump;
            }

            for (int y = 0; y < _bakeHeight; y++)
            {
                for (int x = 0; x < _bakeWidth; x++)
                {
                    if (sourceHasAlpha)
                    {
                        alpha = sourceAlpha[i];
                        //alphaInv = 255 - alpha;
                        alphaInv = 256 - alpha;
                    }

                    if (sourceHasColor)
                    {
                        bakedRed[i]   = (byte)((bakedRed[i] * alphaInv + sourceRed[i] * alpha) >> 8);
                        bakedGreen[i] = (byte)((bakedGreen[i] * alphaInv + sourceGreen[i] * alpha) >> 8);
                        bakedBlue[i]  = (byte)((bakedBlue[i] * alphaInv + sourceBlue[i] * alpha) >> 8);
                    }

                    if (useSourceAlpha)
                    {
                        bakedAlpha[i] = sourceAlpha[i];
                    }

                    if (sourceHasBump)
                    {
                        bakedBump[i] = sourceBump[i];
                    }

                    ++i;
                }
            }

            return(true);
        }
예제 #6
0
        private bool DrawLayer(ManagedImage source, bool useSourceAlpha)
        {
            bool sourceHasColor;
            bool sourceHasAlpha;
            bool sourceHasBump;
            int i = 0;

            sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 &&
                    source.Red != null && source.Green != null && source.Blue != null);
            sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null);
            sourceHasBump = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null);

            useSourceAlpha = (useSourceAlpha && sourceHasAlpha);

            if (source.Width != _bakeWidth || source.Height != _bakeHeight)
            {
                try { source.ResizeNearestNeighbor(_bakeWidth, _bakeHeight); }
                catch { return false; }
            }

            int alpha = 255;
            //int alphaInv = 255 - alpha;
            int alphaInv = 256 - alpha;

            byte[] bakedRed = _bakedTexture.Image.Red;
            byte[] bakedGreen = _bakedTexture.Image.Green;
            byte[] bakedBlue = _bakedTexture.Image.Blue;
            byte[] bakedAlpha = _bakedTexture.Image.Alpha;
            byte[] bakedBump = _bakedTexture.Image.Bump;

            byte[] sourceRed = source.Red;
            byte[] sourceGreen = source.Green;
            byte[] sourceBlue = source.Blue;
            byte[] sourceAlpha = null;
            byte[] sourceBump = null;

            if (sourceHasAlpha)
                sourceAlpha = source.Alpha;

            if (sourceHasBump)
                sourceBump = source.Bump;

            for (int y = 0; y < _bakeHeight; y++)
            {
                for (int x = 0; x < _bakeWidth; x++)
                {
                    if (sourceHasAlpha)
                    {
                        alpha = sourceAlpha[i];
                        //alphaInv = 255 - alpha;
                        alphaInv = 256 - alpha;
                    }

                    if (sourceHasColor)
                    {
                        bakedRed[i] = (byte)((bakedRed[i] * alphaInv + sourceRed[i] * alpha) >> 8);
                        bakedGreen[i] = (byte)((bakedGreen[i] * alphaInv + sourceGreen[i] * alpha) >> 8);
                        bakedBlue[i] = (byte)((bakedBlue[i] * alphaInv + sourceBlue[i] * alpha) >> 8);
                    }

                    if (useSourceAlpha)
                        bakedAlpha[i] = sourceAlpha[i];

                    if (sourceHasBump)
                        bakedBump[i] = sourceBump[i];

                    ++i;
                }
            }

            return true;
        }