/// <summary> /// Gets a Color32 array for engine with a border. /// </summary> /// <param name="srcBitmap">Source DFBitmap.</param> /// <param name="alphaIndex">Index to receive transparent alpha.</param> /// <param name="border">Number of pixels border to add around image.</param> /// <param name="sizeOut">Receives image dimensions with borders included.</param> /// <returns>Color32 array.</returns> public Color32[] GetColors32(DFBitmap srcBitmap, int alphaIndex, int border, out DFSize sizeOut) { // Must be an indexed format if (srcBitmap.Format != DFBitmap.Formats.Indexed) { sizeOut = new DFSize(); return null; } // Calculate dimensions int srcWidth = srcBitmap.Width; int srcHeight = srcBitmap.Height; int dstWidth = srcWidth + border * 2; int dstHeight = srcHeight + border * 2; // Create target array Color32[] colors = new Color32[dstWidth * dstHeight]; DFColor c; byte a; int index, srcRow, dstRow; for (int y = 0; y < srcHeight; y++) { // Get row position srcRow = y * srcWidth; dstRow = (dstHeight - 1 - border - y) * dstWidth; // Write data for this row for (int x = 0; x < srcWidth; x++) { index = srcBitmap.Data[srcRow + x]; c = myPalette.Get(index); if (alphaIndex == index) a = 0x00; else a = 0xff; colors[dstRow + border + x] = new Color32(c.R, c.G, c.B, a); } } sizeOut = new DFSize(dstWidth, dstHeight); return colors; }
/// <summary> /// Gets a Color32 array as emission map based for window textures. /// </summary> /// <param name="srcBitmap">Source bitmap.</param> /// <param name="emissionIndex">Index to receive emission colour.</param> /// <returns>Color32 array.</returns> public Color32[] GetWindowColors32(DFBitmap srcBitmap, int emissionIndex = 0xff) { // Must be an indexed format if (srcBitmap.Format != DFBitmap.Formats.Indexed) return null; // Create target array DFSize sz = new DFSize(srcBitmap.Width, srcBitmap.Height); Color32[] emissionColors = new Color32[sz.Width * sz.Height]; // Generate emissive parts of texture based on index int index, srcRow, dstRow; for (int y = 0; y < sz.Height; y++) { // Get row position srcRow = y * sz.Width; dstRow = (sz.Height - 1 - y) * sz.Width; // Write data for this row for (int x = 0; x < sz.Width; x++) { index = srcBitmap.Data[srcRow + x]; if (index == emissionIndex) emissionColors[dstRow + x] = Color.white; } } return emissionColors; }
/// <summary> /// Special handling for RCI files. /// </summary> /// <param name="reader">Source reader.</param> /// <param name="filename">Name of this file without path.</param> private void ReadRci(ref BinaryReader reader, string filename) { // Set dimensions based on filename DFSize sz; switch (filename) { case "FACES.CIF": case "CHLD00I0.RCI": sz = new DFSize(64, 64); break; case "TFAC00I0.RCI": records = new Record[503]; // Extend array as this file has hundreds of images sz = new DFSize(64, 64); break; case "BUTTONS.RCI": sz = new DFSize(32, 16); break; case "MPOP.RCI": sz = new DFSize(17, 17); break; case "NOTE.RCI": sz = new DFSize(44, 9); break; case "SPOP.RCI": sz = new DFSize(22, 22); break; default: return; } // Get image count int count = managedFile.Length / (sz.Width * sz.Height); // Read count image records for (int i = 0; i < count; i++) { // Create empty frame object records[i].Header.Position = reader.BaseStream.Position; records[i].Header.XOffset = 0; records[i].Header.YOffset = 0; records[i].Header.Width = (Int16)sz.Width; records[i].Header.Height = (Int16)sz.Height; records[i].Header.Compression = CompressionFormats.Uncompressed; records[i].Header.PixelDataLength = (UInt16)(sz.Width * sz.Height); records[i].Header.FrameCount = 1; records[i].Header.DataPosition = reader.BaseStream.Position; // Set record type records[i].FileType = RecordType.MultiImage; // Increment past image data for now reader.BaseStream.Position += records[i].Header.PixelDataLength; // Create empty frame object records[i].Frames = new DFBitmap[1]; } // Store count totalRecords = count; }
/// <summary> /// Gets a Color32 array for engine with a border. /// </summary> /// <param name="record">Record index.</param> /// <param name="frame">Frame index.</param> /// <param name="alphaIndex">Index to receive transparent alpha.</param> /// <param name="border">Number of pixels border to add around image.</param> /// <param name="sizeOut">Receives image dimensions with borders included.</param> /// <returns>Color32 array.</returns> public Color32[] GetColors32(int record, int frame, int alphaIndex, int border, out DFSize sizeOut) { // Get source bitmap DFBitmap srcBitmap = GetDFBitmap(record, frame); return GetColors32(srcBitmap, alphaIndex, border, out sizeOut); }
private static void MixColor(ref Color32[] colors, ref DFSize size, Color32 src, int x, int y) { // Handle outside of bounds if (x < 0 || y < 0 || x > size.Width - 1 || y > size.Height - 1) return; // Get destination pixel colour and ensure it has empty alpha Color32 dst = ReadColor(ref colors, ref size, x, y); if (dst.a != 0) return; // Get count for averaging int count = 1; if (dst != Color.clear) count = 2; // Mix source colour with destination Vector3 avg = new Vector3( src.r + dst.r, src.g + dst.g, src.b + dst.b) / count; // Assign new colour to destination colors[y * size.Width + x] = new Color32((byte)avg.x, (byte)avg.y, (byte)avg.z, 0); }
private static Color32 ReadColor(ref Color32[] colors, ref DFSize size, int x, int y) { // Handle outside of bounds if (x < 0 || y < 0 || x > size.Width - 1 || y > size.Height - 1) return Color.clear; return colors[y * size.Width + x]; }
/// <summary> /// Wraps texture into emtpty border area on opposite side. /// </summary> /// <param name="colors">Source image.</param> /// <param name="size">Image size.</param> /// <param name="border">Border width.</param> public static void WrapBorder(ref Color32[] colors, DFSize size, int border, bool leftRight = true, bool topBottom = true) { // Wrap left-right if (leftRight) { for (int y = border; y < size.Height - border; y++) { int ypos = y * size.Width; int il = ypos + border; int ir = ypos + size.Width - border * 2; for (int x = 0; x < border; x++) { colors[ypos + x] = colors[ir + x]; colors[ypos + size.Width - border + x] = colors[il + x]; } } } // Wrap top-bottom if (topBottom) { for (int y = 0; y < border; y++) { int ypos1 = y * size.Width; int ypos2 = (y + size.Height - border) * size.Width; int it = (border + y) * size.Width; int ib = (y + size.Height - border * 2) * size.Width; for (int x = 0; x < size.Width; x++) { colors[ypos1 + x] = colors[ib + x]; colors[ypos2 + x] = colors[it + x]; } } } }
/// <summary> /// Clamps texture into empty border area. /// </summary> /// <param name="colors">Source image.</param> /// <param name="size">Image size.</param> /// <param name="border">Border width.</param> public static void ClampBorder( ref Color32[] colors, DFSize size, int border, bool leftRight = true, bool topBottom = true, bool topLeft = true, bool topRight = true, bool bottomLeft = true, bool bottomRight = true) { if (leftRight) { // Clamp left-right for (int y = border; y < size.Height - border; y++) { int ypos = y * size.Width; Color32 leftColor = colors[ypos + border]; Color32 rightColor = colors[ypos + size.Width - border - 1]; int il = ypos; int ir = ypos + size.Width - border; for (int x = 0; x < border; x++) { colors[il + x] = leftColor; colors[ir + x] = rightColor; } } } if (topBottom) { // Clamp top-bottom for (int x = border; x < size.Width - border; x++) { Color32 topColor = colors[((border) * size.Width) + x]; Color32 bottomColor = colors[(size.Height - border - 1) * size.Width + x]; for (int y = 0; y < border; y++) { int it = y * size.Width + x; int ib = (size.Height - y - 1) * size.Width + x; colors[it] = topColor; colors[ib] = bottomColor; } } } if (topLeft) { // Clamp top-left Color32 topLeftColor = colors[(border + 1) * size.Width + border]; for (int y = 0; y < border; y++) { for (int x = 0; x < border; x++) { colors[y * size.Width + x] = topLeftColor; } } } if (topRight) { // Clamp top-right Color32 topRightColor = colors[(border + 1) * size.Width + size.Width - border - 1]; for (int y = 0; y < border; y++) { for (int x = size.Width - border; x < size.Width; x++) { colors[y * size.Width + x] = topRightColor; } } } if (bottomLeft) { // Clamp bottom-left Color32 bottomLeftColor = colors[(size.Height - border - 1) * size.Width + border]; for (int y = size.Height - border; y < size.Height; y++) { for (int x = 0; x < border; x++) { colors[y * size.Width + x] = bottomLeftColor; } } } if (bottomRight) { // Clamp bottom-right Color32 bottomRightColor = colors[(size.Height - border - 1) * size.Width + size.Width - border - 1]; for (int y = size.Height - border; y < size.Height; y++) { for (int x = size.Width - border; x < size.Width; x++) { colors[y * size.Width + x] = bottomRightColor; } } } }
/// <summary> /// Creates a blended border around transparent textures. /// Removes dark edges from billboards. /// </summary> /// <param name="colors">Source image.</param> /// <param name="size">Image size.</param> public static void DilateColors(ref Color32[] colors, DFSize size) { for (int y = 0; y < size.Height; y++) { for (int x = 0; x < size.Width; x++) { Color32 color = ReadColor(ref colors, ref size, x, y); if (color.a != 0) { MixColor(ref colors, ref size, color, x - 1, y - 1); MixColor(ref colors, ref size, color, x, y - 1); MixColor(ref colors, ref size, color, x + 1, y - 1); MixColor(ref colors, ref size, color, x - 1, y); MixColor(ref colors, ref size, color, x + 1, y); MixColor(ref colors, ref size, color, x - 1, y + 1); MixColor(ref colors, ref size, color, x, y + 1); MixColor(ref colors, ref size, color, x + 1, y + 1); } } } }
// Copies a subset of Color32 array into XY position of another Color32 array public static void CopyColors(ref Color32[] src, ref Color32[] dst, DFSize srcSize, DFSize dstSize, DFPosition srcPos, DFPosition dstPos, DFSize copySize) { for (int y = 0; y < copySize.Height; y++) { for (int x = 0; x < copySize.Width; x++) { Color32 col = src[(srcPos.Y + y) * srcSize.Width + (srcPos.X + x)]; dst[(dstPos.Y + y) * dstSize.Width + (dstPos.X + x)] = col; } } }
/// <summary> /// Gets a Color32 array for engine. /// </summary> /// <param name="srcBitmap">Source DFBitmap.</param> /// <param name="alphaIndex">Index to receive transparent alpha.</param> /// <param name="border">Number of pixels border to add around image.</param> /// <param name="sizeOut">Receives image dimensions with borders included.</param> /// <returns>Color32 array.</returns> public Color32[] GetColor32(DFBitmap srcBitmap, int alphaIndex, int border, out DFSize sizeOut) { // Calculate dimensions int srcWidth = srcBitmap.Width; int srcHeight = srcBitmap.Height; int dstWidth = srcWidth + border * 2; int dstHeight = srcHeight + border * 2; Color32[] colors = new Color32[dstWidth * dstHeight]; Color32 c = new Color32(); int index, offset, srcRow, dstRow; byte[] paletteData = myPalette.PaletteBuffer; for (int y = 0; y < srcHeight; y++) { // Get row position srcRow = y * srcWidth; dstRow = (dstHeight - 1 - border - y) * dstWidth; // Write data for this row for (int x = 0; x < srcWidth; x++) { index = srcBitmap.Data[srcRow + x]; offset = myPalette.HeaderLength + index * 3; c.r = paletteData[offset]; c.g = paletteData[offset + 1]; c.b = paletteData[offset + 2]; c.a = (alphaIndex == index) ? (byte)0 : (byte)255; colors[dstRow + border + x] = c; } } sizeOut = new DFSize(dstWidth, dstHeight); return colors; }