private Texture2D GetWeaponTextureAtlas( string filename, MetalTypes metalType, out Rect[] rectsOut, out RecordIndex[] indicesOut, int padding, int border, bool dilate = false) { // Load texture file cifFile.Load(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true); // Read every image in archive Rect rect; List <Texture2D> textures = new List <Texture2D>(); List <RecordIndex> indices = new List <RecordIndex>(); for (int record = 0; record < cifFile.RecordCount; record++) { int frames = cifFile.GetFrameCount(record); DFSize size = cifFile.GetSize(record); RecordIndex ri = new RecordIndex() { startIndex = textures.Count, frameCount = frames, width = size.Width, height = size.Height, }; indices.Add(ri); for (int frame = 0; frame < frames; frame++) { textures.Add(GetWeaponTexture2D(filename, record, frame, metalType, out rect, border, dilate)); } } // Pack textures into atlas Texture2D atlas = new Texture2D(2048, 2048, TextureFormat.RGBA32, false); rectsOut = atlas.PackTextures(textures.ToArray(), padding, 2048); indicesOut = indices.ToArray(); // Shrink UV rect to compensate for internal border float ru = 1f / atlas.width; float rv = 1f / atlas.height; for (int i = 0; i < rectsOut.Length; i++) { Rect rct = rectsOut[i]; rct.xMin += border * ru; rct.xMax -= border * ru; rct.yMin += border * rv; rct.yMax -= border * rv; rectsOut[i] = rct; } return(atlas); }
/// <summary> /// Get name for a CifRci image with a metal type. /// </summary> /// <param name="filename">Name of CIF/RCI file.</param> /// <param name="record">Record index.</param> /// <param name="frame">Frame index. It's different than zero only for animations.</param> /// <param name="metalType">Metal type of weapon.</param> static public string GetNameCifRci(string filename, int record, int frame, MetalTypes metalType) { if (metalType == MetalTypes.None) { return(GetNameCifRci(filename, record, frame)); } return(string.Format("{0}_{1}", GetNameCifRci(filename, record, frame), metalType)); }
/// <summary> /// Convert (filename, record, frame) to string name. /// </summary> /// <param name="filename">Name of CIF/RCI file.</param> /// <param name="record">Record index.</param> /// <param name="frame">Frame index. It's different than zero only for animations.</param> /// <param name="metalType">Metal type of weapon.</param> static public string GetNameCifRci(string filename, int record, int frame, MetalTypes metalType) { if (metalType == MetalTypes.None) { return(GetNameCifRci(filename, record, frame)); } else { return(GetNameCifRci(filename, record, frame) + "_" + metalType); } }
// Gets colour indices based on metal type public static byte[] GetMetalColors(MetalTypes metalType) { byte[] indices; switch (metalType) { case MetalTypes.Iron: indices = new byte[] { 0x77, 0x78, 0x57, 0x79, 0x58, 0x59, 0x7A, 0x5A, 0x7B, 0x5B, 0x7C, 0x5C, 0x7D, 0x5D, 0x5E, 0x5F }; break; case MetalTypes.Steel: indices = new byte[] { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F }; break; case MetalTypes.Silver: indices = new byte[] { 0xE0, 0x70, 0x50, 0x71, 0x51, 0x72, 0x73, 0x52, 0x74, 0x53, 0x75, 0x54, 0x55, 0x56, 0x57, 0x58 }; break; case MetalTypes.Elven: indices = new byte[] { 0xE0, 0x70, 0x50, 0x71, 0x51, 0x72, 0x73, 0x52, 0x74, 0x53, 0x75, 0x54, 0x55, 0x56, 0x57, 0x58 }; break; case MetalTypes.Dwarven: indices = new byte[] { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F }; break; case MetalTypes.Mithril: indices = new byte[] { 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE }; break; case MetalTypes.Adamantium: indices = new byte[] { 0x5A, 0x5B, 0x7C, 0x5C, 0x7D, 0x5D, 0x7E, 0x5E, 0x7F, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE }; break; case MetalTypes.Ebony: indices = new byte[] { 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE }; break; case MetalTypes.Orcish: indices = new byte[] { 0xA2, 0xA3, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD }; break; case MetalTypes.Daedric: indices = new byte[] { 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE }; break; default: indices = new byte[] { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F }; break; } return(indices); }
private void LoadWeaponAtlas() { // Get weapon filename string filename = WeaponBasics.GetWeaponFilename(WeaponType); // Load the weapon texture atlas // Texture is dilated into a transparent coloured border to remove dark edges when filtered // Important to use returned UV rects when drawing to get right dimensions weaponAtlas = GetWeaponTextureAtlas(filename, MetalType, out weaponRects, out weaponIndices, 2, 2, true); weaponAtlas.filterMode = dfUnity.MaterialReader.MainFilterMode; // Get weapon anims weaponAnims = (WeaponAnimation[])WeaponBasics.GetWeaponAnims(WeaponType).Clone(); // Store current weapon currentWeaponType = WeaponType; currentMetalType = MetalType; }
private Texture2D GetWeaponTexture2D( string filename, int record, int frame, MetalTypes metalType, out Rect rectOut, int border = 0, bool dilate = false) { // Get source bitmap DFBitmap dfBitmap = cifFile.GetDFBitmap(record, frame); // Tint based on metal type // But not for steel as that is default colour in files if (metalType != MetalTypes.Steel && metalType != MetalTypes.None) { dfBitmap = ImageProcessing.ChangeDye(dfBitmap, ImageProcessing.GetMetalDyeColor(metalType), DyeTargets.WeaponsAndArmor); } // Get Color32 array DFSize sz; Color32[] colors = cifFile.GetColor32(dfBitmap, 0, border, out sz); // Dilate edges if (border > 0 && dilate) { ImageProcessing.DilateColors(ref colors, sz); } // Create Texture2D Texture2D texture = new Texture2D(sz.Width, sz.Height, TextureFormat.ARGB32, false); texture.SetPixels32(colors); texture.Apply(true); // Shrink UV rect to compensate for internal border float ru = 1f / sz.Width; float rv = 1f / sz.Height; rectOut = new Rect(border * ru, border * rv, (sz.Width - border * 2) * ru, (sz.Height - border * 2) * rv); return(texture); }
/// <summary> /// Tint a weapon image based on metal type. /// </summary> /// <param name="srcBitmap">Source weapon image.</param> /// <param name="size">Image size.</param> /// <param name="metalType">Metal type for tint.</param> public static void TintWeaponImage(ref DFBitmap srcBitmap, MetalTypes metalType) { byte[] swaps = GetMetalColors(metalType); int rowPos; for (int y = 0; y < srcBitmap.Height; y++) { rowPos = y * srcBitmap.Width; for (int x = 0; x < srcBitmap.Width; x++) { byte index = srcBitmap.Data[rowPos + x]; if (index >= 0x70 && index <= 0x7f) { int offset = index - 0x70; srcBitmap.Data[rowPos + x] = swaps[offset]; } } } }
/// <summary> /// Converts a DaggerfallUnity metal type to dye colour. /// </summary> public static DyeColors GetMetalDyeColor(MetalTypes metalType) { switch (metalType) { case MetalTypes.Iron: return(DyeColors.Iron); case MetalTypes.Steel: return(DyeColors.Steel); case MetalTypes.Silver: return(DyeColors.Silver); case MetalTypes.Elven: return(DyeColors.Elven); case MetalTypes.Dwarven: return(DyeColors.Dwarven); case MetalTypes.Mithril: return(DyeColors.Mithril); case MetalTypes.Adamantium: return(DyeColors.Adamantium); case MetalTypes.Ebony: return(DyeColors.Ebony); case MetalTypes.Orcish: return(DyeColors.Orcish); case MetalTypes.Daedric: return(DyeColors.Daedric); default: return(DyeColors.Unchanged); } }
/// <summary> /// Search for image on disk to replace .CIFs and .RCIs. for a specific metalType /// (filename_record-frame_metalType.png, for example 'WEAPON04.CIF_0-0_Iron.Png'). /// </summary> /// <param name="filename">Name of image.</param> /// <param name="record">Record index.</param> /// <param name="frame">Frame index. It's different than zero only for weapon animations (WEAPONXX.CIF) </param> /// <returns>True if generic or specific image exists.</returns> static public bool CustomCifExist(string filename, int record, int frame, MetalTypes metalType) { return(TextureFileExist(cifRciPath, GetNameCifRci(filename, record, frame, metalType))); }
/// <summary> /// Seek CifRci with a specific metaltype from modding locations. /// </summary> /// <param name="name">Image name.</param> /// <param name="record">Record index.</param> /// <param name="frame">Animation frame index</param> /// <param name="metalType">Metal type.</param> /// <param name="tex">Imported image as texture.</param> /// <returns>True if CifRci imported.</returns> public static bool TryImportCifRci(string name, int record, int frame, MetalTypes metalType, out Texture2D tex) { return(TryImportTexture(cifRciPath, GetNameCifRci(name, record, frame, metalType), out tex)); }
/// <summary> /// Import image from disk to replace .CIFs and .RCIs. for a specific metalType /// (filename_record-frame_metalType.png', for example 'WEAPON04.CIF_0-0_Iron.Png'). /// </summary> /// <param name="filename">Name of image.</param> /// <param name="record">Record index.</param> /// <param name="frame">Frame index. It's different than zero only for weapon animations (WEAPONXX.CIF) </param> /// <returns>Image for this metalType or generic image if metalType is None.</returns> static public Texture2D LoadCustomCif(string filename, int record, int frame, MetalTypes metalType) { return(ImportTextureFile(cifRciPath, GetNameCifRci(filename, record, frame, metalType))); }
private Texture2D GetWeaponTextureAtlas( string filename, MetalTypes metalType, out Rect[] rectsOut, out RecordIndex[] indicesOut, int padding, int border, bool dilate = false) { // Load texture file cifFile.Load(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true); // Read every image in archive Rect rect; List<Texture2D> textures = new List<Texture2D>(); List<RecordIndex> indices = new List<RecordIndex>(); for (int record = 0; record < cifFile.RecordCount; record++) { int frames = cifFile.GetFrameCount(record); DFSize size = cifFile.GetSize(record); RecordIndex ri = new RecordIndex() { startIndex = textures.Count, frameCount = frames, width = size.Width, height = size.Height, }; indices.Add(ri); for (int frame = 0; frame < frames; frame++) { textures.Add(GetWeaponTexture2D(filename, record, frame, metalType, out rect, border, dilate)); } } // Pack textures into atlas Texture2D atlas = new Texture2D(2048, 2048, TextureFormat.RGBA32, false); rectsOut = atlas.PackTextures(textures.ToArray(), padding, 2048); indicesOut = indices.ToArray(); // Shrink UV rect to compensate for internal border float ru = 1f / atlas.width; float rv = 1f / atlas.height; for (int i = 0; i < rectsOut.Length; i++) { Rect rct = rectsOut[i]; rct.xMin += border * ru; rct.xMax -= border * ru; rct.yMin += border * rv; rct.yMax -= border * rv; rectsOut[i] = rct; } return atlas; }
private void LoadWeaponAtlas() { // Get weapon filename string filename = WeaponBasics.GetWeaponFilename(WeaponType); // Load the weapon texture atlas // Texture is dilated into a transparent coloured border to remove dark edges when filtered // Important to use returned UV rects when drawing to get right dimensions weaponAtlas = GetWeaponTextureAtlas(filename, MetalType, out weaponRects, out weaponIndices, 2, 2, true); weaponAtlas.filterMode = dfUnity.MaterialReader.MainFilterMode; // Get weapon anims weaponAnims = (WeaponAnimation[])WeaponBasics.GetWeaponAnims(WeaponType).Clone(); // Store current weapon lastWeaponType = WeaponType; lastMetalType = MetalType; }
private Texture2D GetWeaponTexture2D( string filename, int record, int frame, MetalTypes metalType, out Rect rectOut, int border = 0, bool dilate = false) { // Get source bitmap DFBitmap dfBitmap = cifFile.GetDFBitmap(record, frame); // Tint based on metal type // But not for steel as that is default colour in files if (metalType != MetalTypes.Steel) ImageProcessing.TintWeaponImage(dfBitmap, metalType); // Get Color32 array DFSize sz; Color32[] colors = cifFile.GetColor32(dfBitmap, 0, border, out sz); // Dilate edges if (border > 0 && dilate) ImageProcessing.DilateColors(ref colors, sz); // Create Texture2D Texture2D texture = new Texture2D(sz.Width, sz.Height, TextureFormat.RGBA32, false); texture.SetPixels32(colors); texture.Apply(true); // Shrink UV rect to compensate for internal border float ru = 1f / sz.Width; float rv = 1f / sz.Height; rectOut = new Rect(border * ru, border * rv, (sz.Width - border * 2) * ru, (sz.Height - border * 2) * rv); return texture; }
/// <summary> /// Converts a DaggerfallUnity metal type to dye colour. /// </summary> public static DyeColors GetMetalDyeColor(MetalTypes metalType) { switch(metalType) { case MetalTypes.Iron: return DyeColors.Iron; case MetalTypes.Steel: return DyeColors.Steel; case MetalTypes.Chain: case MetalTypes.Silver: case MetalTypes.Elven: return DyeColors.SilverOrElven; case MetalTypes.Dwarven: return DyeColors.Dwarven; case MetalTypes.Mithril: return DyeColors.Mithril; case MetalTypes.Adamantium: return DyeColors.Adamantium; case MetalTypes.Ebony: return DyeColors.Ebony; case MetalTypes.Orcish: return DyeColors.Orcish; case MetalTypes.Daedric: return DyeColors.Daedric; default: return DyeColors.Unchanged; } }
/// <summary> /// Tint a weapon image based on metal type. /// </summary> /// <param name="srcBitmap">Source weapon image.</param> /// <param name="size">Image size.</param> /// <param name="metalType">Metal type for tint.</param> public static void TintWeaponImage(DFBitmap srcBitmap, MetalTypes metalType) { // Must be indexed format if (srcBitmap.Format != DFBitmap.Formats.Indexed) return; byte[] swaps = GetMetalColors(metalType); int rowPos; for (int y = 0; y < srcBitmap.Height; y++) { rowPos = y * srcBitmap.Width; for (int x = 0; x < srcBitmap.Width; x++) { byte index = srcBitmap.Data[rowPos + x]; if (index >= 0x70 && index <= 0x7f) { int offset = index - 0x70; srcBitmap.Data[rowPos + x] = swaps[offset]; } } } }
// Gets colour indices based on metal type public static byte[] GetMetalColors(MetalTypes metalType) { byte[] indices; switch (metalType) { case MetalTypes.Iron: indices = new byte[] { 0x77, 0x78, 0x57, 0x79, 0x58, 0x59, 0x7A, 0x5A, 0x7B, 0x5B, 0x7C, 0x5C, 0x7D, 0x5D, 0x5E, 0x5F }; break; case MetalTypes.Steel: indices = new byte[] { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F }; break; case MetalTypes.Silver: indices = new byte[] { 0xE0, 0x70, 0x50, 0x71, 0x51, 0x72, 0x73, 0x52, 0x74, 0x53, 0x75, 0x54, 0x55, 0x56, 0x57, 0x58 }; break; case MetalTypes.Elven: indices = new byte[] { 0xE0, 0x70, 0x50, 0x71, 0x51, 0x72, 0x73, 0x52, 0x74, 0x53, 0x75, 0x54, 0x55, 0x56, 0x57, 0x58 }; break; case MetalTypes.Dwarven: indices = new byte[] { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F }; break; case MetalTypes.Mithril: indices = new byte[] { 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE }; break; case MetalTypes.Adamantium: indices = new byte[] { 0x5A, 0x5B, 0x7C, 0x5C, 0x7D, 0x5D, 0x7E, 0x5E, 0x7F, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE }; break; case MetalTypes.Ebony: indices = new byte[] { 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE }; break; case MetalTypes.Orcish: indices = new byte[] { 0xA2, 0xA3, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD }; break; case MetalTypes.Daedric: indices = new byte[] { 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE }; break; default: indices = new byte[] { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F }; break; } return indices; }
private Texture2D GetWeaponTextureAtlas( string filename, MetalTypes metalType, out Rect[] rectsOut, out RecordIndex[] indicesOut, int padding, int border, bool dilate = false) { // Load texture file cifFile.Load(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true); // Read every image in archive Rect rect; List <Texture2D> textures = new List <Texture2D>(); List <RecordIndex> indices = new List <RecordIndex>(); CustomTextures = new Dictionary <string, Texture2D>(); for (int record = 0; record < cifFile.RecordCount; record++) { int frames = cifFile.GetFrameCount(record); DFSize size = cifFile.GetSize(record); RecordIndex ri = new RecordIndex() { startIndex = textures.Count, frameCount = frames, width = size.Width, height = size.Height, }; indices.Add(ri); for (int frame = 0; frame < frames; frame++) { textures.Add(GetWeaponTexture2D(filename, record, frame, metalType, out rect, border, dilate)); Texture2D tex; if (TextureReplacement.TryImportCifRci(filename, record, frame, metalType, out tex)) { tex.filterMode = (FilterMode)DaggerfallUnity.Settings.MainFilterMode; CustomTextures.Add(record + "-" + frame, tex); } //// Import custom texture //if (TextureReplacement.CustomCifExist(filename, record, frame, metalType)) //{ // Texture2D tex = TextureReplacement.LoadCustomCif(filename, record, frame, metalType); // tex.filterMode = (FilterMode)DaggerfallUnity.Settings.MainFilterMode; // CustomTextures.Add(record + "-" + frame, tex); //} } } // Pack textures into atlas Texture2D atlas = new Texture2D(2048, 2048, TextureFormat.ARGB32, false); rectsOut = atlas.PackTextures(textures.ToArray(), padding, 2048); indicesOut = indices.ToArray(); // Shrink UV rect to compensate for internal border float ru = 1f / atlas.width; float rv = 1f / atlas.height; for (int i = 0; i < rectsOut.Length; i++) { Rect rct = rectsOut[i]; rct.xMin += border * ru; rct.xMax -= border * ru; rct.yMin += border * rv; rct.yMax -= border * rv; rectsOut[i] = rct; } return(atlas); }