#region References
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
#endregion
namespace Ultima
{
public sealed class MultiMap
{
private static byte[] m_StreamBuffer;
///
/// Returns Bitmap
///
///
public static unsafe Bitmap GetMultiMap()
{
string path = Files.GetFilePath("Multimap.rle");
if (path != null)
{
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var bin = new BinaryReader(fs))
{
int width, height;
byte pixel;
int count;
int x, i;
x = 0;
ushort c = 0;
width = bin.ReadInt32();
height = bin.ReadInt32();
var multimap = new Bitmap(width, height, Settings.PixelFormat);
BitmapData bd = multimap.LockBits(
new Rectangle(0, 0, multimap.Width, multimap.Height), ImageLockMode.WriteOnly, Settings.PixelFormat);
var line = (ushort*)bd.Scan0;
int delta = bd.Stride >> 1;
ushort* cur = line;
var len = (int)(bin.BaseStream.Length - bin.BaseStream.Position);
if (m_StreamBuffer == null || m_StreamBuffer.Length < len)
{
m_StreamBuffer = new byte[len];
}
bin.Read(m_StreamBuffer, 0, len);
int j = 0;
while (j != len)
{
pixel = m_StreamBuffer[j++];
count = (pixel & 0x7f);
if ((pixel & 0x80) != 0)
{
c = 0x8000; //Color.Black;
}
else
{
c = 0xffff; //Color.White;
}
for (i = 0; i < count; ++i)
{
cur[x++] = c;
if (x >= width)
{
cur += delta;
x = 0;
}
}
}
multimap.UnlockBits(bd);
return multimap;
}
}
}
return null;
}
///
/// Saves Bitmap to rle Format
///
///
///
public static unsafe void SaveMultiMap(Bitmap image, BinaryWriter bin)
{
bin.Write(2560); // width
bin.Write(2048); // height
byte data = 1;
byte mask = 0x0;
ushort curcolor = 0;
BitmapData bd = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, Settings.PixelFormat);
var line = (ushort*)bd.Scan0;
int delta = bd.Stride >> 1;
ushort* cur = line;
curcolor = cur[0]; //init
for (int y = 0; y < image.Height; ++y, line += delta)
{
cur = line;
for (int x = 0; x < image.Width; ++x)
{
ushort c = cur[x];
if (c == curcolor)
{
++data;
if (data == 0x7f)
{
if (curcolor == 0xffff)
{
mask = 0x0;
}
else
{
mask = 0x80;
}
data |= mask;
bin.Write(data);
data = 1;
}
}
else
{
if (curcolor == 0xffff)
{
mask = 0x0;
}
else
{
mask = 0x80;
}
data |= mask;
bin.Write(data);
curcolor = c;
data = 1;
}
}
}
if (curcolor == 0xffff)
{
mask = 0x0;
}
else
{
mask = 0x80;
}
data |= mask;
bin.Write(data);
image.UnlockBits(bd);
}
///
/// reads facet0*.mul into Bitmap
///
/// facet id
/// Bitmap
public static unsafe Bitmap GetFacetImage(int id)
{
Bitmap bmp;
string path = Files.GetFilePath(String.Format("facet0{0}.mul", id));
if (path != null)
{
using (var reader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
int width = reader.ReadInt16();
int height = reader.ReadInt16();
bmp = new Bitmap(width, height);
BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, Settings.PixelFormat);
var line = (ushort*)bd.Scan0;
int delta = bd.Stride >> 1;
for (int y = 0; y < height; y++, line += delta)
{
int colorsCount = reader.ReadInt32() / 3;
ushort* endline = line + delta;
ushort* cur = line;
ushort* end;
for (int c = 0; c < colorsCount; c++)
{
byte count = reader.ReadByte();
short color = reader.ReadInt16();
end = cur + count;
while (cur < end)
{
if (cur > endline)
{
break;
}
*cur++ = (ushort)(color ^ 0x8000);
}
}
}
bmp.UnlockBits(bd);
}
return bmp;
}
return null;
}
///
/// Stores Image into facet.mul format
///
///
///
public static unsafe void SaveFacetImage(string path, Bitmap sourceBitmap)
{
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
using (
var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)))
{
writer.Write((short)width);
writer.Write((short)height);
BitmapData bd = sourceBitmap.LockBits(
new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, Settings.PixelFormat);
var line = (ushort*)bd.Scan0;
int delta = bd.Stride >> 1;
for (int y = 0; y < height; y++, line += delta)
{
long pos = writer.BaseStream.Position;
writer.Write(0); //bytes count for current line
int colorsAtLine = 0;
int colorsCount = 0;
int x = 0;
while (x < width)
{
ushort hue = line[x];
while (x < width && colorsCount < byte.MaxValue && hue == line[x])
{
++colorsCount;
++x;
}
writer.Write((byte)colorsCount);
writer.Write((ushort)(hue ^ 0x8000));
colorsAtLine++;
colorsCount = 0;
}
long currpos = writer.BaseStream.Position;
writer.BaseStream.Seek(pos, SeekOrigin.Begin);
writer.Write(colorsAtLine * 3); //byte count
writer.BaseStream.Seek(currpos, SeekOrigin.Begin);
}
}
}
}
}