BizHawk/Bizware/BizHawk.Bizware.BizwareGL.G.../IGL_GdiPlus.cs

451 lines
11 KiB
C#

using System;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using swf = System.Windows.Forms;
using sd = System.Drawing;
using sdi = System.Drawing.Imaging;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using BizHawk.Bizware.BizwareGL;
//TODO - maybe a layer to cache Graphics parameters (notably, filtering) ?
namespace BizHawk.Bizware.BizwareGL.Drivers.GdiPlus
{
public class IGL_GdiPlus : IGL
{
//rendering state
RenderTarget _CurrRenderTarget;
public IGL_GdiPlus()
{
MyBufferedGraphicsContext = new BufferedGraphicsContext();
}
void IDisposable.Dispose()
{
}
public void Clear(OpenTK.Graphics.OpenGL.ClearBufferMask mask)
{
var g = GetCurrentGraphics();
if((mask & ClearBufferMask.ColorBufferBit) != 0)
{
g.Clear(_currentClearColor);
}
}
public string API { get { return "GDIPLUS"; } }
public IBlendState CreateBlendState(BlendingFactorSrc colorSource, BlendEquationMode colorEquation, BlendingFactorDest colorDest,
BlendingFactorSrc alphaSource, BlendEquationMode alphaEquation, BlendingFactorDest alphaDest)
{
return null;
}
private sd.Color _currentClearColor = Color.Transparent;
public void SetClearColor(sd.Color color)
{
_currentClearColor = color;
}
public unsafe void BindArrayData(void* pData)
{
}
public void FreeTexture(Texture2d tex)
{
var tw = tex.Opaque as TextureWrapper;
tw.Dispose();
}
public Shader CreateFragmentShader(bool cg, string source, string entry, bool required)
{
return null;
}
public Shader CreateVertexShader(bool cg, string source, string entry, bool required)
{
return null;
}
public void FreeShader(IntPtr shader) { }
public void SetBlendState(IBlendState rsBlend)
{
//TODO for real
}
class MyBlendState : IBlendState { }
static MyBlendState _rsBlendNoneVerbatim = new MyBlendState(), _rsBlendNoneOpaque = new MyBlendState(), _rsBlendNormal = new MyBlendState();
public IBlendState BlendNoneCopy { get { return _rsBlendNoneVerbatim; } }
public IBlendState BlendNoneOpaque { get { return _rsBlendNoneOpaque; } }
public IBlendState BlendNormal { get { return _rsBlendNormal; } }
public Pipeline CreatePipeline(VertexLayout vertexLayout, Shader vertexShader, Shader fragmentShader, bool required, string memo)
{
return null;
}
public void FreePipeline(Pipeline pipeline) {}
public VertexLayout CreateVertexLayout() { return new VertexLayout(this, new IntPtr(0)); }
public void SetTextureWrapMode(Texture2d tex, bool clamp)
{
}
public void DrawArrays(PrimitiveType mode, int first, int count)
{
}
public void BindPipeline(Pipeline pipeline)
{
}
public void Internal_FreeShader(Shader shader)
{
}
public void SetPipelineUniform(PipelineUniform uniform, bool value)
{
}
public unsafe void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4 mat, bool transpose)
{
}
public unsafe void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4 mat, bool transpose)
{
}
public void SetPipelineUniform(PipelineUniform uniform, Vector4 value)
{
}
public void SetPipelineUniform(PipelineUniform uniform, Vector2 value)
{
}
public void SetPipelineUniform(PipelineUniform uniform, float value)
{
}
public unsafe void SetPipelineUniform(PipelineUniform uniform, Vector4[] values)
{
}
public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex)
{
}
public void TexParameter2d(Texture2d tex, TextureParameterName pname, int param)
{
var tw = tex.Opaque as TextureWrapper;
if (pname == TextureParameterName.TextureMinFilter)
tw.MinFilter = (TextureMinFilter)param;
if (pname == TextureParameterName.TextureMagFilter)
tw.MagFilter = (TextureMagFilter)param;
}
public Texture2d LoadTexture(sd.Bitmap bitmap)
{
var sdbmp = (sd.Bitmap)bitmap.Clone();
TextureWrapper tw = new TextureWrapper();
tw.SDBitmap = sdbmp;
return new Texture2d(this, tw, bitmap.Width, bitmap.Height);
}
public Texture2d LoadTexture(Stream stream)
{
using (var bmp = new BitmapBuffer(stream, new BitmapLoadOptions()))
return (this as IGL).LoadTexture(bmp);
}
public Texture2d CreateTexture(int width, int height)
{
return null;
}
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
{
//TODO - need to rip the texturedata. we had code for that somewhere...
return null;
}
public void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
{
var tw = tex.Opaque as TextureWrapper;
bmp.ToSysdrawingBitmap(tw.SDBitmap);
}
public Texture2d LoadTexture(BitmapBuffer bmp)
{
//definitely needed (by TextureFrugalizer at least)
var sdbmp = bmp.ToSysdrawingBitmap();
var tw = new TextureWrapper();
tw.SDBitmap = sdbmp;
return new Texture2d(this, tw, bmp.Width, bmp.Height);
}
public unsafe BitmapBuffer ResolveTexture2d(Texture2d tex)
{
var tw = tex.Opaque as TextureWrapper;
var blow = new BitmapLoadOptions()
{
AllowWrap = false //must be an independent resource
};
var bb = new BitmapBuffer(tw.SDBitmap,blow);
return bb;
}
public Texture2d LoadTexture(string path)
{
//todo
//using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
// return (this as IGL).LoadTexture(fs);
return null;
}
public Matrix4 CreateGuiProjectionMatrix(int w, int h)
{
return CreateGuiProjectionMatrix(new sd.Size(w, h));
}
public Matrix4 CreateGuiViewMatrix(int w, int h, bool autoflip)
{
return CreateGuiViewMatrix(new sd.Size(w, h), autoflip);
}
public Matrix4 CreateGuiProjectionMatrix(sd.Size dims)
{
//see CreateGuiViewMatrix for more
return Matrix4.Identity;
}
public Matrix4 CreateGuiViewMatrix(sd.Size dims, bool autoflip)
{
//on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here
//furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it
//this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable
//if (autoflip && _CurrRenderTarget != null)
//{
// Matrix4 ret = Matrix4.Identity;
// ret.M22 = -1;
// ret.M42 = dims.Height;
// return ret;
//}
//else
return Matrix4.Identity;
}
public void SetViewport(int x, int y, int width, int height)
{
}
public void SetViewport(int width, int height)
{
}
public void SetViewport(sd.Size size)
{
SetViewport(size.Width, size.Height);
}
public void SetViewport(swf.Control control)
{
}
public void BeginControl(GLControlWrapper_GdiPlus control)
{
CurrentControl = control;
}
public void EndControl(GLControlWrapper_GdiPlus control)
{
CurrentControl = null;
}
public void SwapControl(GLControlWrapper_GdiPlus control)
{
}
public class RenderTargetWrapper
{
public RenderTargetWrapper(IGL_GdiPlus gdi)
{
Gdi = gdi;
}
public void Dispose()
{
}
IGL_GdiPlus Gdi;
/// <summary>
/// the control associated with this render target (if any)
/// </summary>
public GLControlWrapper_GdiPlus Control;
/// <summary>
/// the offscreen render target, if that's what this is representing
/// </summary>
public RenderTarget Target;
public BufferedGraphics MyBufferedGraphics;
public Graphics refGraphics; //?? hacky?
public void CreateGraphics()
{
Rectangle r;
if (Control != null)
{
r = Control.ClientRectangle;
refGraphics = Control.CreateGraphics();
}
else
{
var tw = Target.Texture2d.Opaque as TextureWrapper;
r = Target.Texture2d.Rectangle;
refGraphics = Graphics.FromImage(tw.SDBitmap);
}
if (MyBufferedGraphics != null)
MyBufferedGraphics.Dispose();
MyBufferedGraphics = Gdi.MyBufferedGraphicsContext.Allocate(refGraphics, r);
//MyBufferedGraphics.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
////not sure about this stuff...
////it will wreck alpha blending, for one thing
//MyBufferedGraphics.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
//MyBufferedGraphics.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
}
}
public void BeginScene()
{
}
public void EndScene()
{
//maybe an inconsistent semantic with other implementations..
//but accomplishes the needed goal of getting the current RT to render
BindRenderTarget(null);
}
public IGraphicsControl Internal_CreateGraphicsControl()
{
var ret = new GLControlWrapper_GdiPlus(this);
//create a render target for this control
RenderTargetWrapper rtw = new RenderTargetWrapper(this);
rtw.Control = ret;
ret.RenderTargetWrapper = rtw;
return ret;
}
public void FreeRenderTarget(RenderTarget rt)
{
var rtw = rt.Opaque as RenderTargetWrapper;
rtw.Dispose();
}
public unsafe RenderTarget CreateRenderTarget(int w, int h)
{
TextureWrapper tw = new TextureWrapper();
tw.SDBitmap = new Bitmap(w,h, sdi.PixelFormat.Format32bppArgb);
var tex = new Texture2d(this, tw, w, h);
RenderTargetWrapper rtw = new RenderTargetWrapper(this);
var rt = new RenderTarget(this, rtw, tex);
rtw.Target = rt;
return rt;
}
public void BindRenderTarget(RenderTarget rt)
{
if (_CurrentOffscreenGraphics != null)
{
_CurrentOffscreenGraphics.Dispose();
_CurrentOffscreenGraphics = null;
}
_CurrRenderTarget = rt;
if (CurrentRenderTargetWrapper != null)
{
if (CurrentRenderTargetWrapper == CurrentControl.RenderTargetWrapper)
{
//dont do anything til swapbuffers
}
else
{
//CurrentRenderTargetWrapper.MyBufferedGraphics.Render();
}
}
if (rt == null)
{
//null means to use the default RT for the current control
CurrentRenderTargetWrapper = CurrentControl.RenderTargetWrapper;
}
else
{
var tw = rt.Texture2d.Opaque as TextureWrapper;
CurrentRenderTargetWrapper = rt.Opaque as RenderTargetWrapper;
_CurrentOffscreenGraphics = Graphics.FromImage(tw.SDBitmap);
//if (CurrentRenderTargetWrapper.MyBufferedGraphics == null)
// CurrentRenderTargetWrapper.CreateGraphics();
}
}
Graphics _CurrentOffscreenGraphics;
public Graphics GetCurrentGraphics()
{
if (_CurrentOffscreenGraphics != null)
return _CurrentOffscreenGraphics;
var rtw = CurrentRenderTargetWrapper;
return rtw.MyBufferedGraphics.Graphics;
}
public GLControlWrapper_GdiPlus CurrentControl;
public RenderTargetWrapper CurrentRenderTargetWrapper;
public BufferedGraphicsContext MyBufferedGraphicsContext;
public class TextureWrapper : IDisposable
{
public sd.Bitmap SDBitmap;
public TextureMinFilter MinFilter = TextureMinFilter.Nearest;
public TextureMagFilter MagFilter = TextureMagFilter.Nearest;
public void Dispose()
{
if (SDBitmap != null)
{
SDBitmap.Dispose();
SDBitmap = null;
}
}
}
} //class IGL_GdiPlus
}