protected override void Export(CookingContext context, ParticleSystemSet input) { var particleBitmaps = new Dictionary <Bitmap, ParticleSystem>(); foreach (var item in input.ParticleSystems) { var tag = (ImageCookingTag)item.Value.Image.Tag; particleBitmaps.Add(tag.Bitmap, item.Value); } using (var bitmapSheet = BitmapSheet.Create(particleBitmaps.Keys, BitmapSheetSize.Width, BitmapSheetSize.Height, BitmapSheetClusterSize.Width, BitmapSheetClusterSize.Height, BitmapSheet.Options.PowerOfTwoSize | BitmapSheet.Options.RotatableMerging)) { ExportImageSet.SaveTextureAssets(context, bitmapSheet, TextureOutput, (source, textureURI, clippingRectangle, appliedTransform) => { ParticleSystem value = null; if (particleBitmaps.TryGetValue(source, out value)) { value.Image.TextureURI = textureURI; value.Image.ClippingRectangle = clippingRectangle; value.Image.AppliedTransform = appliedTransform; } }); } }
public static void SaveTextureAssets(CookingContext context, BitmapSheet bitmapSheet, string textureOutput, Action <Bitmap, string, Rectangle, Image.Transform> f) { SaveTextureAssets(context, bitmapSheet.Sheets, textureOutput, true); foreach (BitmapSheet.Element item in bitmapSheet.Elements) { string textureURI = Path.Combine(context.Directory, Path.ChangeExtension((string)item.Sheet.Tag, null)); var clippingRectangle = new Rectangle(item.Bounds.X, item.Bounds.Y, item.Bounds.Width, item.Bounds.Height); var appliedTransform = item.AppliedTransform; f(item.Source, textureURI, clippingRectangle, appliedTransform); } }
protected override void Export(CookingContext context, SpriteSet input) { var spriteBitmaps = new Dictionary <Bitmap, List <Tuple <Sprite, int> > >(); foreach (var item in input.Sprites) { var tag = (SpriteCookingTag)item.Value.Tag; for (int i = 0; i < tag.Bitmaps.Count; i++) { Bitmap bitmap = tag.Bitmaps[i]; List <Tuple <Sprite, int> > values = null; if (spriteBitmaps.TryGetValue(bitmap, out values)) { values.Add(Tuple.Create(item.Value, i)); } else { values = new List <Tuple <Sprite, int> >(); values.Add(Tuple.Create(item.Value, i)); spriteBitmaps.Add(bitmap, values); } } } using (var bitmapSheet = BitmapSheet.Create(spriteBitmaps.Keys, BitmapSheetSize.Width, BitmapSheetSize.Height, BitmapSheetClusterSize.Width, BitmapSheetClusterSize.Height, BitmapSheet.Options.PowerOfTwoSize | BitmapSheet.Options.RotatableMerging)) { ExportImageSet.SaveTextureAssets(context, bitmapSheet, TextureOutput, (source, textureURI, clippingRectangle, appliedTransform) => { List <Tuple <Sprite, int> > values = null; if (spriteBitmaps.TryGetValue(source, out values)) { foreach (var item in values) { item.Item1.Keyframes[item.Item2].TextureURI = textureURI; item.Item1.Keyframes[item.Item2].ClippingRectangle = clippingRectangle; item.Item1.Keyframes[item.Item2].AppliedTransform = appliedTransform; } } }); } }
public static void Export(CookingContext context, ImageSet input, Size bitmapSheetSize, Size bitmapSheetClusterSize, string textureOutput) { var imageBitmaps = new Dictionary <Bitmap, List <Image> >(); foreach (var item in input.Images) { var tag = (ImageCookingTag)item.Value.Tag; List <Image> values = null; if (imageBitmaps.TryGetValue(tag.Bitmap, out values)) { values.Add(item.Value); } else { values = new List <Image>(); values.Add(item.Value); imageBitmaps.Add(tag.Bitmap, values); } } using (var bitmapSheet = BitmapSheet.Create(imageBitmaps.Keys, bitmapSheetSize.Width, bitmapSheetSize.Height, bitmapSheetClusterSize.Width, bitmapSheetClusterSize.Height, BitmapSheet.Options.PowerOfTwoSize | BitmapSheet.Options.RotatableMerging)) { SaveTextureAssets(context, bitmapSheet, textureOutput, (source, textureURI, clippingRectangle, appliedTransform) => { List <Image> values = null; if (imageBitmaps.TryGetValue(source, out values)) { foreach (Image image in values) { image.TextureURI = textureURI; image.ClippingRectangle = clippingRectangle; image.AppliedTransform = appliedTransform; } } }); } }
private void MergeAllImages(CookingContext context, ICollection <UIImage> images) { var imageBitmaps = new Dictionary <Bitmap, List <UIImage> >(images.Count); foreach (var item in images) { var tag = item.Source.Tag as ImageCookingTag; if (tag != null && tag.Bitmap != null) { List <UIImage> values = null; if (imageBitmaps.TryGetValue(tag.Bitmap, out values)) { values.Add(item); } else { values = new List <UIImage>() { item }; imageBitmaps.Add(tag.Bitmap, values); } } } using (var bitmapSheet = BitmapSheet.Create(imageBitmaps.Keys, BitmapSheetSize.Width, BitmapSheetSize.Height, BitmapSheetClusterSize.Width, BitmapSheetClusterSize.Height, BitmapSheet.Options.PowerOfTwoSize /* | BitmapSheet.Options.RotatableMerging*/)) { #region Texture File과 Asset을 저장합니다. string absoluteDirectory = Path.Combine(context.BaseDirectory, context.Directory); if (Directory.Exists(absoluteDirectory) == false) { Directory.CreateDirectory(absoluteDirectory); } int textureNumber = 0; string textureOutputFormat = context.ExpandVariables(TextureOutput); foreach (Bitmap item in bitmapSheet.Sheets) { Trace.Assert(item.Tag == null); // 밑에서 Tag를 직접 사용할 것이기 때문에 확인합니다. string path = string.Format(textureOutputFormat, textureNumber++); string textureFilePath = Path.ChangeExtension(path, "png"); string fullPath = Path.Combine(absoluteDirectory, textureFilePath); string fullPathDirectory = Path.GetDirectoryName(fullPath); if (Directory.Exists(fullPathDirectory) == false) { Directory.CreateDirectory(fullPathDirectory); } item.Save(fullPath, ImageFormat.Png); item.Tag = textureFilePath; using (var fs = new FileStream(Path.ChangeExtension(fullPath, "asset"), FileMode.Create, FileAccess.Write)) { // png 파일은 자동 추론 되기 때문에 그냥 빈 파일만 생성합니다. } } #endregion #region Image Asset을 저장합니다 // EMBEDDED UIIMAGE /* * var readImage = new ReadGameAsset(); * var imageRecipe = new GameAssetRecipe() * { * Cook = readImage, * Author = GetType().FullName, * Comment = "Automatically generated.", * }; * * int imageNumber = 0; * string imageOutputFormat = context.ExpandVariables(ImageOutput); */ foreach (BitmapSheet.Element item in bitmapSheet.Elements) { string textureURI = Path.Combine(context.Directory, Path.ChangeExtension((string)item.Sheet.Tag, null)); /* * string path = string.Format(imageOutputFormat, imageNumber++); * * readImage.Input = new Image() * { * TextureURI = Path.Combine(context.Directory, Path.ChangeExtension((string)item.Sheet.Tag, null)), * ClippingRectangle = new Rectangle(item.Bounds.X, item.Bounds.Y, * item.Bounds.Width, item.Bounds.Height), * AppliedTransform = item.AppliedTransform, * }; * * JsonSerializer.Instance.Serialize(Path.Combine(context.BaseDirectory, context.Directory, Path.ChangeExtension(path, "asset")), imageRecipe); */ List <UIImage> values = null; if (imageBitmaps.TryGetValue(item.Source, out values)) { foreach (var image in values) { image.Source.TextureURI = textureURI; image.Source.ClippingRectangle = new Rectangle(item.Bounds.X, item.Bounds.Y, item.Bounds.Width, item.Bounds.Height); image.Source.AppliedTransform = item.AppliedTransform; } /* * context.Store(Path.Combine(context.Directory, Path.ChangeExtension(path, null)), values[0].Source); * * for (int i = 1; i < values.Count; i++) * values[i] = values[0]; */ } } #endregion } }
private static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.White; /* new epicHiveObjectsCXML(), new lostHallsObjectsCXML(), new oryxScribeObjectsCXML(), * new cnidarianReefObjectsCXML(), new gemLordObjectCXML(), new testAtrapperObjectCXML(), new stSorcAndHuntObjectsCXML(), * new bearCaveObjectCXML(), new goblinLairObjectCXML(), new KrathTestObjectsCXML(), new KrathMuTestObjectsCXML()];*/ var objectXmlPaths = new[] { "projectiles.xml", "equip.xml", "skins.xml", "dungeons/testAtrapper/testAtrapperSkins.xml", "dungeons/stSorcAndHunt/stSorcAndHuntSkins.xml", "dyes.xml", "textiles.xml", "permapets.xml", "token.xml", "testing/willemTesting.xml", "testing/ttesting.xml", "testing/btesting.xml", "testing/stesting.xml", "testing/mtesting.xml", "testing/ktesting.xml", "players.xml", "containers.xml", "objects.xml", "portals.xml", "testingObjects.xml", "staticobjects.xml", "tutorial/tutorialObjects.xml", "tutorial/tutorialMonsters.xml", "allies.xml", "heroes.xml", "playersZombies.xml", "pets.xml", "npc.xml", "realm/shore.xml", "realm/low.xml", "realm/mid.xml", "realm/high.xml", "realm/mountains.xml", "encounters.xml", "arena.xml", "dungeons/oryxCastle.xml", "dungeons/tombOfTheAncients.xml", "dungeons/spriteWorld.xml", "dungeons/undeadLair.xml", "dungeons/oceanTrench.xml", "dungeons/forbiddenJungle.xml", "dungeons/oryxChamber.xml", "dungeons/oryxChickenChamber.xml", "dungeons/oryxWineCellar.xml", "dungeons/manorOfTheImmortals.xml", "dungeons/pirateCave.xml", "dungeons/snakePit.xml", "dungeons/spiderDen.xml", "dungeons/abyssOfDemons.xml", "dungeons/ghostShip.xml", "dungeons/madLab.xml", "dungeons/caveOfAThousandTreasures.xml", "dungeons/candyLand.xml", "dungeons/hauntedCemetery.xml", "dungeons/forestMaze.xml", "dungeons/epicForestMaze.xml", "dungeons/epicPirateCave.xml", "dungeons/epicSpiderDen.xml", "dungeons/nexusDestroyed.xml", "dungeons/miniDungeonHub.xml", "dungeons/lairOfDraconis.xml", "dungeons/lairOfShaitan.xml", "dungeons/shatters.xml", "dungeons/belladonna.xml", "dungeons/puppetMaster.xml", "dungeons/iceCave.xml", "dungeons/theHive.xml", "dungeons/toxicSewers.xml", "dungeons/puppetMasterEncore.xml", "dungeons/iceTomb.xml", "dungeons/parasiteDen/parasiteDenObjects.xml", "dungeons/stPatricks/stPatricksObjects.xml", "dungeons/buffedBunny/buffedBunnyObjects.xml", "dungeons/hanamiNexus/hanamiNexusObjects.xml", "dungeons/mountainTemple/mountainTempleObjects.xml", "dungeons/oryxHorde/oryxHordeObjects.xml", "dungeons/summerNexus/summerNexusObjects.xml", "dungeons/autumnNexus/autumnNexusObjects.xml", "dungeons/epicHive/epicHiveObjects.xml", "dungeons/lostHalls/lostHallsObjects.xml", "dungeons/oryxScribe/oryxScribeObjects.xml", "dungeons/cnidarianReef/cnidarianReefObjects.xml", "dungeons/magicWoods/magicWoodsObjects.xml", "dungeons/santaWorkshop/santaWorkshopObjects.xml", "dungeons/gemLord/gemLordObjects.xml", "dungeons/testAtrapper/testAtrapperObjects.xml", "dungeons/stSorcAndHunt/stSorcAndHuntObjects.xml", "dungeons/bearCave/bearCaveObjects.xml", "dungeons/goblinLair/goblinLairObjects.xml", "dungeons/krathTest/krathTestObjects.xml", "dungeons/krathTest/krathMuTestObjects.xml" }; foreach (var file in objectXmlPaths.Select(o => new FileInfo($"xml/{o}"))) { if (!file.Exists) { Log($"ERROR: {file.FullName} doesn't exist"); continue; } load(file); } Log($"{items.Count} items"); var rendersBitmap = new Bitmap(40 * 25, Math.Max(items.Count / 25, 1) * 40); Log( $"Output bitmap: {rendersBitmap.Width} * {rendersBitmap.Height} ({rendersBitmap.Width * rendersBitmap.Height}px)"); var dict = new Dictionary <int, List <object> > { { -1, new List <object> { "empty slot", 0, -1, 0, 0, 0, 0 } } }; var bitmapSheetByName = new Dictionary <string, BitmapSheet>(); var addedSprites = new Dictionary <string, Dictionary <ushort, int> >(); var index = 1; foreach (var item in items) { var increment = true; var sheet = new FileInfo($"sheets/{item.Sheet}.png"); if (!sheet.Exists) { Log($"ERROR: sheet {sheet.Name} doesn't exist"); break; } var sheetBitmap = AImage.FromFile(sheet.FullName); if (!bitmapSheetByName.ContainsKey(item.Sheet)) { Log( $"{item.Sheet} bitmap: {sheetBitmap.Width} * {sheetBitmap.Height} ({sheetBitmap.Width * sheetBitmap.Height}px)"); int size; bool animated; switch (sheetBitmap.Width) { case 8 * 16: size = 8; animated = false; break; case 8 * 7: size = 8; animated = true; break; case 16 * 16: size = 16; animated = false; break; case 16 * 7: size = 16; animated = true; break; default: Log($"ERROR: unknown width: {sheetBitmap.Width}"); continue; } bitmapSheetByName.Add(item.Sheet, BitmapSheet.FromImage(sheet.FullName, 5, 4, size, false, false, false)); Log( $"{item.Sheet} - size {size} animated {animated} indexes {bitmapSheetByName[item.Sheet].Bitmaps.Keys.Max()}"); } // Log($"{item.Id}: {item.Sheet}.{item.Index}"); if (!addedSprites.ContainsKey(item.Sheet)) { addedSprites.Add(item.Sheet, new Dictionary <ushort, int>()); } int x, y; if (!addedSprites[item.Sheet].ContainsKey(item.Index)) { addedSprites[item.Sheet].Add(item.Index, index); indexToCoords(index, rendersBitmap.Width, out x, out y); rendersBitmap.Add( bitmapSheetByName[item.Sheet].Bitmaps[ item.Animated ? (ushort)(item.Index * (item.Sheet.Contains("player") ? 21 : 7)) : item.Index], x, y); } else { indexToCoords(addedSprites[item.Sheet][item.Index], rendersBitmap.Width, out x, out y); increment = false; } dict.Add(item.Type, new List <object> { item.Id, item.SlotType, item.Tier, x, y, item.FameBonus, item.FeedPower }); if (increment) { index++; } } rendersBitmap.SavePng("renders.png"); rendersBitmap.Dispose(); var classesDict = classes.ToDictionary <ClassData, int, List <object> >(classData => classData.Type, classData => new List <object> { classData.Id ?? "", classData.Starts ?? new ushort[0], classData.Averages ?? new ushort[0], classData.Maxes ?? new ushort[0], classData.Slots ?? new ushort[0] }); File.WriteAllText("constants.js", $@"items = { JsonConvert.SerializeObject(dict, new JsonSerializerSettings {Formatting = Formatting.Indented}) } classes = {JsonConvert.SerializeObject(classesDict, new JsonSerializerSettings {Formatting = Formatting.Indented})} skins = {{ {string.Join("\n", skins.Select(skin => $" 0x{skin.Type:x}: {skin.Index}, // {skin.Id}"))} }}"); var skinBitmap = new Bitmap(56, (skins.Count + 14) * 24); var maskBitmap = new Bitmap(56, (skins.Count + 14) * 24); addedSprites.Clear(); index = 0; foreach (var classData in classes) { var sheet = new FileInfo($"sheets/{classData.Sheet}.png"); if (!sheet.Exists) { Log($"ERROR: sheet {sheet.Name} doesn't exist"); break; } var mask = new FileInfo($"sheets/{classData.Sheet}Mask.png"); var maskSheet = AImage.FromFile(mask.FullName); var sheetBitmap = AImage.FromFile(sheet.FullName); var crop = new Crop(new Rectangle(0, classData.SheetIndex * 24, 56, 24)); var piece = crop.Apply(sheetBitmap); skinBitmap.Add(piece, 0, index * 24); crop = new Crop(new Rectangle(0, classData.SheetIndex * 24, 56, 24)); piece = crop.Apply(maskSheet); maskBitmap.Add(piece, 0, index * 24); index++; } index = 0; foreach (var skinData in skins.OrderBy(skin => skin.Index)) { var sheet = new FileInfo($"sheets/{skinData.Sheet}.png"); if (!sheet.Exists) { Log($"ERROR: sheet {sheet.Name} doesn't exist"); break; } var mask = new FileInfo($"sheets/{skinData.Sheet}Mask.png"); var maskSheet = AImage.FromFile(mask.FullName); var sheetBitmap = AImage.FromFile(sheet.FullName); var crop = new Crop(new Rectangle(0, skinData.SheetIndex * 24, 56, 24)); var piece = crop.Apply(sheetBitmap); skinBitmap.Add(piece, 0, (index + 14) * 24); crop = new Crop(new Rectangle(0, skinData.SheetIndex * 24, 56, 24)); piece = crop.Apply(maskSheet); maskBitmap.Add(piece, 0, (index + 14) * 24); index++; } using (var ms = new MemoryStream()) { skinBitmap.Save(ms, ImageFormat.Png); File.WriteAllText("sheets-skin.js", $"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}"); } using (var ms = new MemoryStream()) { maskBitmap.Save(ms, ImageFormat.Png); File.WriteAllText("sheets-skinmask.js", $"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}"); } skinBitmap.SavePng("skins.png"); maskBitmap.SavePng("skinsmask.png"); }