451 lines
11 KiB
C#
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
|
|
|
|
}
|