Example #1
0
        public static AbstractSubBaker CreateSubBaker(this Wearable wearable)
        {
            VisualParamsMapper.CompleteParams(wearable.Params);

            switch (wearable.Type)
            {
            case WearableType.Eyes:
                return(new EyeSubBaker(wearable));

            case WearableType.Skin:
                return(new SkinSubBaker(wearable));

            case WearableType.Hair:
                return(new HairSubBaker(wearable));

            case WearableType.Shape:
                return(new ShapeSubBaker(wearable));

            case WearableType.Tattoo:
                return(new TattooSubBaker(wearable));

            case WearableType.Alpha:
                return(new AlphaMaskSubBaker(wearable));

            case WearableType.Shirt:
                return(new ShirtSubBaker(wearable));

            case WearableType.Jacket:
                return(new JacketSubBaker(wearable));

            case WearableType.Socks:
                return(new SocksSubBaker(wearable));

            case WearableType.Pants:
                return(new PantsSubBaker(wearable));

            case WearableType.Underpants:
                return(new UnderpantsSubBaker(wearable));

            case WearableType.Undershirt:
                return(new UndershirtSubBaker(wearable));

            case WearableType.Shoes:
                return(new ShoesSubBaker(wearable));

            case WearableType.Skirt:
                return(new SkirtSubBaker(wearable));

            case WearableType.Gloves:
                return(new GlovesSubBaker(wearable));

            case WearableType.Universal:
                return(new UniversalSubBaker(wearable));

            default:
                return(null);    /* intentionally returning null here */
            }
        }
