2014-01-27 00:02:21 +00:00
//regarding binding and vertex arrays:
//http://stackoverflow.com/questions/8704801/glvertexattribpointer-clarification
//http://stackoverflow.com/questions/9536973/oes-vertex-array-object-and-client-state
//http://www.opengl.org/wiki/Vertex_Specification
//etc
//glBindAttribLocation (programID, 0, "vertexPosition_modelspace");
//for future reference: c# tesselators
//http://www.opentk.com/node/437 (AGG#, codes on Tao forums)
using System ;
2014-01-27 02:06:05 +00:00
using System.Reflection ;
2014-01-27 00:02:21 +00:00
using System.Threading ;
using System.IO ;
using System.Collections.Generic ;
using sd = System . Drawing ;
using sdi = System . Drawing . Imaging ;
using swf = System . Windows . Forms ;
using BizHawk.Bizware.BizwareGL ;
using OpenTK ;
using OpenTK.Graphics ;
using OpenTK.Graphics.OpenGL ;
namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
{
/// <summary>
/// OpenTK implementation of the BizwareGL.IGL interface.
/// TODO - can we have more than one of these? could be dangerous. such dangerous things to be possibly reconsidered are marked with HAMNUTS
/// TODO - if we have any way of making contexts, we also need a way of freeing it, and then we can cleanup our dictionaries
/// </summary>
public class IGL_TK : IGL
{
static IGL_TK ( )
{
//make sure OpenTK initializes without getting wrecked on the SDL check and throwing an exception to annoy our MDA's
var toolkitOptions = global :: OpenTK . ToolkitOptions . Default ;
toolkitOptions . Backend = PlatformBackend . PreferNative ;
global :: OpenTK . Toolkit . Init ( toolkitOptions ) ;
//NOTE: this throws EGL exceptions anyway. I'm going to ignore it and whine about it later
}
public IGL_TK ( )
{
2014-01-27 05:37:04 +00:00
//make an 'offscreen context' so we can at least do things without having to create a window
2014-01-27 00:02:21 +00:00
OffscreenNativeWindow = new NativeWindow ( ) ;
OffscreenNativeWindow . ClientSize = new sd . Size ( 8 , 8 ) ;
this . GraphicsContext = new GraphicsContext ( GraphicsMode . Default , OffscreenNativeWindow . WindowInfo , 2 , 0 , GraphicsContextFlags . Default ) ;
MakeDefaultCurrent ( ) ;
2014-01-27 05:37:04 +00:00
//this is important for reasons unknown
this . GraphicsContext . LoadAll ( ) ;
//misc initialization
2014-01-27 00:02:21 +00:00
CreateRenderStates ( ) ;
2014-01-30 04:54:02 +00:00
PurgeStateCache ( ) ;
2014-01-27 00:02:21 +00:00
}
2014-01-27 05:37:04 +00:00
void IDisposable . Dispose ( )
{
//TODO - a lot of analysis here
OffscreenNativeWindow . Dispose ( ) ; OffscreenNativeWindow = null ;
GraphicsContext . Dispose ( ) ; GraphicsContext = null ;
}
2014-02-03 05:27:59 +00:00
public void Clear ( ClearBufferMask mask )
2014-01-27 00:02:21 +00:00
{
GL . Clear ( ( global :: OpenTK . Graphics . OpenGL . ClearBufferMask ) mask ) ;
}
2014-02-03 05:27:59 +00:00
public void SetClearColor ( sd . Color color )
2014-01-27 00:02:21 +00:00
{
GL . ClearColor ( color ) ;
}
2014-02-03 05:27:59 +00:00
public IGraphicsControl Internal_CreateGraphicsControl ( )
2014-01-27 00:02:21 +00:00
{
2014-01-28 19:33:49 +00:00
var glc = new GLControlWrapper ( this ) ;
2014-01-27 00:02:21 +00:00
glc . CreateControl ( ) ;
//now the control's context will be current. annoying! fix it.
MakeDefaultCurrent ( ) ;
2014-01-27 02:06:05 +00:00
2014-01-28 19:33:49 +00:00
return glc ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public IntPtr GenTexture ( ) { return new IntPtr ( GL . GenTexture ( ) ) ; }
public void FreeTexture ( IntPtr texHandle ) { GL . DeleteTexture ( texHandle . ToInt32 ( ) ) ; }
public IntPtr GetEmptyHandle ( ) { return new IntPtr ( 0 ) ; }
public IntPtr GetEmptyUniformHandle ( ) { return new IntPtr ( - 1 ) ; }
2014-01-27 00:02:21 +00:00
2014-02-03 07:43:47 +00:00
public Shader CreateFragmentShader ( string source , bool required )
2014-01-27 00:02:21 +00:00
{
2014-02-03 07:43:47 +00:00
return CreateShader ( ShaderType . FragmentShader , source , required ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 07:43:47 +00:00
public Shader CreateVertexShader ( string source , bool required )
2014-01-27 00:02:21 +00:00
{
2014-02-03 07:43:47 +00:00
return CreateShader ( ShaderType . VertexShader , source , required ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public void FreeShader ( IntPtr shader ) { GL . DeleteShader ( shader . ToInt32 ( ) ) ; }
2014-01-27 00:02:21 +00:00
class MyBlendState : IBlendState
{
public bool enabled ;
public global :: OpenTK . Graphics . OpenGL . BlendingFactorSrc colorSource ;
public global :: OpenTK . Graphics . OpenGL . BlendEquationMode colorEquation ;
public global :: OpenTK . Graphics . OpenGL . BlendingFactorDest colorDest ;
public global :: OpenTK . Graphics . OpenGL . BlendingFactorSrc alphaSource ;
public global :: OpenTK . Graphics . OpenGL . BlendEquationMode alphaEquation ;
public global :: OpenTK . Graphics . OpenGL . BlendingFactorDest alphaDest ;
2014-01-27 09:45:16 +00:00
public MyBlendState ( bool enabled , BlendingFactorSrc colorSource , BlendEquationMode colorEquation , BlendingFactorDest colorDest ,
BlendingFactorSrc alphaSource , BlendEquationMode alphaEquation , BlendingFactorDest alphaDest )
2014-01-27 00:02:21 +00:00
{
this . enabled = enabled ;
this . colorSource = ( global :: OpenTK . Graphics . OpenGL . BlendingFactorSrc ) colorSource ;
this . colorEquation = ( global :: OpenTK . Graphics . OpenGL . BlendEquationMode ) colorEquation ;
this . colorDest = ( global :: OpenTK . Graphics . OpenGL . BlendingFactorDest ) colorDest ;
this . alphaSource = ( global :: OpenTK . Graphics . OpenGL . BlendingFactorSrc ) alphaSource ;
this . alphaEquation = ( global :: OpenTK . Graphics . OpenGL . BlendEquationMode ) alphaEquation ;
this . alphaDest = ( global :: OpenTK . Graphics . OpenGL . BlendingFactorDest ) alphaDest ;
}
}
2014-02-03 05:27:59 +00:00
public IBlendState CreateBlendState ( BlendingFactorSrc colorSource , BlendEquationMode colorEquation , BlendingFactorDest colorDest ,
2014-01-27 09:45:16 +00:00
BlendingFactorSrc alphaSource , BlendEquationMode alphaEquation , BlendingFactorDest alphaDest )
2014-01-27 00:02:21 +00:00
{
return new MyBlendState ( true , colorSource , colorEquation , colorDest , alphaSource , alphaEquation , alphaDest ) ;
}
2014-02-03 05:27:59 +00:00
public void SetBlendState ( IBlendState rsBlend )
2014-01-27 00:02:21 +00:00
{
var mybs = rsBlend as MyBlendState ;
if ( mybs . enabled )
{
GL . Enable ( EnableCap . Blend ) ;
GL . BlendEquationSeparate ( mybs . colorEquation , mybs . alphaEquation ) ;
GL . BlendFuncSeparate ( mybs . colorSource , mybs . colorDest , mybs . alphaSource , mybs . alphaDest ) ;
}
else GL . Disable ( EnableCap . Blend ) ;
}
2014-02-03 05:27:59 +00:00
public IBlendState BlendNone { get { return _rsBlendNone ; } }
public IBlendState BlendNormal { get { return _rsBlendNormal ; } }
2014-01-27 00:02:21 +00:00
2014-02-03 07:43:47 +00:00
public Pipeline CreatePipeline ( VertexLayout vertexLayout , Shader vertexShader , Shader fragmentShader , bool required )
2014-01-27 00:02:21 +00:00
{
2014-02-03 07:43:47 +00:00
bool success = true ;
2014-01-27 00:02:21 +00:00
ErrorCode errcode ;
int pid = GL . CreateProgram ( ) ;
GL . AttachShader ( pid , vertexShader . Id . ToInt32 ( ) ) ;
errcode = GL . GetError ( ) ;
GL . AttachShader ( pid , fragmentShader . Id . ToInt32 ( ) ) ;
errcode = GL . GetError ( ) ;
2014-02-03 05:27:59 +00:00
//bind the attribute locations from the vertex layout
foreach ( var kvp in vertexLayout . Items )
GL . BindAttribLocation ( pid , kvp . Key , kvp . Value . Name ) ;
2014-01-27 00:23:53 +00:00
2014-01-27 00:02:21 +00:00
GL . LinkProgram ( pid ) ;
errcode = GL . GetError ( ) ;
2014-01-27 00:23:53 +00:00
string resultLog = GL . GetProgramInfoLog ( pid ) ;
2014-02-03 07:43:47 +00:00
2014-01-27 00:23:53 +00:00
if ( errcode ! = ErrorCode . NoError )
2014-02-03 07:43:47 +00:00
if ( required )
throw new InvalidOperationException ( "Error creating pipeline (error returned from glLinkProgram): " + errcode + "\r\n\r\n" + resultLog ) ;
else success = false ;
2014-01-27 00:02:21 +00:00
2014-01-27 00:23:53 +00:00
int linkStatus ;
GL . GetProgram ( pid , GetProgramParameterName . LinkStatus , out linkStatus ) ;
2014-02-03 07:43:47 +00:00
if ( linkStatus = = 0 )
if ( required )
throw new InvalidOperationException ( "Error creating pipeline (link status false returned from glLinkProgram): " + "\r\n\r\n" + resultLog ) ;
else success = false ;
2014-01-27 00:02:21 +00:00
2014-01-28 01:58:54 +00:00
//need to work on validation. apparently there are some weird caveats to glValidate which make it complicated and possibly excuses (barely) the intel drivers' dysfunctional operation
2014-01-28 02:07:50 +00:00
//"A sampler points to a texture unit used by fixed function with an incompatible target"
/ /
//info:
//http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgram.xml
//This function mimics the validation operation that OpenGL implementations must perform when rendering commands are issued while programmable shaders are part of current state.
//glValidateProgram checks to see whether the executables contained in program can execute given the current OpenGL state
//This function is typically useful only during application development.
/ /
//So, this is no big deal. we shouldnt be calling validate right now anyway.
//conclusion: glValidate is very complicated and is of virtually no use unless your draw calls are returning errors and you want to know why
2014-01-28 01:58:54 +00:00
//GL.ValidateProgram(pid);
//errcode = GL.GetError();
//resultLog = GL.GetProgramInfoLog(pid);
//if (errcode != ErrorCode.NoError)
// throw new InvalidOperationException("Error creating pipeline (error returned from glValidateProgram): " + errcode + "\r\n\r\n" + resultLog);
//int validateStatus;
//GL.GetProgram(pid, GetProgramParameterName.ValidateStatus, out validateStatus);
//if (validateStatus == 0)
// throw new InvalidOperationException("Error creating pipeline (validateStatus status false returned from glValidateProgram): " + "\r\n\r\n" + resultLog);
2014-01-27 00:02:21 +00:00
2014-01-27 09:36:18 +00:00
//set the program to active, in case we need to set sampler uniforms on it
GL . UseProgram ( pid ) ;
2014-02-03 05:27:59 +00:00
////get all the attributes (not needed)
//List<AttributeInfo> attributes = new List<AttributeInfo>();
//int nAttributes;
//GL.GetProgram(pid, GetProgramParameterName.ActiveAttributes, out nAttributes);
//for (int i = 0; i < nAttributes; i++)
//{
// int size, length;
// var sbName = new System.Text.StringBuilder();
// ActiveAttribType type;
// GL.GetActiveAttrib(pid, i, 1024, out length, out size, out type, sbName);
// attributes.Add(new AttributeInfo() { Handle = new IntPtr(i), Name = sbName.ToString() });
//}
2014-01-27 00:02:21 +00:00
//get all the uniforms
List < UniformInfo > uniforms = new List < UniformInfo > ( ) ;
int nUniforms ;
int nSamplers = 0 ;
GL . GetProgram ( pid , GetProgramParameterName . ActiveUniforms , out nUniforms ) ;
2014-01-27 09:36:18 +00:00
2014-01-27 00:02:21 +00:00
for ( int i = 0 ; i < nUniforms ; i + + )
{
int size , length ;
ActiveUniformType type ;
var sbName = new System . Text . StringBuilder ( ) ;
GL . GetActiveUniform ( pid , i , 1024 , out length , out size , out type , sbName ) ;
2014-01-27 09:36:18 +00:00
errcode = GL . GetError ( ) ;
2014-01-27 00:02:21 +00:00
string name = sbName . ToString ( ) ;
int loc = GL . GetUniformLocation ( pid , name ) ;
var ui = new UniformInfo ( ) ;
ui . Name = name ;
ui . Handle = new IntPtr ( loc ) ;
//automatically assign sampler uniforms to texture units (and bind them)
bool isSampler = ( type = = ActiveUniformType . Sampler2D ) ;
if ( isSampler )
{
ui . SamplerIndex = nSamplers ;
GL . Uniform1 ( loc , nSamplers ) ;
nSamplers + + ;
}
uniforms . Add ( ui ) ;
}
2014-01-27 09:36:18 +00:00
//deactivate the program, so we dont accidentally use it
GL . UseProgram ( 0 ) ;
2014-01-27 00:02:21 +00:00
2014-02-03 07:43:47 +00:00
if ( ! vertexShader . Available ) success = false ;
if ( ! fragmentShader . Available ) success = false ;
return new Pipeline ( this , new IntPtr ( pid ) , success , vertexLayout , uniforms ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public VertexLayout CreateVertexLayout ( ) { return new VertexLayout ( this , new IntPtr ( 0 ) ) ; }
2014-01-27 00:02:21 +00:00
2014-02-03 05:27:59 +00:00
public void BindTexture2d ( Texture2d tex )
2014-01-27 00:02:21 +00:00
{
GL . BindTexture ( TextureTarget . Texture2D , tex . Id . ToInt32 ( ) ) ;
}
2014-04-15 21:46:18 +00:00
public void SetTextureWrapMode ( Texture2d tex , bool clamp )
{
BindTexture2d ( tex ) ;
int mode ;
if ( clamp )
{
mode = ( int ) global :: OpenTK . Graphics . OpenGL . TextureWrapMode . ClampToEdge ;
}
else
mode = ( int ) global :: OpenTK . Graphics . OpenGL . TextureWrapMode . Repeat ;
GL . TexParameter ( TextureTarget . Texture2D , TextureParameterName . TextureWrapS , mode ) ;
GL . TexParameter ( TextureTarget . Texture2D , TextureParameterName . TextureWrapT , mode ) ;
}
2014-02-03 05:27:59 +00:00
public unsafe void BindArrayData ( void * pData )
2014-01-27 00:02:21 +00:00
{
2014-01-30 04:54:02 +00:00
MyBindArrayData ( sStatePendingVertexLayout , pData ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public void DrawArrays ( PrimitiveType mode , int first , int count )
2014-01-27 00:02:21 +00:00
{
GL . DrawArrays ( ( global :: OpenTK . Graphics . OpenGL . PrimitiveType ) mode , first , count ) ;
}
2014-02-03 05:27:59 +00:00
public void BindPipeline ( Pipeline pipeline )
2014-01-27 00:02:21 +00:00
{
2014-04-16 16:31:53 +00:00
if ( pipeline = = null )
{
sStatePendingVertexLayout = null ;
GL . UseProgram ( 0 ) ;
return ;
}
2014-02-03 07:43:47 +00:00
if ( ! pipeline . Available ) throw new InvalidOperationException ( "Attempt to bind unavailable pipeline" ) ;
2014-02-03 05:27:59 +00:00
sStatePendingVertexLayout = pipeline . VertexLayout ;
2014-01-27 00:02:21 +00:00
GL . UseProgram ( pipeline . Id . ToInt32 ( ) ) ;
}
2014-02-06 09:45:55 +00:00
public void SetPipelineUniform ( PipelineUniform uniform , bool value )
{
GL . Uniform1 ( uniform . Id . ToInt32 ( ) , value ? 1 : 0 ) ;
}
2014-02-03 05:27:59 +00:00
public unsafe void SetPipelineUniformMatrix ( PipelineUniform uniform , Matrix4 mat , bool transpose )
2014-01-27 00:02:21 +00:00
{
GL . UniformMatrix4 ( uniform . Id . ToInt32 ( ) , 1 , transpose , ( float * ) & mat ) ;
}
2014-02-03 05:27:59 +00:00
public unsafe void SetPipelineUniformMatrix ( PipelineUniform uniform , ref Matrix4 mat , bool transpose )
2014-01-27 00:02:21 +00:00
{
2014-01-27 00:38:10 +00:00
fixed ( Matrix4 * pMat = & mat )
2014-01-27 00:02:21 +00:00
GL . UniformMatrix4 ( uniform . Id . ToInt32 ( ) , 1 , transpose , ( float * ) pMat ) ;
}
2014-02-03 05:27:59 +00:00
public void SetPipelineUniform ( PipelineUniform uniform , Vector4 value )
2014-01-27 00:02:21 +00:00
{
GL . Uniform4 ( uniform . Id . ToInt32 ( ) , value . X , value . Y , value . Z , value . W ) ;
}
2014-02-03 05:27:59 +00:00
public void SetPipelineUniform ( PipelineUniform uniform , Vector2 value )
{
GL . Uniform2 ( uniform . Id . ToInt32 ( ) , value . X , value . Y ) ;
}
public void SetPipelineUniform ( PipelineUniform uniform , float value )
{
GL . Uniform1 ( uniform . Id . ToInt32 ( ) , value ) ;
}
2014-02-06 09:45:55 +00:00
public unsafe void SetPipelineUniform ( PipelineUniform uniform , Vector4 [ ] values )
{
fixed ( Vector4 * pValues = & values [ 0 ] )
GL . Uniform4 ( uniform . Id . ToInt32 ( ) , values . Length , ( float * ) pValues ) ;
}
2014-02-03 05:27:59 +00:00
public void SetPipelineUniformSampler ( PipelineUniform uniform , IntPtr texHandle )
2014-01-27 00:02:21 +00:00
{
//set the sampler index into the uniform first
//now bind the texture
2014-01-30 04:54:02 +00:00
if ( sActiveTexture ! = uniform . SamplerIndex )
{
sActiveTexture = uniform . SamplerIndex ;
var selectedUnit = ( TextureUnit ) ( ( int ) TextureUnit . Texture0 + uniform . SamplerIndex ) ;
GL . ActiveTexture ( selectedUnit ) ;
}
2014-01-27 00:02:21 +00:00
GL . BindTexture ( TextureTarget . Texture2D , texHandle . ToInt32 ( ) ) ;
}
2014-02-03 05:27:59 +00:00
public void TexParameter2d ( TextureParameterName pname , int param )
2014-01-27 00:02:21 +00:00
{
GL . TexParameter ( TextureTarget . Texture2D , ( global :: OpenTK . Graphics . OpenGL . TextureParameterName ) pname , param ) ;
}
2014-02-03 05:27:59 +00:00
public Texture2d LoadTexture ( sd . Bitmap bitmap )
2014-01-27 00:02:21 +00:00
{
using ( var bmp = new BitmapBuffer ( bitmap , new BitmapLoadOptions ( ) ) )
return ( this as IGL ) . LoadTexture ( bmp ) ;
}
2014-02-03 05:27:59 +00:00
public Texture2d LoadTexture ( Stream stream )
2014-01-27 00:02:21 +00:00
{
using ( var bmp = new BitmapBuffer ( stream , new BitmapLoadOptions ( ) ) )
return ( this as IGL ) . LoadTexture ( bmp ) ;
}
2014-02-03 05:27:59 +00:00
public Texture2d CreateTexture ( int width , int height )
2014-01-27 00:02:21 +00:00
{
IntPtr id = ( this as IGL ) . GenTexture ( ) ;
return new Texture2d ( this , id , width , height ) ;
}
2014-04-15 21:46:18 +00:00
public Texture2d WrapGLTexture2d ( IntPtr glTexId , int width , int height )
{
return new Texture2d ( this as IGL , glTexId , width , height ) ;
}
2014-02-03 05:27:59 +00:00
public void LoadTextureData ( Texture2d tex , BitmapBuffer bmp )
2014-01-27 00:02:21 +00:00
{
sdi . BitmapData bmp_data = bmp . LockBits ( ) ;
try
{
GL . BindTexture ( TextureTarget . Texture2D , tex . Id . ToInt32 ( ) ) ;
GL . TexSubImage2D ( TextureTarget . Texture2D , 0 , 0 , 0 , bmp . Width , bmp . Height , PixelFormat . Bgra , PixelType . UnsignedByte , bmp_data . Scan0 ) ;
}
finally
{
bmp . UnlockBits ( bmp_data ) ;
}
}
2014-02-03 05:27:59 +00:00
public void FreeRenderTarget ( RenderTarget rt )
2014-01-28 19:33:49 +00:00
{
rt . Texture2d . Dispose ( ) ;
2014-02-03 08:04:11 +00:00
GL . Ext . DeleteFramebuffer ( rt . Id . ToInt32 ( ) ) ;
2014-01-28 19:33:49 +00:00
}
2014-02-03 05:27:59 +00:00
public unsafe RenderTarget CreateRenderTarget ( int w , int h )
2014-01-27 09:36:18 +00:00
{
//create a texture for it
IntPtr texid = ( this as IGL ) . GenTexture ( ) ;
Texture2d tex = new Texture2d ( this , texid , w , h ) ;
GL . BindTexture ( TextureTarget . Texture2D , texid . ToInt32 ( ) ) ;
2014-04-16 16:31:53 +00:00
GL . TexImage2D ( TextureTarget . Texture2D , 0 , PixelInternalFormat . Rgba8 , w , h , 0 , PixelFormat . Bgra , PixelType . UnsignedByte , IntPtr . Zero ) ;
2014-01-27 09:36:18 +00:00
tex . SetMagFilter ( TextureMagFilter . Nearest ) ;
tex . SetMinFilter ( TextureMinFilter . Nearest ) ;
//create the FBO
2014-02-03 08:04:11 +00:00
int fbid = GL . Ext . GenFramebuffer ( ) ;
GL . Ext . BindFramebuffer ( FramebufferTarget . Framebuffer , fbid ) ;
2014-01-27 09:36:18 +00:00
//bind the tex to the FBO
2014-02-03 08:04:11 +00:00
GL . Ext . FramebufferTexture2D ( FramebufferTarget . Framebuffer , FramebufferAttachment . ColorAttachment0 , TextureTarget . Texture2D , texid . ToInt32 ( ) , 0 ) ;
2014-01-27 09:36:18 +00:00
//do something, I guess say which colorbuffers are used by the framebuffer
2014-02-03 08:11:13 +00:00
DrawBuffersEnum * buffers = stackalloc DrawBuffersEnum [ 1 ] ;
buffers [ 0 ] = DrawBuffersEnum . ColorAttachment0 ;
GL . DrawBuffers ( 1 , buffers ) ;
2014-01-27 09:36:18 +00:00
2014-02-03 08:04:11 +00:00
if ( GL . Ext . CheckFramebufferStatus ( FramebufferTarget . Framebuffer ) ! = FramebufferErrorCode . FramebufferComplete )
2014-01-27 09:36:18 +00:00
throw new InvalidOperationException ( "Error creating framebuffer (at CheckFramebufferStatus)" ) ;
//since we're done configuring unbind this framebuffer, to return to the default
2014-02-03 08:04:11 +00:00
GL . Ext . BindFramebuffer ( FramebufferTarget . Framebuffer , 0 ) ;
2014-01-27 09:36:18 +00:00
return new RenderTarget ( this , new IntPtr ( fbid ) , tex ) ;
}
2014-02-03 05:27:59 +00:00
public void BindRenderTarget ( RenderTarget rt )
2014-01-27 09:36:18 +00:00
{
if ( rt = = null )
2014-02-03 08:04:11 +00:00
GL . Ext . BindFramebuffer ( FramebufferTarget . Framebuffer , 0 ) ;
2014-01-27 09:36:18 +00:00
else
2014-02-03 08:04:11 +00:00
GL . Ext . BindFramebuffer ( FramebufferTarget . Framebuffer , rt . Id . ToInt32 ( ) ) ;
2014-01-27 09:36:18 +00:00
}
2014-02-03 05:27:59 +00:00
public Texture2d LoadTexture ( BitmapBuffer bmp )
2014-01-27 00:02:21 +00:00
{
Texture2d ret = null ;
IntPtr id = ( this as IGL ) . GenTexture ( ) ;
try
{
ret = new Texture2d ( this , id , bmp . Width , bmp . Height ) ;
GL . BindTexture ( TextureTarget . Texture2D , id . ToInt32 ( ) ) ;
//picking a color order that matches doesnt seem to help, any. maybe my driver is accelerating it, or maybe it isnt a big deal. but its something to study on another day
GL . TexImage2D ( TextureTarget . Texture2D , 0 , PixelInternalFormat . Rgba , bmp . Width , bmp . Height , 0 , PixelFormat . Bgra , PixelType . UnsignedByte , IntPtr . Zero ) ;
( this as IGL ) . LoadTextureData ( ret , bmp ) ;
}
catch
{
( this as IGL ) . FreeTexture ( id ) ;
throw ;
}
//set default filtering.. its safest to do this always
ret . SetFilterNearest ( ) ;
return ret ;
}
2014-02-07 23:06:51 +00:00
public unsafe BitmapBuffer ResolveTexture2d ( Texture2d tex )
{
//note - this is dangerous since it changes the bound texture. could we save it?
BindTexture2d ( tex ) ;
var bb = new BitmapBuffer ( tex . IntWidth , tex . IntHeight ) ;
var bmpdata = bb . LockBits ( ) ;
2014-06-02 20:16:59 +00:00
GL . GetTexImage ( TextureTarget . Texture2D , 0 , PixelFormat . Bgra , PixelType . UnsignedByte , bmpdata . Scan0 ) ;
2014-02-07 23:06:51 +00:00
bb . UnlockBits ( bmpdata ) ;
return bb ;
}
2014-02-03 05:27:59 +00:00
public Texture2d LoadTexture ( string path )
2014-01-27 00:02:21 +00:00
{
using ( var fs = new FileStream ( path , FileMode . Open , FileAccess . Read , FileShare . Read ) )
return ( this as IGL ) . LoadTexture ( fs ) ;
}
2014-02-03 05:27:59 +00:00
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 )
2014-01-27 00:02:21 +00:00
{
2014-01-27 00:38:10 +00:00
Matrix4 ret = Matrix4 . Identity ;
2014-02-03 05:27:59 +00:00
ret . M11 = 2.0f / ( float ) dims . Width ;
ret . M22 = 2.0f / ( float ) dims . Height ;
2014-01-27 00:02:21 +00:00
return ret ;
}
2014-02-03 05:27:59 +00:00
public Matrix4 CreateGuiViewMatrix ( sd . Size dims )
2014-01-27 00:02:21 +00:00
{
2014-01-27 00:38:10 +00:00
Matrix4 ret = Matrix4 . Identity ;
2014-01-27 00:02:21 +00:00
ret . M22 = - 1.0f ;
2014-02-03 05:27:59 +00:00
ret . M41 = - ( float ) dims . Width * 0.5f ; // -0.5f;
ret . M42 = ( float ) dims . Height * 0.5f ; // +0.5f;
2014-01-27 00:02:21 +00:00
return ret ;
}
2014-02-03 05:27:59 +00:00
public void SetViewport ( int x , int y , int width , int height )
2014-01-27 00:02:21 +00:00
{
GL . Viewport ( x , y , width , height ) ;
2014-04-26 21:55:04 +00:00
GL . Scissor ( x , y , width , height ) ; //hack for mupen[rice]+intel: at least the rice plugin leaves the scissor rectangle scrambled, and we're trying to run it in the main graphics context for intel
2014-01-27 09:36:18 +00:00
}
2014-02-03 05:27:59 +00:00
public void SetViewport ( int width , int height )
2014-01-27 09:36:18 +00:00
{
2014-04-26 21:55:04 +00:00
SetViewport ( 0 , 0 , width , height ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public void SetViewport ( sd . Size size )
{
SetViewport ( size . Width , size . Height ) ;
}
public void SetViewport ( swf . Control control )
2014-01-27 00:02:21 +00:00
{
var r = control . ClientRectangle ;
2014-04-26 21:55:04 +00:00
SetViewport ( r . Left , r . Top , r . Width , r . Height ) ;
2014-01-27 00:02:21 +00:00
}
//------------------
INativeWindow OffscreenNativeWindow ;
IGraphicsContext GraphicsContext ;
//---------------
//my utility methods
GLControl CastControl ( swf . Control swfControl )
{
GLControl glc = swfControl as GLControl ;
if ( glc = = null )
throw new ArgumentException ( "Argument isn't a control created by the IGL interface" , "glControl" ) ;
return glc ;
}
2014-02-03 07:43:47 +00:00
Shader CreateShader ( ShaderType type , string source , bool required )
2014-01-27 00:02:21 +00:00
{
2014-02-03 07:43:47 +00:00
int sid = GL . CreateShader ( type ) ;
bool ok = CompileShaderSimple ( sid , source , required ) ;
if ( ! ok )
{
GL . DeleteShader ( sid ) ;
sid = 0 ;
}
2014-02-07 02:36:27 +00:00
2014-02-03 07:43:47 +00:00
return new Shader ( this , new IntPtr ( sid ) , ok ) ;
}
bool CompileShaderSimple ( int sid , string source , bool required )
{
bool success = true ;
2014-01-27 18:30:28 +00:00
ErrorCode errcode ;
2014-02-06 09:45:55 +00:00
errcode = GL . GetError ( ) ;
if ( errcode ! = ErrorCode . NoError )
throw new InvalidOperationException ( "Error compiling shader (from previous operation) " + errcode ) ;
2014-01-27 00:02:21 +00:00
GL . ShaderSource ( sid , source ) ;
2014-01-27 18:30:28 +00:00
errcode = GL . GetError ( ) ;
if ( errcode ! = ErrorCode . NoError )
2014-02-03 07:43:47 +00:00
if ( required )
2014-02-06 09:45:55 +00:00
throw new InvalidOperationException ( "Error compiling shader (ShaderSource) " + errcode ) ;
2014-02-03 07:43:47 +00:00
else success = false ;
2014-01-27 18:30:28 +00:00
2014-01-27 00:02:21 +00:00
GL . CompileShader ( sid ) ;
errcode = GL . GetError ( ) ;
2014-01-27 18:30:28 +00:00
string resultLog = GL . GetShaderInfoLog ( sid ) ;
if ( errcode ! = ErrorCode . NoError )
2014-02-03 07:43:47 +00:00
if ( required )
2014-02-06 09:45:55 +00:00
throw new InvalidOperationException ( "Error compiling shader (CompileShader) " + errcode + "\r\n\r\n" + resultLog ) ;
2014-02-03 07:43:47 +00:00
else success = false ;
2014-01-27 18:30:28 +00:00
2014-01-27 00:02:21 +00:00
int n ;
GL . GetShader ( sid , ShaderParameter . CompileStatus , out n ) ;
2014-01-27 18:30:28 +00:00
2014-02-03 07:43:47 +00:00
if ( n = = 0 )
if ( required )
2014-02-06 09:45:55 +00:00
throw new InvalidOperationException ( "Error compiling shader (CompileShader )" + "\r\n\r\n" + resultLog ) ;
2014-02-03 07:43:47 +00:00
else success = false ;
return success ;
2014-01-27 00:02:21 +00:00
}
2014-01-30 04:54:02 +00:00
2014-01-27 00:02:21 +00:00
void UnbindVertexAttributes ( )
{
//HAMNUTS:
//its not clear how many bindings we'll have to disable before we can enable the ones we need..
//so lets just disable the ones we remember we have bound
2014-01-30 04:54:02 +00:00
var currBindings = sVertexAttribEnables ;
2014-01-27 00:02:21 +00:00
foreach ( var index in currBindings )
GL . DisableVertexAttribArray ( index ) ;
currBindings . Clear ( ) ;
}
unsafe void MyBindArrayData ( VertexLayout layout , void * pData )
{
UnbindVertexAttributes ( ) ;
//HAMNUTS (continued)
2014-01-30 04:54:02 +00:00
var currBindings = sVertexAttribEnables ;
sStateCurrentVertexLayout = sStatePendingVertexLayout ;
2014-01-27 00:02:21 +00:00
2014-04-16 16:31:53 +00:00
if ( layout = = null ) return ;
2014-01-27 00:02:21 +00:00
foreach ( var kvp in layout . Items )
{
GL . VertexAttribPointer ( kvp . Key , kvp . Value . Components , ( VertexAttribPointerType ) kvp . Value . AttribType , kvp . Value . Normalized , kvp . Value . Stride , new IntPtr ( pData ) + kvp . Value . Offset ) ;
GL . EnableVertexAttribArray ( kvp . Key ) ;
currBindings . Add ( kvp . Key ) ;
}
}
2014-06-08 23:30:34 +00:00
public void MakeDefaultCurrent ( )
2014-01-27 00:02:21 +00:00
{
2014-01-30 04:54:02 +00:00
MakeContextCurrent ( this . GraphicsContext , OffscreenNativeWindow . WindowInfo ) ;
2014-01-27 00:02:21 +00:00
}
2014-01-28 19:33:49 +00:00
internal void MakeContextCurrent ( IGraphicsContext context , global :: OpenTK . Platform . IWindowInfo windowInfo )
2014-01-27 00:02:21 +00:00
{
context . MakeCurrent ( windowInfo ) ;
2014-01-30 04:54:02 +00:00
PurgeStateCache ( ) ;
2014-01-27 00:02:21 +00:00
}
void CreateRenderStates ( )
{
2014-01-27 09:45:16 +00:00
_rsBlendNone = new MyBlendState ( false , BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero , BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ) ;
_rsBlendNormal = new MyBlendState ( true ,
BlendingFactorSrc . SrcAlpha , BlendEquationMode . FuncAdd , BlendingFactorDest . OneMinusSrcAlpha ,
BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ) ;
2014-01-27 00:02:21 +00:00
}
MyBlendState _rsBlendNone , _rsBlendNormal ;
2014-01-30 04:54:02 +00:00
//state caches
int sActiveTexture ;
VertexLayout sStateCurrentVertexLayout ;
VertexLayout sStatePendingVertexLayout ;
HashSet < int > sVertexAttribEnables = new HashSet < int > ( ) ;
void PurgeStateCache ( )
{
sStateCurrentVertexLayout = null ;
sStatePendingVertexLayout = null ;
sVertexAttribEnables . Clear ( ) ;
sActiveTexture = - 1 ;
}
2014-01-27 00:02:21 +00:00
} //class IGL_TK
}