//this is full of bugs probably, related to state from old rendering sessions being all messed up. its only barely good enough to work at all using System; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using sd = System.Drawing; using System.Drawing.Imaging; using OpenTK; using OpenTK.Graphics.OpenGL; namespace BizHawk.Bizware.BizwareGL.Drivers.GdiPlus { public class GDIPlusGuiRenderer : IGuiRenderer { public GDIPlusGuiRenderer(IGL_GdiPlus gl) { Owner = gl; Gdi = gl as IGL_GdiPlus; } OpenTK.Graphics.Color4[] CornerColors = new OpenTK.Graphics.Color4[4] { new OpenTK.Graphics.Color4(1.0f,1.0f,1.0f,1.0f),new OpenTK.Graphics.Color4(1.0f,1.0f,1.0f,1.0f),new OpenTK.Graphics.Color4(1.0f,1.0f,1.0f,1.0f),new OpenTK.Graphics.Color4(1.0f,1.0f,1.0f,1.0f) }; public void SetCornerColor(int which, OpenTK.Graphics.Color4 color) { CornerColors[which] = color; } public void SetCornerColors(OpenTK.Graphics.Color4[] colors) { Flush(); //dont really need to flush with current implementation. we might as well roll modulate color into it too. if (colors.Length != 4) throw new ArgumentException("array must be size 4", "colors"); for (int i = 0; i < 4; i++) CornerColors[i] = colors[i]; } public void Dispose() { if (CurrentImageAttributes != null) CurrentImageAttributes.Dispose(); } public void SetPipeline(Pipeline pipeline) { } public void SetDefaultPipeline() { } public void SetModulateColorWhite() { SetModulateColor(sd.Color.White); } ImageAttributes CurrentImageAttributes; public void SetModulateColor(sd.Color color) { //white is really no color at all if (color.ToArgb() == sd.Color.White.ToArgb()) { CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap); return; } float r = color.R / 255.0f; float g = color.G / 255.0f; float b = color.B / 255.0f; float a = color.A / 255.0f; float[][] colorMatrixElements = { new float[] {r, 0, 0, 0, 0}, new float[] {0, g, 0, 0, 0}, new float[] {0, 0, b, 0, 0}, new float[] {0, 0, 0, a, 0}, new float[] {0, 0, 0, 0, 1}}; ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements); CurrentImageAttributes.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default, ColorAdjustType.Bitmap); } sd.Color CurrentModulateColor = sd.Color.White; IBlendState CurrentBlendState; public void SetBlendState(IBlendState rsBlend) { CurrentBlendState = rsBlend; } MatrixStack _Projection, _Modelview; public MatrixStack Projection { get { return _Projection; } set { _Projection = value; _Projection.IsDirty = true; } } public MatrixStack Modelview { get { return _Modelview; } set { _Modelview = value; _Modelview.IsDirty = true; } } public void Begin(sd.Size size) { Begin(size.Width, size.Height); } public void Begin(int width, int height) { Begin(); CurrentBlendState = Gdi.BlendNormal; Projection = Owner.CreateGuiProjectionMatrix(width, height); Modelview = Owner.CreateGuiViewMatrix(width, height); } public void Begin() { //uhhmmm I want to throw an exception if its already active, but its annoying. IsActive = true; CurrentImageAttributes = new ImageAttributes(); } public void Flush() { //no batching, nothing to do here yet } public void End() { if (!IsActive) throw new InvalidOperationException("GuiRenderer is not active!"); IsActive = false; if (CurrentImageAttributes != null) { CurrentImageAttributes.Dispose(); CurrentImageAttributes = null; } } public void RectFill(float x, float y, float w, float h) { } public void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1) { var tw = tex.Opaque as IGL_GdiPlus.TextureWrapper; var g = Gdi.GetCurrentGraphics(); PrepDraw(g, tex); SetupMatrix(g); float x0 = u0 * tex.Width; float y0 = v0 * tex.Height; float x1 = u1 * tex.Width; float y1 = v1 * tex.Height; sd.PointF[] destPoints = new sd.PointF[] { new sd.PointF(x,y), new sd.PointF(x+w,y), new sd.PointF(x,y+h), }; g.DrawImage(tw.SDBitmap, destPoints, new sd.RectangleF(x0, y0, x1 - x0, y1 - y0), sd.GraphicsUnit.Pixel, CurrentImageAttributes); g.Transform = new sd.Drawing2D.Matrix(); //.Reset() doesnt work ? ? } public void Draw(Art art) { DrawInternal(art, 0, 0, art.Width, art.Height, false, false); } public void Draw(Art art, float x, float y) { DrawInternal(art, x, y, art.Width, art.Height, false, false); } public void Draw(Art art, float x, float y, float width, float height) { DrawInternal(art, x, y, width, height, false, false); } public void Draw(Art art, Vector2 pos) { DrawInternal(art, pos.X, pos.Y, art.Width, art.Height, false, false); } public void Draw(Texture2d tex) { DrawInternal(tex, 0, 0, tex.Width, tex.Height); } public void Draw(Texture2d tex, float x, float y) { DrawInternal(tex, x, y, tex.Width, tex.Height); } public void DrawFlipped(Art art, bool xflip, bool yflip) { DrawInternal(art, 0, 0, art.Width, art.Height, xflip, yflip); } public void Draw(Texture2d art, float x, float y, float width, float height) { DrawInternal(art, x, y, width, height); } void PrepDraw(sd.Graphics g, Texture2d tex) { var tw = tex.Opaque as IGL_GdiPlus.TextureWrapper; //TODO - we can support bicubic for the final presentation.. if ((int)tw.MagFilter != (int)tw.MinFilter) throw new InvalidOperationException("tw.MagFilter != tw.MinFilter"); if (tw.MagFilter == TextureMagFilter.Linear) g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; if (tw.MagFilter == TextureMagFilter.Nearest) g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; //--------- if (CurrentBlendState == Gdi.BlendNormal) { g.CompositingMode = sd.Drawing2D.CompositingMode.SourceOver; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.Default; //? //CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap); } else //if(CurrentBlendState == Gdi.BlendNoneCopy) //if(CurrentBlendState == Gdi.BlendNoneOpaque) { g.CompositingMode = sd.Drawing2D.CompositingMode.SourceCopy; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed; //WARNING : DO NOT USE COLOR MATRIX TO WIPE THE ALPHA //ITS SOOOOOOOOOOOOOOOOOOOOOOOOOOOO SLOW //instead, we added kind of hacky support for 24bpp images } } private void SetupMatrix(sd.Graphics g) { //projection is always identity, so who cares i guess //Matrix4 mat = Projection.Top * Modelview.Top; Matrix4 mat = Modelview.Top; g.Transform = new sd.Drawing2D.Matrix(mat.M11, mat.M12, mat.M21, mat.M22, mat.M41, mat.M42); } unsafe void DrawInternal(Texture2d tex, float x, float y, float w, float h) { var g = Gdi.GetCurrentGraphics(); PrepDraw(g, tex); SetupMatrix(g); sd.PointF[] destPoints = new sd.PointF[] { new sd.PointF(x,y), new sd.PointF(x+w,y), new sd.PointF(x,y+h), }; var tw = tex.Opaque as IGL_GdiPlus.TextureWrapper; g.PixelOffsetMode = sd.Drawing2D.PixelOffsetMode.Half; g.DrawImage(tw.SDBitmap, destPoints, new sd.RectangleF(0, 0, tex.Width, tex.Height), sd.GraphicsUnit.Pixel, CurrentImageAttributes); g.Transform = new sd.Drawing2D.Matrix(); //.Reset() doesnt work ? ? } unsafe void DrawInternal(Art art, float x, float y, float w, float h, bool fx, bool fy) { } public bool IsActive { get; private set; } public IGL Owner { get; private set; } public IGL_GdiPlus Gdi; } }