Example #2
0
        public BakeOutput Process(BakeCache cache, AssetServiceInterface assetSource, Action <string> logOutput = null)
        {
            var output = new BakeOutput();

            if (cache.IsBaked)
            {
                throw new AlreadyBakedException();
            }

            m_AssetService = assetSource;

            output.VisualParams = VisualParamsMapper.CreateVisualParams(cache.Wearables, ref output.AvatarHeight);

            var Tgt          = new Targets();
            var SourceBakers = new Dictionary <WearableType, List <AbstractSubBaker> >();

            foreach (WearableType t in Enum.GetValues(typeof(WearableType)))
            {
                SourceBakers.Add(t, new List <AbstractSubBaker>());
            }

            foreach (AbstractSubBaker subbaker in cache.SubBakers)
            {
#if DEBUG
                logOutput?.Invoke(string.Format("Using subbaker {0}: baked={1}", subbaker.Type.ToString(), subbaker.IsBaked.ToString()));
#endif
                SourceBakers[subbaker.Type].Add(subbaker);
            }
#if DEBUG
            int subbakercount = 0;
            foreach (List <AbstractSubBaker> entrylist in SourceBakers.Values)
            {
                subbakercount += entrylist.Count;
            }
            logOutput?.Invoke(string.Format("Using {0} subbakers", subbakercount));
#endif

            try
            {
                foreach (BakeTarget idx in BakeIndices)
                {
                    int    dimensions = idx == BakeTarget.Eyes ? 128 : 512;
                    Bitmap bmp;
                    if (idx == BakeTarget.Skirt && SourceBakers[WearableType.Skirt].Count == 0)
                    {
                        continue;
                    }
                    bmp = new Bitmap(dimensions, dimensions, PixelFormat.Format32bppArgb);
                    Tgt.Images.Add(idx, bmp);
                    Graphics gfx = Graphics.FromImage(bmp);
                    if (idx == BakeTarget.Hair)
                    {
                        gfx.CompositingMode = CompositingMode.SourceCopy;
                        using (var b = new SolidBrush(Color.FromArgb(0, Color.White)))
                        {
                            gfx.FillRectangle(b, new Rectangle(0, 0, dimensions, dimensions));
                        }
                    }
                    gfx.CompositingMode = CompositingMode.SourceOver;
                    Tgt.Graphics.Add(idx, gfx);
                }

                logOutput?.Invoke("Processing R,G,B and bump parts");
                DrawSubBakers(Tgt, SourceBakers[WearableType.Skin], SkinIndices);

                DrawSubBakers(Tgt, SourceBakers[WearableType.Universal].OrderBy(item => item.Ordinal), UniversalIndices);

                DrawSubBakers(Tgt, SourceBakers[WearableType.Tattoo].OrderBy(item => item.Ordinal), SkinIndices);

                DrawSubBakers(Tgt, SourceBakers[WearableType.Hair], new BakeTarget[] { BakeTarget.Hair });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Hair], new BakeTarget[] { BakeTarget.Hair });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Eyes], new BakeTarget[] { BakeTarget.Eyes });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Eyes], new BakeTarget[] { BakeTarget.Eyes });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Underpants].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.LowerBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Underpants], new BakeTarget[] { BakeTarget.LowerBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Undershirt].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.UpperBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Undershirt], new BakeTarget[] { BakeTarget.UpperBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Socks].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.LowerBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Socks], new BakeTarget[] { BakeTarget.LowerBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Shoes].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.LowerBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Shoes], new BakeTarget[] { BakeTarget.LowerBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Pants].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.LowerBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Pants], new BakeTarget[] { BakeTarget.LowerBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Shirt].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.UpperBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Shirt], new BakeTarget[] { BakeTarget.UpperBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Jacket].OrderBy(item => item.Ordinal), ClothingIndices);
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Jacket], ClothingIndices);

                DrawSubBakers(Tgt, SourceBakers[WearableType.Gloves].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.UpperBody });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Gloves], new BakeTarget[] { BakeTarget.UpperBody });

                DrawSubBakers(Tgt, SourceBakers[WearableType.Skirt].OrderBy(item => item.Ordinal), new BakeTarget[] { BakeTarget.Skirt });
                DrawBumpMaps(Tgt, SourceBakers[WearableType.Skirt], new BakeTarget[] { BakeTarget.Skirt });

                /* for alpha masks we have to get rid of the Graphics */
                foreach (Graphics gfx in Tgt.Graphics.Values)
                {
                    gfx.Dispose();
                }
                Tgt.Graphics.Clear();

                logOutput?.Invoke("Processing alpha mask");
                /* clean out alpha channel. the ones we used before are not necessary anymore */
                foreach (KeyValuePair <BakeTarget, Bitmap> kvp in Tgt.Images)
                {
                    if (kvp.Key == BakeTarget.Hair)
                    {
                        /* skip hair */
                        continue;
                    }
                    int        byteSize = kvp.Value.Width * kvp.Value.Height * 4;
                    BitmapData lockBits = kvp.Value.LockBits(Tgt.Rectangles[kvp.Key], ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    var        rawdata  = new byte[byteSize];
                    Marshal.Copy(lockBits.Scan0, rawdata, 0, byteSize);
                    for (int bytePos = byteSize; bytePos-- != 0; bytePos -= 3)
                    {
                        rawdata[bytePos] = 255;
                    }
                    Marshal.Copy(rawdata, 0, lockBits.Scan0, byteSize);
                    kvp.Value.UnlockBits(lockBits);
                }

                if (SourceBakers[WearableType.Alpha].Count != 0)
                {
                    var AlphaMaskBakes = new Dictionary <BakeTarget, byte[]>();

                    foreach (AbstractSubBaker baker in SourceBakers[WearableType.Alpha])
                    {
                        foreach (BakeTarget tgt in BakeIndices)
                        {
                            Image  srcimg;
                            Bitmap tgtimg;
                            byte[] dstAlphaMask;
                            byte[] srcAlphaMask;
                            int    dimensions = tgt == BakeTarget.Eyes ? 128 : 512;
                            int    imagebytes = dimensions * dimensions * 4;

                            srcimg = baker.BakeAlphaMaskOutput(this, tgt);
                            if (srcimg == null)
                            {
                                continue;
                            }

                            if (!AlphaMaskBakes.TryGetValue(tgt, out dstAlphaMask))
                            {
                                if (!Tgt.Images.TryGetValue(tgt, out tgtimg))
                                {
                                    continue;
                                }
                                dstAlphaMask        = GetRawData(tgtimg);
                                AlphaMaskBakes[tgt] = dstAlphaMask;
                            }

                            using (var srcbmp = new Bitmap(srcimg))
                            {
                                srcAlphaMask = GetRawData(srcbmp);
                            }

                            for (int idx = imagebytes; idx-- != 0; idx -= 3)
                            {
                                dstAlphaMask[idx] = Math.Min(dstAlphaMask[idx], srcAlphaMask[idx]);
                            }
                        }
                    }

                    foreach (KeyValuePair <BakeTarget, byte[]> kvp in AlphaMaskBakes)
                    {
                        UpdateRawData(Tgt.Images[kvp.Key], kvp.Value);
                    }
                }

                logOutput?.Invoke("Compressing bakes");
                byte[] finalbump;
                output.HairBake = new AssetData
                {
                    ID        = UUID.RandomFixedFirst(0xffffffff),
                    Type      = AssetType.Texture,
                    Temporary = true,
                    Data      = J2cEncoder.EncodeWithBump(Tgt.Images[BakeTarget.Hair], true, Tgt.Bumps[BakeTarget.Hair]),
                    Name      = "Bake Texture Hair"
                };
                output.HeadBake = new AssetData
                {
                    ID        = UUID.RandomFixedFirst(0xffffffff),
                    Type      = AssetType.Texture,
                    Temporary = true,
                    Data      = J2cEncoder.EncodeWithBump(Tgt.Images[BakeTarget.Head], true, Tgt.Bumps[BakeTarget.Head]),
                    Name      = "Bake Texture Head"
                };

                output.UpperBake = new AssetData
                {
                    ID        = UUID.RandomFixedFirst(0xffffffff),
                    Type      = AssetType.Texture,
                    Temporary = true,
                    Data      = J2cEncoder.EncodeWithBump(Tgt.Images[BakeTarget.UpperBody], true, Tgt.Bumps[BakeTarget.UpperBody]),
                    Name      = "Bake Texture Upperbody"
                };

                output.LowerBake = new AssetData
                {
                    ID        = UUID.RandomFixedFirst(0xffffffff),
                    Type      = AssetType.Texture,
                    Temporary = true,
                    Data      = J2cEncoder.EncodeWithBump(Tgt.Images[BakeTarget.LowerBody], true, Tgt.Bumps[BakeTarget.LowerBody]),
                    Name      = "Bake Texture Lowerbody"
                };

                output.EyeBake = new AssetData
                {
                    ID        = UUID.RandomFixedFirst(0xffffffff),
                    Type      = AssetType.Texture,
                    Temporary = true,
                    Data      = J2cEncoder.EncodeWithBump(Tgt.Images[BakeTarget.Eyes], true, Tgt.Bumps[BakeTarget.Eyes]),
                    Name      = "Bake Texture Eyes"
                };

                Bitmap finalSkirt;
                if (Tgt.Images.TryGetValue(BakeTarget.Skirt, out finalSkirt))
                {
                    output.SkirtBake = new AssetData
                    {
                        ID        = UUID.RandomFixedFirst(0xffffffff),
                        Type      = AssetType.Texture,
                        Temporary = true,
                        Data      = Tgt.Bumps.TryGetValue(BakeTarget.Skirt, out finalbump) ?
                                    J2cEncoder.EncodeWithBump(finalSkirt, true, finalbump) :
                                    J2cEncoder.Encode(finalSkirt, true),
                        Name = "Bake Texture Skirt"
                    };
                }

                Bitmap finalLeftArm;
                if (Tgt.Images.TryGetValue(BakeTarget.LeftArm, out finalLeftArm))
                {
                    output.LeftArmBake = new AssetData
                    {
                        ID        = UUID.RandomFixedFirst(0xffffffff),
                        Type      = AssetType.Texture,
                        Temporary = true,
                        Data      = J2cEncoder.Encode(finalLeftArm, true),
                        Name      = "Bake Texture LeftArm"
                    };
                }

                Bitmap finalLeftLeg;
                if (Tgt.Images.TryGetValue(BakeTarget.LeftLeg, out finalLeftLeg))
                {
                    output.LeftLegBake = new AssetData
                    {
                        ID        = UUID.RandomFixedFirst(0xffffffff),
                        Type      = AssetType.Texture,
                        Temporary = true,
                        Data      = J2cEncoder.Encode(finalLeftLeg, true),
                        Name      = "Bake Texture LeftLeg"
                    };
                }

                Bitmap finalAux1;
                if (Tgt.Images.TryGetValue(BakeTarget.Aux1, out finalAux1))
                {
                    output.Aux1Bake = new AssetData
                    {
                        ID        = UUID.RandomFixedFirst(0xffffffff),
                        Type      = AssetType.Texture,
                        Temporary = true,
                        Data      = J2cEncoder.Encode(finalAux1, true),
                        Name      = "Bake Texture Aux1"
                    };
                }

                Bitmap finalAux2;
                if (Tgt.Images.TryGetValue(BakeTarget.Aux1, out finalAux2))
                {
                    output.Aux2Bake = new AssetData
                    {
                        ID        = UUID.RandomFixedFirst(0xffffffff),
                        Type      = AssetType.Texture,
                        Temporary = true,
                        Data      = J2cEncoder.Encode(finalAux2, true),
                        Name      = "Bake Texture Aux2"
                    };
                }

                Bitmap finalAux3;
                if (Tgt.Images.TryGetValue(BakeTarget.Aux1, out finalAux3))
                {
                    output.Aux3Bake = new AssetData
                    {
                        ID        = UUID.RandomFixedFirst(0xffffffff),
                        Type      = AssetType.Texture,
                        Temporary = true,
                        Data      = J2cEncoder.Encode(finalAux3, true),
                        Name      = "Bake Texture Aux3"
                    };
                }
            }
            finally
            {
                foreach (Graphics gfx in Tgt.Graphics.Values)
                {
                    gfx.Dispose();
                }
                foreach (Bitmap bmp in Tgt.Images.Values)
                {
                    bmp.Dispose();
                }
            }

            return(output);
        }