//CALL STACK: LoadData -> ReadLayerFromStream private static CompressedLayer _ReadLayerFromStream(BinaryReader br, BahnLib.ZoomFactor zoomFactor, GraphicVersion graphicVersion) { if (br == null) { throw new ArgumentNullException("br"); } CompressedLayer l = new CompressedLayer(); l.X0 = br.ReadInt16(); l.Y0 = br.ReadInt16(); l.Width = br.ReadInt16(); l.Height = br.ReadInt16(); if (graphicVersion == GraphicVersion.Version2) { int layerLength = br.ReadInt32(); List <uint> data = new List <uint>(); for (int i = 0; i < layerLength; i++) { data.Add(br.ReadUInt32()); } l.LayerData = data.ToArray(); } else if (graphicVersion < GraphicVersion.Version2) { uint[,] decompressedLayer = _ReadLayerFromStreamVersion0(br, l.Width, l.Height); l = CompressLayer(_FillLayer(decompressedLayer, l.X0, l.Y0, zoomFactor), zoomFactor); } else { throw new ArgumentOutOfRangeException("graphicVersion"); } return(l); }
private static void _WriteLayerToStream(CompressedLayer layer, BinaryWriter bw, BahnLib.ZoomFactor zoomFactor) { if (bw == null) { throw new ArgumentNullException("bw"); } bw.Write(layer.X0); //x0 bw.Write(layer.Y0); //y0 bw.Write(layer.Width); //width bw.Write(layer.Height); //height bw.Write(layer.LayerData.Length); foreach (uint item in layer.LayerData) { bw.Write(item); } }
/// <summary> /// Gets or sets a layer of the graphic. Null-value represents an empty or fully transparent layer. /// </summary> /// <param name="layerID">The LayerID</param> /// <returns>The layer</returns> public uint[, ] this[LayerID layerID] { get { if (!layersCompressed.ContainsKey(layerID)) { uint[,] layer = new uint[Constants.ElementHeight * 8 * (byte)this.ZoomFactor, Constants.ElementWidth * 3 * (byte)this.ZoomFactor]; for (int x = 0; x < layer.GetLength(Width); x++) { for (int y = 0; y < layer.GetLength(Height); y++) { layer[y, x] = Constants.ColorTransparent; } } return(layer); } return(DecompressLayer(this.layersCompressed[layerID], this.ZoomFactor)); } set { if (value == null) { this.layersCompressed.Remove(layerID); } else { CompressedLayer compressedLayer = CompressLayer(value, this.ZoomFactor); if (compressedLayer == null) { this.layersCompressed.Remove(layerID); } else { this.layersCompressed[layerID] = compressedLayer; } } } }
private static CompressedLayer CompressLayer(uint[,] decompressedLayer, ZoomFactor zoomFactor) { int layerWidth = decompressedLayer.GetLength(Width); int layerHeight = decompressedLayer.GetLength(Height); int minx = layerWidth; int miny = layerHeight; int maxx = 0; int maxy = 0; for (int i = 0; i < layerHeight; i++) { for (int j = 0; j < layerWidth; j++) { if (decompressedLayer[i, j] != Constants.ColorTransparent) { if (minx > j) { minx = j; } if (maxx < j) { maxx = j; } if (miny > i) { miny = i; } if (maxy < i) { maxy = i; } } } } if (maxx == 0 && maxy == 0) { return(null); } maxx++; maxy++; List <uint> pixels = new List <uint>(); int trimmedHeight = maxy - miny; int trimmedWidth = maxx - minx; for (int i = 0; i < trimmedHeight; i++) { for (int j = 0; j < trimmedWidth; j++) { pixels.Add(decompressedLayer[i + miny, j + minx]); } } short x0 = (short)(minx - Constants.ElementWidth * (int)zoomFactor); short y0 = (short)(miny - Constants.ElementHeight * (int)zoomFactor); List <uint> colors = new List <uint>(); int colorposition = 0; while (colorposition < pixels.Count) { int length = 0; uint lastcolor = pixels[colorposition]; for (; colorposition < pixels.Count; colorposition++) { if (lastcolor != pixels[colorposition] || length > 256) { break; } length++; lastcolor = pixels[colorposition]; } if (length <= 1) { colors.Add(lastcolor); } else if (lastcolor == Constants.ColorTransparent) { colors.Add(Constants.ColorCompressedTransparent | (uint)(length - 2)); } else if (((lastcolor & Constants.ColorLogic) != 0) && lastcolor != (uint)Pixel.PixelProperty.BehindGlass) { uint color = lastcolor - Constants.ColorAsMin; color = color << 8; color = color | Constants.ColorCompressedSystemcolor; colors.Add(color | (uint)(length - 2)); } else { colors.Add(Constants.ColorCompressed | (uint)(length - 2)); colors.Add(lastcolor); } } CompressedLayer layer = new CompressedLayer(); layer.LayerData = colors.ToArray(); layer.X0 = x0; layer.Y0 = y0; layer.Height = (short)trimmedHeight; layer.Width = (short)trimmedWidth; return(layer); }
private static uint[,] DecompressLayer(CompressedLayer layer, ZoomFactor zoomFactor) { int arrayPosition = 0; List <uint> colors = new List <uint>(); for (int i = 0; i < layer.LayerData.Length; i++) { uint item = layer.LayerData[arrayPosition++]; int count = 0; if ((item & Constants.ColorAdditionalDataMask) == Constants.ColorCompressed) { count = (int)(item & Constants.ColorMaskCompressedCount) + 2; if ((item & Constants.ColorMaskCompressedTransparent) != 0) { // item is transparent for (int k = 0; k < count; k++) { colors.Add(Constants.ColorTransparent); } } else if ((item & Constants.ColorMaskCompressedSystemcolor) != 0) { // item is a system-color for (int k = 0; k < count; k++) { colors.Add(((item & Constants.ColorMaskCompressedSFB) >> 8) + Constants.ColorAsMin); } } else { // item is a color, may be a set of colors uint wdhlen = ((item & Constants.ColorMaskCompressedLength) >> 8) + 1; if (wdhlen > Constants.MaxRepeatedColorsLength) { throw new InvalidDataException("color repetition length out of range"); } List <uint> buffer = new List <uint>(); for (int j = 0; j < wdhlen; j++) { buffer.Add(layer.LayerData[arrayPosition++]); i++; } for (int j = 0; j < count; j++) { foreach (var b in buffer) { colors.Add(b); } } } } else { // not packed, single pixel count = 1; colors.Add(item); } } int height = Constants.ElementHeight * 8 * (int)zoomFactor; int width = Constants.ElementWidth * 3 * (int)zoomFactor; uint[,] layerElement = new uint[height, width]; int x0 = (int)(layer.X0 + Constants.ElementWidth * (int)zoomFactor); int y0 = (int)(layer.Y0 + Constants.ElementHeight * (int)zoomFactor); int _x0 = x0 + layer.Width; int _y0 = y0 + layer.Height; int position = 0; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (i >= y0 && i < _y0 && j >= x0 && j < _x0) { layerElement[i, j] = colors[position++]; } else { layerElement[i, j] = Constants.ColorTransparent; } } } return(layerElement); }
internal static Graphic Load(BinaryReader br) { if (br == null) { throw new ArgumentNullException("br"); } // Load Header Graphic graphic = new Graphic(); while (br.ReadByte() != Constants.HeaderTextTerminator) { } //Headertext, can be skipped byte[] readIdentification = br.ReadBytes(3); //Read indentification string if (readIdentification[0] != 71 || readIdentification[1] != 90 || readIdentification[2] != 71) //identification string "GZG" ASCII-format { throw new InvalidDataException("wrong identification string"); } byte zoomFactor = (byte)(br.ReadByte() - 48); //Zoomfactor is read as ASCII-character, then "converted" to a byte //ASCII 0 => 48, ASCII 1 => 49, etc... switch (zoomFactor) { case 1: case 2: case 4: graphic.ZoomFactor = (ZoomFactor)zoomFactor; break; default: throw new InvalidDataException("unknown zoom factor"); } ushort readMajorVersion = br.ReadUInt16(); byte[] readMinorVersion = br.ReadBytes(2); if (readMajorVersion != Constants.GraphicFileFormat || readMinorVersion[0] != 0x00) { throw new InvalidDataException("wrong version"); } switch (readMinorVersion[1]) { case (byte)GraphicVersion.Version0: case (byte)GraphicVersion.Version1: case (byte)GraphicVersion.Version2: graphic.Version = (GraphicVersion)readMinorVersion[1]; break; default: throw new InvalidDataException("wrong version"); } int p = br.ReadInt32(); //Properties graphic.Properties = new GraphicProperties() { RawData = (GraphicProperties.Properties)p }; //If either Smoke or Steam is set in the GraphicProperties if (graphic.Properties.HasParticles) { graphic.Properties.ParticleX = br.ReadInt32(); graphic.Properties.ParticleY = br.ReadInt32(); graphic.Properties.ParticleWidth = br.ReadInt32(); } //If Clock is set in the GraphicProperties if (graphic.Properties.RawData.HasFlag(GraphicProperties.Properties.Clock)) { if (graphic.Version == GraphicVersion.Version0) { throw new InvalidDataException("Clock is set, but invalid for the version of the graphic"); } br.ReadInt32(); //skipping unused data (for future use) graphic.Properties.ClockProperties = (ClockProperties)br.ReadInt32(); graphic.Properties.ClockX = br.ReadInt32(); graphic.Properties.ClockY = br.ReadInt32(); graphic.Properties.ClockZ = (LayerID)br.ReadInt32(); graphic.Properties.ClockWidth = br.ReadInt32(); graphic.Properties.ClockHeight = br.ReadInt32(); graphic.Properties.ClockColorHoursPointer = br.ReadUInt32(); graphic.Properties.ClockColorMinutesPointer = br.ReadUInt32(); br.ReadInt32(); //skipping unused data (for future use) } //If Cursor is set in the GraphicProperties if (graphic.Properties.RawData.HasFlag(GraphicProperties.Properties.Cursor)) { if (graphic.Version < GraphicVersion.Version2) { throw new InvalidDataException("Cursor is set, but invalid for the version of the graphic"); } graphic.Properties.CursorNormalDirection = (Direction)br.ReadInt32(); graphic.Properties.CursorReverseDirection = (Direction)br.ReadInt32(); } //If ColorInSchematicMode is set in the GraphicProperties if (graphic.Properties.RawData.HasFlag(GraphicProperties.Properties.ColorSchematicMode)) { if (graphic.Version < GraphicVersion.Version2) { throw new InvalidDataException("ColorSchematicMode is set, but invalid for the version of the graphic"); } graphic.Properties.ColorInSchematicMode = br.ReadUInt32(); br.ReadUInt32(); //skipping unused data } //If DrivingWay is set in the GraphicProperties if (graphic.Properties.RawData.HasFlag(GraphicProperties.Properties.DrivingWay)) { if (graphic.Version < GraphicVersion.Version2) { throw new InvalidDataException("DrivingWay is set, but invalid for the version of the graphic"); } graphic.DrivingWay = new List <DrivingWayElement>(); int count = br.ReadInt32(); for (int i = 0; i < count; i++) { graphic.DrivingWay.Add(DrivingWayElement.FromBytes(br.ReadBytes(12))); } } int layercount = br.ReadInt16(); br.ReadUInt16(); //skipping unknown data, see more in save-method char c; StringBuilder sb = new StringBuilder(); while ((c = br.ReadChar()) != Constants.UnicodeNull) { sb.Append(c); } graphic.InfoText = sb.ToString(); // Load Data bool backgroundLayerExists = false; for (int i = 0; i < layercount; i++) { LayerID id = (LayerID)br.ReadInt16(); CompressedLayer compressedLayer = _ReadLayerFromStream(br, graphic.ZoomFactor, graphic.Version); if (id == LayerID.Background0) { if (!backgroundLayerExists) { backgroundLayerExists = true; } else { id = LayerID.Background1; } } graphic.layersCompressed.Add(id, compressedLayer); } return(graphic); }