public void RenderColoredGray4(ColoredFrame frame) { // fall back if firmware doesn't support colored gray 4 if (!_supportsColoredGray4) { var rgb24Frame = ColorUtil.ColorizeFrame(DmdWidth, DmdHeight, FrameUtil.Join(DmdWidth, DmdHeight, frame.Planes), frame.Palette); RenderRgb24(rgb24Frame); return; } // copy palette var paletteChanged = false; for (var i = 0; i < 16; i++) { var color = frame.Palette[i]; var j = i * 3; paletteChanged = paletteChanged || (_frameBufferColoredGray4[j + 1] != color.R || _frameBufferColoredGray4[j + 2] != color.G || _frameBufferColoredGray4[j + 3] != color.B); _frameBufferColoredGray4[j + 1] = color.R; _frameBufferColoredGray4[j + 2] = color.G; _frameBufferColoredGray4[j + 3] = color.B; } // copy frame var frameChanged = FrameUtil.Copy(frame.Planes, _frameBufferColoredGray4, 49); // send frame buffer to device if (frameChanged || paletteChanged) { RenderRaw(_frameBufferColoredGray4); } }
public void RenderColoredGray2(ColoredFrame frame) { SetPalette(frame.Palette, frame.PaletteIndex); var joinedFrame = FrameUtil.Join(DmdWidth, DmdHeight, frame.Planes); // send frame buffer to device RenderGray4(FrameUtil.ConvertGrayToGray(joinedFrame, new byte[] { 0x0, 0x1, 0x4, 0xf })); }
public void RenderColoredGray2(byte[][] planes, Color[] palette) { SetPalette(palette); var frame = FrameUtil.Join(DmdWidth, DmdHeight, planes); // send frame buffer to device RenderGray4(FrameUtil.ConvertGrayToGray(frame, new byte[] { 0x0, 0x1, 0x4, 0xf })); }
private Tuple<byte[][], Color[]> TransformColoredGray4(int width, int height, byte[][] planes, Color[] palette, IFixedSizeDestination dest) { if (dest == null) { return new Tuple<byte[][], Color[]>(TransformationUtil.Flip(width, height, planes, FlipHorizontally, FlipVertically), palette); } if (width == dest.DmdWidth && height == dest.DmdHeight && !FlipHorizontally && !FlipVertically) { return new Tuple<byte[][], Color[]>(planes, palette); } var bmp = ImageUtil.ConvertFromGray4(width, height, FrameUtil.Join(width, height, planes), 0, 1, 1); var transformedBmp = TransformationUtil.Transform(bmp, dest.DmdWidth, dest.DmdHeight, Resize, FlipHorizontally, FlipVertically); var transformedFrame = ImageUtil.ConvertToGray4(transformedBmp); return new Tuple<byte[][], Color[]>(FrameUtil.Split(dest.DmdWidth, dest.DmdHeight, 4, transformedFrame), palette); }
public void Unserialize(byte[] data, ISocketAction action) { var start = 0; using (var memoryStream = new MemoryStream(data)) using (var reader = new BinaryReader(memoryStream)) { while (data[start++] != 0x0) { ; } var name = Encoding.ASCII.GetString(reader.ReadBytes(start - 1)); reader.BaseStream.Seek(1, SeekOrigin.Current); switch (name) { case "color": { action.OnColor(ColorUtil.FromInt(reader.ReadInt32())); break; } case "palette": { var len = reader.ReadInt32(); var palette = new Color[len]; for (var i = 0; i < len; i++) { palette[i] = ColorUtil.FromInt(reader.ReadInt32()); } action.OnPalette(palette); break; } case "clearColor": { action.OnClearColor(); break; } case "clearPalette": { action.OnClearPalette(); break; } case "dimensions": { Width = reader.ReadInt32(); Height = reader.ReadInt32(); action.OnDimensions(Width, Height); break; } case "gameName": { char c; var gameName = ""; do { c = reader.ReadChar(); gameName += c; } while (c != 0x0); action.OnGameName(gameName); break; } case "rgb24": { action.OnRgb24(reader.ReadUInt32(), reader.ReadBytes(data.Length - (int)reader.BaseStream.Position)); break; } case "coloredGray4": { var timestamp = reader.ReadUInt32(); var numColors = reader.ReadInt32(); var palette = new Color[numColors]; for (var i = 0; i < numColors; i++) { palette[i] = ColorUtil.FromInt(reader.ReadInt32()); } var planes = new byte[4][]; var planeSize = (data.Length - (int)reader.BaseStream.Position) / 4; for (var i = 0; i < 4; i++) { planes[i] = reader.ReadBytes(planeSize); } action.OnColoredGray4(timestamp, palette, planes); break; } case "coloredGray2": { var timestamp = reader.ReadUInt32(); var numColors = reader.ReadInt32(); var palette = new Color[numColors]; for (var i = 0; i < numColors; i++) { palette[i] = ColorUtil.FromInt(reader.ReadInt32()); } var planes = new byte[2][]; var planeSize = (data.Length - (int)reader.BaseStream.Position) / 2; for (var i = 0; i < 2; i++) { planes[i] = reader.ReadBytes(planeSize); } action.OnColoredGray2(timestamp, palette, planes); break; } case "gray4Planes": { var timestamp = reader.ReadUInt32(); var planes = new byte[4][]; var planeSize = (data.Length - (int)reader.BaseStream.Position) / 4; for (var i = 0; i < 4; i++) { planes[i] = reader.ReadBytes(planeSize); } action.OnGray4(timestamp, FrameUtil.Join(Width, Height, planes)); break; } case "gray2Planes": { var timestamp = reader.ReadUInt32(); var planes = new byte[2][]; var planeSize = (data.Length - (int)reader.BaseStream.Position) / 2; for (var i = 0; i < 2; i++) { planes[i] = reader.ReadBytes(planeSize); } action.OnGray2(timestamp, FrameUtil.Join(Width, Height, planes)); break; } } } }
public void RenderColoredGray4(ColoredFrame frame) { SetPalette(frame.Palette); RenderGray4(FrameUtil.Join(DmdWidth, DmdHeight, frame.Planes)); }
public void RenderColoredGray2(byte[][] planes, Color[] palette) { SetPalette(palette); RenderGray2(FrameUtil.Join(DmdWidth, DmdHeight, planes)); }
/// <summary> /// Connects a source with a destination and defines in which mode data is /// sent and received. /// </summary> /// <remarks> /// Note that render bitlength is enforced, i.e. even if the destination /// supports the "from" bitlength, it will be converted to the given "to" /// bitlength. /// </remarks> /// <param name="source">Source to subscribe to</param> /// <param name="dest">Destination to send the data to</param> /// <param name="from">Data format to read from source (incompatible source will throw exception)</param> /// <param name="to">Data forma to send to destination (incompatible destination will throw exception)</param> private void Connect(ISource source, IDestination dest, FrameFormat from, FrameFormat to) { var destFixedSize = dest as IFixedSizeDestination; var destGray2 = dest as IGray2Destination; var destGray4 = dest as IGray4Destination; var destRgb24 = dest as IRgb24Destination; var destBitmap = dest as IBitmapDestination; var destColoredGray2 = dest as IColoredGray2Destination; var destColoredGray4 = dest as IColoredGray4Destination; var scheduler = Scheduler.Default; Logger.Info("Connecting {0} to {1} ({2} => {3})", source.Name, dest.Name, from.ToString(), to.ToString()); switch (from) { // source is gray2: case FrameFormat.Gray2: var sourceGray2 = source as IGray2Source; switch (to) { // gray2 -> gray2 case FrameFormat.Gray2: AssertCompatibility(source, sourceGray2, dest, destGray2, from, to); _activeSources.Add(sourceGray2.GetGray2Frames() .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray2.RenderGray2)); break; // gray2 -> gray4 case FrameFormat.Gray4: throw new NotImplementedException("Cannot convert from gray2 to gray4 (every gray4 destination should be able to do gray2 as well)."); // gray2 -> rgb24 case FrameFormat.Rgb24: AssertCompatibility(source, sourceGray2, dest, destRgb24, from, to); _activeSources.Add(sourceGray2.GetGray2Frames() .Select(frame => ColorizeGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame)) .Select(frame => TransformRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destRgb24.RenderRgb24)); break; // gray2 -> bitmap case FrameFormat.Bitmap: AssertCompatibility(source, sourceGray2, dest, destBitmap, from, to); _activeSources.Add(sourceGray2.GetGray2Frames() .Select(frame => ImageUtil.ConvertFromRgb24( source.Dimensions.Value.Width, source.Dimensions.Value.Height, ColorizeGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame) )) .Select(bmp => Transform(bmp, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destBitmap.RenderBitmap)); break; // gray2 -> colored gray2 case FrameFormat.ColoredGray2: throw new NotImplementedException("Cannot convert from gray2 to colored gray2 (doesn't make any sense, colored gray2 can also do gray2)."); // gray2 -> colored gray4 case FrameFormat.ColoredGray4: throw new NotImplementedException("Cannot convert from gray2 to colored gray2 (a colored gray4 destination should also be able to do gray2 directly)."); default: throw new ArgumentOutOfRangeException(nameof(to), to, null); } break; // source is gray4: case FrameFormat.Gray4: var sourceGray4 = source as IGray4Source; switch (to) { // gray4 -> gray2 case FrameFormat.Gray2: AssertCompatibility(source, sourceGray4, dest, destGray2, from, to); _activeSources.Add(sourceGray4.GetGray4Frames() .Select(frame => FrameUtil.ConvertGrayToGray(frame, new byte[] { 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3 })) .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray2.RenderGray2)); break; // gray4 -> gray4 case FrameFormat.Gray4: AssertCompatibility(source, sourceGray4, dest, destGray4, from, to); _activeSources.Add(sourceGray4.GetGray4Frames() .Select(frame => TransformGray4(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray4.RenderGray4)); break; // gray4 -> rgb24 case FrameFormat.Rgb24: AssertCompatibility(source, sourceGray4, dest, destRgb24, from, to); _activeSources.Add(sourceGray4.GetGray4Frames() .Select(frame => ColorizeGray4(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame)) .Select(frame => TransformRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destRgb24.RenderRgb24)); break; // gray4 -> bitmap case FrameFormat.Bitmap: AssertCompatibility(source, sourceGray4, dest, destBitmap, from, to); _activeSources.Add(sourceGray4.GetGray4Frames() .Select(frame => ImageUtil.ConvertFromRgb24( source.Dimensions.Value.Width, source.Dimensions.Value.Height, ColorizeGray4(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame) )) .Select(bmp => Transform(bmp, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destBitmap.RenderBitmap)); break; // gray4 -> colored gray2 case FrameFormat.ColoredGray2: throw new NotImplementedException("Cannot convert from gray4 to colored gray2 (doesn't make any sense, colored gray2 can also do gray4)."); // gray4 -> colored gray4 case FrameFormat.ColoredGray4: throw new NotImplementedException("Cannot convert from gray2 to colored gray2 (doesn't make any sense, colored gray4 can also do gray4)."); default: throw new ArgumentOutOfRangeException(nameof(to), to, null); } break; // source is rgb24: case FrameFormat.Rgb24: var sourceRgb24 = source as IRgb24Source; switch (to) { // rgb24 -> gray2 case FrameFormat.Gray2: AssertCompatibility(source, sourceRgb24, dest, destGray2, from, to); _activeSources.Add(sourceRgb24.GetRgb24Frames() .Select(frame => ImageUtil.ConvertToGray(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, 4)) .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray2.RenderGray2)); break; // rgb24 -> gray4 case FrameFormat.Gray4: AssertCompatibility(source, sourceRgb24, dest, destGray4, from, to); _activeSources.Add(sourceRgb24.GetRgb24Frames() .Select(frame => ImageUtil.ConvertToGray(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, 16)) .Select(frame => TransformGray4(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray4.RenderGray4)); break; // rgb24 -> rgb24 case FrameFormat.Rgb24: AssertCompatibility(source, sourceRgb24, dest, destRgb24, from, to); _activeSources.Add(sourceRgb24.GetRgb24Frames() .Select(frame => TransformRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destRgb24.RenderRgb24)); break; // rgb24 -> bitmap case FrameFormat.Bitmap: AssertCompatibility(source, sourceRgb24, dest, destBitmap, from, to); _activeSources.Add(sourceRgb24.GetRgb24Frames() .Select(frame => ImageUtil.ConvertFromRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame)) .Select(bmp => Transform(bmp, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destBitmap.RenderBitmap)); break; // rgb24 -> colored gray2 case FrameFormat.ColoredGray2: throw new NotImplementedException("Cannot convert from rgb24 to colored gray2 (colored gray2 only has 4 colors per frame)."); // rgb24 -> colored gray4 case FrameFormat.ColoredGray4: throw new NotImplementedException("Cannot convert from rgb24 to colored gray2 (colored gray4 only has 16 colors per frame)."); default: throw new ArgumentOutOfRangeException(nameof(to), to, null); } break; // source is bitmap: case FrameFormat.Bitmap: var sourceBitmap = source as IBitmapSource; switch (to) { // bitmap -> gray2 case FrameFormat.Gray2: AssertCompatibility(source, sourceBitmap, dest, destGray2, from, to); _activeSources.Add(sourceBitmap.GetBitmapFrames() .Select(bmp => ImageUtil.ConvertToGray2(bmp)) .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray2.RenderGray2)); break; // bitmap -> gray4 case FrameFormat.Gray4: AssertCompatibility(source, sourceBitmap, dest, destGray4, from, to); _activeSources.Add(sourceBitmap.GetBitmapFrames() .Select(bmp => ImageUtil.ConvertToGray4(bmp)) .Select(frame => TransformGray4(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray4.RenderGray4)); break; // bitmap -> rgb24 case FrameFormat.Rgb24: AssertCompatibility(source, sourceBitmap, dest, destRgb24, from, to); _activeSources.Add(sourceBitmap.GetBitmapFrames() .Select(bmp => ImageUtil.ConvertToRgb24(bmp)) .Select(frame => TransformRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destRgb24.RenderRgb24)); break; // bitmap -> bitmap case FrameFormat.Bitmap: AssertCompatibility(Source, sourceBitmap, dest, destBitmap, from, to); _activeSources.Add(sourceBitmap.GetBitmapFrames() .Select(bmp => Transform(bmp, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destBitmap.RenderBitmap)); break; // bitmap -> colored gray2 case FrameFormat.ColoredGray2: throw new NotImplementedException("Cannot convert from bitmap to colored gray2 (colored gray2 only has 4 colors per frame)."); // bitmap -> colored gray4 case FrameFormat.ColoredGray4: throw new NotImplementedException("Cannot convert from bitmap to colored gray2 (colored gray4 only has 16 colors per frame)."); default: throw new ArgumentOutOfRangeException(nameof(to), to, null); } break; // source is colored gray2: case FrameFormat.ColoredGray2: var sourceColoredGray2 = source as IColoredGray2Source; switch (to) { // colored gray2 -> gray2 case FrameFormat.Gray2: AssertCompatibility(source, sourceColoredGray2, dest, destGray2, from, to); _activeSources.Add(sourceColoredGray2.GetColoredGray2Frames() .Select(x => FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1)) .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray2.RenderGray2)); break; // colored gray2 -> gray4 case FrameFormat.Gray4: throw new NotImplementedException("Cannot convert from colored gray2 to gray4 (it's not like we can extract luminosity from the colors...)"); // colored gray2 -> rgb24 case FrameFormat.Rgb24: AssertCompatibility(source, sourceColoredGray2, dest, destRgb24, from, to); _activeSources.Add(sourceColoredGray2.GetColoredGray2Frames() .Select(x => ColorUtil.ColorizeFrame( source.Dimensions.Value.Width, source.Dimensions.Value.Height, FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1), x.Item2) ) .Select(frame => TransformRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destRgb24.RenderRgb24)); break; // colored gray2 -> bitmap case FrameFormat.Bitmap: AssertCompatibility(source, sourceColoredGray2, dest, destBitmap, from, to); _activeSources.Add(sourceColoredGray2.GetColoredGray2Frames() .Select(x => ColorUtil.ColorizeFrame( source.Dimensions.Value.Width, source.Dimensions.Value.Height, FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1), x.Item2) ) .Select(frame => ImageUtil.ConvertFromRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame)) .Select(bmp => Transform(bmp, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destBitmap.RenderBitmap)); break; // colored gray2 -> colored gray2 case FrameFormat.ColoredGray2: AssertCompatibility(source, sourceColoredGray2, dest, destColoredGray2, from, to); _activeSources.Add(sourceColoredGray2.GetColoredGray2Frames() .Select(x => TransformColoredGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1, x.Item2, destFixedSize)) .ObserveOn(scheduler) .Subscribe(x => destColoredGray2.RenderColoredGray2(x.Item1, x.Item2))); break; // colored gray2 -> colored gray4 case FrameFormat.ColoredGray4: throw new NotImplementedException("Cannot convert from colored gray2 to colored gray4 (if a destination can do colored gray4 it should be able to do colored gray2 directly)."); default: throw new ArgumentOutOfRangeException(nameof(to), to, null); } break; // source is colored gray4: case FrameFormat.ColoredGray4: var sourceColoredGray4 = source as IColoredGray4Source; switch (to) { // colored gray4 -> gray2 case FrameFormat.Gray2: AssertCompatibility(source, sourceColoredGray4, dest, destGray2, from, to); _activeSources.Add(sourceColoredGray4.GetColoredGray4Frames() .Select(x => FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1)) .Select(frame => FrameUtil.ConvertGrayToGray(frame, new byte[] { 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3 })) .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray2.RenderGray2)); break; // colored gray4 -> gray4 case FrameFormat.Gray4: AssertCompatibility(source, sourceColoredGray4, dest, destGray4, from, to); _activeSources.Add(sourceColoredGray4.GetColoredGray4Frames() .Select(x => FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1)) .Select(frame => TransformGray2(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destGray4.RenderGray4)); break; // colored gray4 -> rgb24 case FrameFormat.Rgb24: AssertCompatibility(source, sourceColoredGray4, dest, destRgb24, from, to); _activeSources.Add(sourceColoredGray4.GetColoredGray4Frames() .Select(x => ColorUtil.ColorizeFrame( source.Dimensions.Value.Width, source.Dimensions.Value.Height, FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1), x.Item2) ) .Select(frame => TransformRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destRgb24.RenderRgb24)); break; // colored gray4 -> bitmap case FrameFormat.Bitmap: AssertCompatibility(source, sourceColoredGray4, dest, destBitmap, from, to); _activeSources.Add(sourceColoredGray4.GetColoredGray4Frames() .Select(x => ColorUtil.ColorizeFrame( source.Dimensions.Value.Width, source.Dimensions.Value.Height, FrameUtil.Join(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1), x.Item2) ) .Select(frame => ImageUtil.ConvertFromRgb24(source.Dimensions.Value.Width, source.Dimensions.Value.Height, frame)) .Select(bmp => Transform(bmp, destFixedSize)) .ObserveOn(scheduler) .Subscribe(destBitmap.RenderBitmap)); break; // colored gray4 -> colored gray2 case FrameFormat.ColoredGray2: throw new NotImplementedException("Cannot convert from colored gray4 to colored gray2 (use rgb24 instead of down-coloring)."); // colored gray4 -> colored gray4 case FrameFormat.ColoredGray4: AssertCompatibility(source, sourceColoredGray4, dest, destColoredGray4, from, to); _activeSources.Add(sourceColoredGray4.GetColoredGray4Frames() .Select(x => TransformColoredGray4(source.Dimensions.Value.Width, source.Dimensions.Value.Height, x.Item1, x.Item2, destFixedSize)) .ObserveOn(scheduler) .Subscribe(x => destColoredGray4.RenderColoredGray4(x.Item1, x.Item2))); break; default: throw new ArgumentOutOfRangeException(nameof(to), to, null); } break; default: throw new ArgumentOutOfRangeException(); } }
public byte[] GetFrame(int width, int height) { return(FrameUtil.Join(width, height, Planes)); }