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

457 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 ResourceIdManager
{
int Last = 1;
Queue<int> Available = new Queue<int>();
public Dictionary<int, object> Lookup = new Dictionary<int, object>();
public enum EResourceType
{
Texture,
RenderTarget
}
public IntPtr Alloc(EResourceType type)
{
if (Available.Count == 0)
{
return new IntPtr(Last++);
}
else return new IntPtr(Available.Dequeue());
}
public void Free(IntPtr handle)
{
int n = handle.ToInt32();
object o;
if (Lookup.TryGetValue(n, out o))
{
if (o is IDisposable)
{
((IDisposable)o).Dispose();
}
Lookup.Remove(n);
}
Available.Enqueue(n);
}
}
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;
}
}
}
public class IGL_GdiPlus : IGL
{
public IGL_GdiPlus()
{
MyBufferedGraphicsContext = new BufferedGraphicsContext();
}
void IDisposable.Dispose()
{
}
public void Clear(OpenTK.Graphics.OpenGL.ClearBufferMask mask)
{
}
public string API { get { return "GDIPLUS"; } }
public IBlendState CreateBlendState(BlendingFactorSrc colorSource, BlendEquationMode colorEquation, BlendingFactorDest colorDest,
BlendingFactorSrc alphaSource, BlendEquationMode alphaEquation, BlendingFactorDest alphaDest)
{
return null;
}
public void SetClearColor(sd.Color color)
{
}
public unsafe void BindArrayData(void* pData)
{
}
public IntPtr GenTexture() { return ResourceIDs.Alloc(ResourceIdManager.EResourceType.Texture); }
public void FreeTexture(Texture2d tex)
{
ResourceIDs.Free(tex.Id);
}
public IntPtr GetEmptyHandle() { return new IntPtr(0); }
public IntPtr GetEmptyUniformHandle() { return new IntPtr(-1); }
public Shader CreateFragmentShader(string source, bool required)
{
return null;
}
public Shader CreateVertexShader(string source, 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)
{
return null;
}
public VertexLayout CreateVertexLayout() { return new VertexLayout(this, new IntPtr(0)); }
public void BindTexture2d(Texture2d tex)
{
CurrentBoundTexture = tex;
}
public void SetTextureWrapMode(Texture2d tex, bool clamp)
{
if (CurrentBoundTexture == null)
throw new InvalidOperationException();
}
public void DrawArrays(PrimitiveType mode, int first, int count)
{
}
public void BindPipeline(Pipeline pipeline)
{
}
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, IntPtr texHandle)
{
}
public void TexParameter2d(TextureParameterName pname, int param)
{
if (CurrentBoundTexture == null)
return;
TextureWrapper tw = TextureWrapperForTexture(CurrentBoundTexture);
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;
IntPtr id = GenTexture();
ResourceIDs.Lookup[id.ToInt32()] = tw;
return new Texture2d(this, id, null, 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)
{
bmp.ToSysdrawingBitmap(BitmapForTexture(tex));
}
public Texture2d LoadTexture(BitmapBuffer bmp)
{
//definitely needed (by TextureFrugalizer at least)
var sdbmp = bmp.ToSysdrawingBitmap();
IntPtr id = GenTexture();
var tw = new TextureWrapper();
tw.SDBitmap = sdbmp;
ResourceIDs.Lookup[id.ToInt32()] = tw;
return new Texture2d(this, id, null, bmp.Width, bmp.Height);
}
public unsafe BitmapBuffer ResolveTexture2d(Texture2d tex)
{
//todo
return null;
}
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)
{
return CreateGuiViewMatrix(new sd.Size(w, h));
}
public Matrix4 CreateGuiProjectionMatrix(sd.Size dims)
{
Matrix4 ret = Matrix4.Identity;
ret.M11 = 2.0f / (float)dims.Width;
ret.M22 = 2.0f / (float)dims.Height;
return ret;
}
public Matrix4 CreateGuiViewMatrix(sd.Size dims)
{
Matrix4 ret = Matrix4.Identity;
ret.M22 = -1.0f;
ret.M41 = -(float)dims.Width * 0.5f; // -0.5f;
ret.M42 = (float)dims.Height * 0.5f; // +0.5f;
return ret;
}
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;
}
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 void CreateGraphics()
{
Graphics refGraphics;
Rectangle r;
if (Control != null)
{
r = Control.ClientRectangle;
refGraphics = Control.CreateGraphics();
}
else
{
r = Target.Texture2d.Rectangle;
refGraphics = Graphics.FromImage(Gdi.BitmapForTexture(Target.Texture2d));
}
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 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)
{
int id = rt.Id.ToInt32();
var rtw = ResourceIDs.Lookup[id] as RenderTargetWrapper;
rtw.Target.Dispose();
ResourceIDs.Free(rt.Id);
}
public unsafe RenderTarget CreateRenderTarget(int w, int h)
{
Texture2d tex = null;
var rt = new RenderTarget(this, ResourceIDs.Alloc(ResourceIdManager.EResourceType.RenderTarget), tex);
int id = rt.Id.ToInt32();
RenderTargetWrapper rtw = new RenderTargetWrapper(this);
rtw.Target = rt;
ResourceIDs.Lookup[id] = rtw;
return rt;
}
public void BindRenderTarget(RenderTarget rt)
{
if (rt == null)
{
//null means to use the default RT for the current control
CurrentRenderTargetWrapper = CurrentControl.RenderTargetWrapper;
}
else
{
CurrentRenderTargetWrapper = RenderTargetWrapperForRt(rt);
}
}
public sd.Bitmap BitmapForTexture(Texture2d tex)
{
return TextureWrapperForTexture(tex).SDBitmap;
}
public TextureWrapper TextureWrapperForTexture(Texture2d tex)
{
return ResourceIDs.Lookup[tex.Id.ToInt32()] as TextureWrapper;
}
public RenderTargetWrapper RenderTargetWrapperForRt(RenderTarget rt)
{
return ResourceIDs.Lookup[rt.Id.ToInt32()] as RenderTargetWrapper;
}
public Graphics GetCurrentGraphics()
{
var rtw = CurrentRenderTargetWrapper;
return rtw.MyBufferedGraphics.Graphics;
}
public GLControlWrapper_GdiPlus CurrentControl;
public RenderTargetWrapper CurrentRenderTargetWrapper;
Texture2d CurrentBoundTexture;
//todo - not thread safe
public static ResourceIdManager ResourceIDs = new ResourceIdManager();
public BufferedGraphicsContext MyBufferedGraphicsContext;
} //class IGL_GdiPlus
}