#region References using System.Drawing; using System.Drawing.Imaging; using System.IO; #endregion namespace Ultima { public sealed class Light { private static FileIndex m_FileIndex = new FileIndex("lightidx.mul", "light.mul", 100, -1); private static Bitmap[] m_Cache = new Bitmap[100]; private static bool[] m_Removed = new bool[100]; private static byte[] m_StreamBuffer; /// /// ReReads light.mul /// public static void Reload() { m_FileIndex = new FileIndex("lightidx.mul", "light.mul", 100, -1); m_Cache = new Bitmap[100]; m_Removed = new bool[100]; } /// /// Gets count of definied lights /// /// public static int GetCount() { string idxPath = Files.GetFilePath("lightidx.mul"); if (idxPath == null) { return 0; } using (var index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { return (int)(index.Length / 12); } } /// /// Tests if given index is valid /// /// /// public static bool TestLight(int index) { if (m_Removed[index]) { return false; } if (m_Cache[index] != null) { return true; } int length, extra; bool patched; Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched); if (stream == null) { return false; } stream.Close(); int width = (extra & 0xFFFF); int height = ((extra >> 16) & 0xFFFF); if ((width > 0) && (height > 0)) { return true; } return false; } /// /// Removes Light /// /// public static void Remove(int index) { m_Removed[index] = true; } /// /// Replaces Light /// /// /// public static void Replace(int index, Bitmap bmp) { m_Cache[index] = bmp; m_Removed[index] = false; } public static byte[] GetRawLight(int index, out int width, out int height) { width = 0; height = 0; if (m_Removed[index]) { return null; } int length, extra; bool patched; Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched); if (stream == null) { return null; } width = (extra & 0xFFFF); height = ((extra >> 16) & 0xFFFF); var buffer = new byte[length]; stream.Read(buffer, 0, length); stream.Close(); return buffer; } /// /// Returns Bitmap of given index /// /// /// public static unsafe Bitmap GetLight(int index) { if (m_Removed[index]) { return null; } if (m_Cache[index] != null) { return m_Cache[index]; } int length, extra; bool patched; Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched); if (stream == null) { return null; } int width = (extra & 0xFFFF); int height = ((extra >> 16) & 0xFFFF); if (m_StreamBuffer == null || m_StreamBuffer.Length < length) { m_StreamBuffer = new byte[length]; } stream.Read(m_StreamBuffer, 0, length); var bmp = new Bitmap(width, height, Settings.PixelFormat); BitmapData bd = bmp.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, Settings.PixelFormat); var line = (ushort*)bd.Scan0; int delta = bd.Stride >> 1; fixed (byte* data = m_StreamBuffer) { var bindat = (sbyte*)data; for (int y = 0; y < height; ++y, line += delta) { ushort* cur = line; ushort* end = cur + width; while (cur < end) { sbyte value = *bindat++; *cur++ = (ushort)(((0x1f + value) << 10) + ((0x1F + value) << 5) + (0x1F + value)); } } } bmp.UnlockBits(bd); stream.Close(); if (!Files.CacheData) { return m_Cache[index] = bmp; } else { return bmp; } } public static unsafe void Save(string path) { string idx = Path.Combine(path, "lightidx.mul"); string mul = Path.Combine(path, "light.mul"); using ( FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write), fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write)) { using (BinaryWriter binidx = new BinaryWriter(fsidx), binmul = new BinaryWriter(fsmul)) { for (int index = 0; index < m_Cache.Length; index++) { if (m_Cache[index] == null) { m_Cache[index] = GetLight(index); } Bitmap bmp = m_Cache[index]; if ((bmp == null) || (m_Removed[index])) { binidx.Write(-1); // lookup binidx.Write(-1); // length binidx.Write(-1); // extra } else { BitmapData bd = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, Settings.PixelFormat); var line = (ushort*)bd.Scan0; int delta = bd.Stride >> 1; binidx.Write((int)fsmul.Position); //lookup var length = (int)fsmul.Position; for (int Y = 0; Y < bmp.Height; ++Y, line += delta) { ushort* cur = line; ushort* end = cur + bmp.Width; while (cur < end) { var value = (sbyte)(((*cur++ >> 10) & 0xffff) - 0x1f); if (value > 0) // wtf? but it works... { --value; } binmul.Write(value); } } length = (int)fsmul.Position - length; binidx.Write(length); binidx.Write((bmp.Width << 16) + bmp.Height); bmp.UnlockBits(bd); } } } } } } }