//#define COSMOSDEBUG using Cosmos.HAL.Drivers; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Cosmos.System.Graphics; namespace Cosmos.System { public class VBEScreen : Canvas { /// /// Driver for Setting vbe modes and ploting/getting pixels /// private VBEDriver VBEDriver; public VBEScreen() : base() { Global.mDebugger.SendInternal($"Creating new VBEScreen() with default mode {defaultGraphicMode}"); // We don't need to add a Control for defaultGraphicMode we assume it to be always a valid mode VBEDriver = new VBEDriver((ushort)defaultGraphicMode.Columns, (ushort)defaultGraphicMode.Rows, (ushort)defaultGraphicMode.ColorDepth); } public VBEScreen(Mode mode) : base(mode) { //Global.mDebugger.SendInternal($"Creating new VBEScreen() with mode {mode}"); ThrowIfModeIsNotValid(mode); VBEDriver = new VBEDriver((ushort)mode.Columns, (ushort)mode.Rows, (ushort)mode.ColorDepth); } public override Mode Mode { get { return mode; } set { mode = value; SetMode(mode); } } #region Display /// /// All the available screen modes VBE supports, I would like to query the hardware and obtain from it the list but I have /// not yet find how to do it! For now I hardcode the most used VESA modes, VBE seems to support until HDTV resolution /// without problems that is well... excellent :-) /// public override List getAvailableModes() { return new List { new Mode(320, 240, ColorDepth.ColorDepth32), new Mode(640, 480, ColorDepth.ColorDepth32), new Mode(800, 600, ColorDepth.ColorDepth32), new Mode(1024, 768, ColorDepth.ColorDepth32), /* The so called HD-Ready resolution */ new Mode(1280, 720, ColorDepth.ColorDepth32), new Mode(1280, 1024, ColorDepth.ColorDepth32), /* A lot of HD-Ready screen uses this instead of 1280x720 */ new Mode(1366, 768, ColorDepth.ColorDepth32), new Mode(1680, 1050, ColorDepth.ColorDepth32), /* HDTV resolution */ new Mode(1920, 1080, ColorDepth.ColorDepth32), /* HDTV resolution (16:10 AR) */ new Mode(1920, 1200, ColorDepth.ColorDepth32), }; } protected override Mode getDefaultGraphicMode() => new Mode(1024, 768, ColorDepth.ColorDepth32); /// /// Use this to setup the screen, this will disable the console. /// /// The desired Mode resolution private void SetMode(Mode mode) { ThrowIfModeIsNotValid(mode); ushort xres = (ushort)Mode.Columns; ushort yres = (ushort)Mode.Rows; ushort bpp = (ushort)Mode.ColorDepth; //set the screen VBEDriver.VBESet(xres, yres, bpp); } #endregion #region Drawing public override void Clear(Color color) { Global.mDebugger.SendInternal($"Clearing the Screen with Color {color}"); //if (color == null) // throw new ArgumentNullException(nameof(color)); /* * TODO this version of Clear() works only when mode.ColorDepth == ColorDepth.ColorDepth32 * in the other cases you should before convert color and then call the opportune ClearVRAM() overload * (the one that takes ushort for ColorDepth.ColorDepth16 and the one that takes byte for ColorDepth.ColorDepth8) * For ColorDepth.ColorDepth24 you should mask the Alpha byte. */ VBEDriver.ClearVRAM((uint)color.ToArgb()); } /* * As DrawPoint() is the basic block of DrawLine() and DrawRect() and in theory of all the future other methods that will * be implemented is better to not check the validity of the arguments here or it will repeat the check for any point * to be drawn slowing down all. */ public override void DrawPoint(Pen pen, int x, int y) { Color color = pen.Color; uint pitch; uint stride; uint offset; uint ColorDepthInBytes = (uint)mode.ColorDepth / 8; /* * For now we can Draw only if the ColorDepth is 32 bit, we will throw otherwise. * * How to support other ColorDepth? The offset calculation should be the same (and so could be done out of the switch) * adding support ColorDepth.ColorDepth24 is easier as you need can use the version of SetVRAM() that take a byte * and call it 3 time for the B, G and R component (the Color class has properties to do this!), the problem is * for ColorDepth.ColorDepth16 and ColorDepth.ColorDepth8 than need a conversion from color (an ARGB32 color) to the RGB16 and RGB8 * how to do this conversion faster maybe using pre-computed tables? What happens if the color cannot be converted? We will throw? */ switch (mode.ColorDepth) { case ColorDepth.ColorDepth32: Global.mDebugger.SendInternal("Computing offset..."); pitch = (uint)mode.Columns * ColorDepthInBytes; stride = ColorDepthInBytes; //offset = ((uint)x * pitch) + ((uint)y * stride); offset = ((uint)x * stride) + ((uint)y * pitch); Global.mDebugger.SendInternal($"Drawing Point of color {color} at offset {offset}"); VBEDriver.SetVRAM(offset, (uint)color.ToArgb()); Global.mDebugger.SendInternal("Point drawn"); break; default: String errorMsg = "DrawPoint() with ColorDepth " + (int)Mode.ColorDepth + " not yet supported"; throw new NotImplementedException(errorMsg); } } public override void DrawPoint(Pen pen, float x, float y) { throw new NotImplementedException(); } #endregion #region Reading // TODO add to Canvas GetPointColor() #endregion } }