2020-02-28 18:32:45 +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
2014-01-27 00:02:21 +00:00
2020-02-28 18:32:45 +00:00
// etc
// glBindAttribLocation (programID, 0, "vertexPosition_modelspace");
2014-01-27 00:02:21 +00:00
2020-02-28 18:32:45 +00:00
// for future reference: c# tesselators
// http://www.opentk.com/node/437 (AGG#, codes on Tao forums)
2014-01-27 00:02:21 +00:00
using System ;
using System.IO ;
using System.Collections.Generic ;
using BizHawk.Bizware.BizwareGL ;
using OpenTK ;
using OpenTK.Graphics ;
using OpenTK.Graphics.OpenGL ;
2020-01-25 09:23:31 +00:00
using sd = System . Drawing ;
using sdi = System . Drawing . Imaging ;
using swf = System . Windows . Forms ;
2014-01-27 00:02:21 +00:00
2020-02-18 16:31:49 +00:00
namespace BizHawk.Client.EmuHawk
2014-01-27 00:02:21 +00:00
{
/// <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
{
2015-08-20 23:35:53 +00:00
//rendering state
2020-02-28 18:32:45 +00:00
private Pipeline _currPipeline ;
private RenderTarget _currRenderTarget ;
2015-08-20 23:35:53 +00:00
2014-01-27 00:02:21 +00:00
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
}
2020-02-25 19:15:43 +00:00
public string API = > "OPENGL" ;
2014-12-08 02:15:42 +00:00
2014-12-16 20:24:14 +00:00
public int Version
{
get
{
2014-12-20 06:39:17 +00:00
//doesnt work on older than gl3 maybe
//int major, minor;
////other overloads may not exist...
//GL.GetInteger(GetPName.MajorVersion, out major);
//GL.GetInteger(GetPName.MinorVersion, out minor);
//supposedly the standard dictates that whatever junk is in the version string, some kind of version is at the beginning
string version_string = GL . GetString ( StringName . Version ) ;
var version_parts = version_string . Split ( '.' ) ;
int major = int . Parse ( version_parts [ 0 ] ) ;
//getting a minor version out is too hard and not needed now
return major * 100 ;
2014-12-16 20:24:14 +00:00
}
}
2020-02-28 18:32:45 +00:00
public IGL_TK ( int majorVersion , int minorVersion , bool forwardCompatible )
2014-01-27 00:02:21 +00:00
{
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
2020-02-28 17:15:06 +00:00
OffscreenNativeWindow = new NativeWindow { ClientSize = new sd . Size ( 8 , 8 ) } ;
2020-02-28 18:32:45 +00:00
GraphicsContext = new GraphicsContext ( GraphicsMode . Default , OffscreenNativeWindow . WindowInfo , majorVersion , minorVersion , forwardCompatible ? GraphicsContextFlags . ForwardCompatible : GraphicsContextFlags . Default ) ;
2014-01-27 00:02:21 +00:00
MakeDefaultCurrent ( ) ;
2014-01-27 05:37:04 +00:00
//this is important for reasons unknown
2020-02-28 17:15:06 +00:00
GraphicsContext . LoadAll ( ) ;
2014-01-27 05:37:04 +00:00
//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
}
2015-08-20 23:35:53 +00:00
public void BeginScene ( )
{
2020-02-28 18:32:45 +00:00
// seems not to be needed...
2015-08-20 23:35:53 +00:00
}
public void EndScene ( )
{
2020-02-28 18:32:45 +00:00
// seems not to be needed...
2015-08-20 23:35:53 +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
{
2020-02-28 18:32:45 +00:00
GL . Clear ( mask ) ;
2014-01-27 00:02:21 +00:00
}
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 ( ) ;
2020-02-28 18:32:45 +00:00
// now the control's context will be current. annoying! fix it.
2014-01-27 00:02:21 +00:00
MakeDefaultCurrent ( ) ;
2014-01-28 19:33:49 +00:00
return glc ;
2014-01-27 00:02:21 +00:00
}
2020-02-28 18:32:45 +00:00
public int GenTexture ( ) = > GL . GenTexture ( ) ;
2014-12-08 02:15:42 +00:00
public void FreeTexture ( Texture2d tex )
{
2015-08-20 23:35:53 +00:00
GL . DeleteTexture ( ( int ) tex . Opaque ) ;
2014-12-08 02:15:42 +00:00
}
2014-01-27 00:02:21 +00:00
2015-08-20 23:35:53 +00:00
public Shader CreateFragmentShader ( bool cg , string source , string entry , bool required )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
return CreateShader ( cg , ShaderType . FragmentShader , source , entry , required ) ;
2014-01-27 00:02:21 +00:00
}
2020-02-28 18:32:45 +00:00
2015-08-20 23:35:53 +00:00
public Shader CreateVertexShader ( bool cg , string source , string entry , bool required )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
return CreateShader ( cg , ShaderType . VertexShader , source , entry , required ) ;
2014-01-27 00:02:21 +00:00
}
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
{
2015-08-20 23:35:53 +00:00
return new CacheBlendState ( true , colorSource , colorEquation , colorDest , alphaSource , alphaEquation , alphaDest ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public void SetBlendState ( IBlendState rsBlend )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
var mybs = rsBlend as CacheBlendState ;
if ( mybs . Enabled )
2014-01-27 00:02:21 +00:00
{
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-12-13 23:04:22 +00:00
if ( rsBlend = = _rsBlendNoneOpaque )
{
//make sure constant color is set correctly
GL . BlendColor ( new Color4 ( 255 , 255 , 255 , 255 ) ) ;
}
2014-01-27 00:02:21 +00:00
}
2020-02-25 20:13:06 +00:00
public IBlendState BlendNoneCopy = > _rsBlendNoneVerbatim ;
public IBlendState BlendNoneOpaque = > _rsBlendNoneOpaque ;
public IBlendState BlendNormal = > _rsBlendNormal ;
2014-01-27 00:02:21 +00:00
2020-02-28 18:32:45 +00:00
private class ShaderWrapper
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
public int sid ;
public Dictionary < string , string > MapCodeToNative ;
public Dictionary < string , string > MapNativeToCode ;
}
2020-02-28 18:32:45 +00:00
private class PipelineWrapper
2015-08-20 23:35:53 +00:00
{
public int pid ;
public Shader FragmentShader , VertexShader ;
public List < int > SamplerLocs ;
}
2020-01-01 11:38:41 +00:00
/// <exception cref="InvalidOperationException">
/// <paramref name="required"/> is <see langword="true"/> and either <paramref name="vertexShader"/> or <paramref name="fragmentShader"/> is unavailable (their <see cref="Shader.Available"/> property is <see langword="false"/>), or
/// <c>glLinkProgram</c> call did not produce expected result
/// </exception>
2015-08-20 23:35:53 +00:00
public Pipeline CreatePipeline ( VertexLayout vertexLayout , Shader vertexShader , Shader fragmentShader , bool required , string memo )
{
2020-02-28 18:32:45 +00:00
// if the shaders aren't available, the pipeline isn't either
2015-10-18 00:27:58 +00:00
if ( ! vertexShader . Available | | ! fragmentShader . Available )
{
2019-03-20 04:41:19 +00:00
string errors = $"Vertex Shader:\r\n {vertexShader.Errors} \r\n-------\r\nFragment Shader:\r\n{fragmentShader.Errors}" ;
2016-02-03 08:28:03 +00:00
if ( required )
2019-03-20 04:41:19 +00:00
throw new InvalidOperationException ( $"Couldn't build required GL pipeline:\r\n{errors}" ) ;
2020-02-28 17:15:06 +00:00
var pipeline = new Pipeline ( this , null , false , null , null , null ) { Errors = errors } ;
2016-02-03 08:28:03 +00:00
return pipeline ;
2015-10-18 00:27:58 +00:00
}
2014-02-03 07:43:47 +00:00
bool success = true ;
2015-08-20 23:35:53 +00:00
var vsw = vertexShader . Opaque as ShaderWrapper ;
var fsw = fragmentShader . Opaque as ShaderWrapper ;
var sws = new [ ] { vsw , fsw } ;
bool mapVariables = vsw . MapCodeToNative ! = null | | fsw . MapCodeToNative ! = null ;
2014-01-27 00:02:21 +00:00
ErrorCode errcode ;
int pid = GL . CreateProgram ( ) ;
2015-08-20 23:35:53 +00:00
GL . AttachShader ( pid , vsw . sid ) ;
2014-01-27 00:02:21 +00:00
errcode = GL . GetError ( ) ;
2015-08-20 23:35:53 +00:00
GL . AttachShader ( pid , fsw . sid ) ;
2014-01-27 00:02:21 +00:00
errcode = GL . GetError ( ) ;
2014-02-03 05:27:59 +00:00
2015-08-20 23:35:53 +00:00
//NOT BEING USED NOW: USING SEMANTICS INSTEAD
////bind the attribute locations from the vertex layout
////as we go, look for attribute mappings (CGC will happily reorder and rename our attribute mappings)
////what's more it will _RESIZE_ them but this seems benign..somehow..
////WELLLLLLL we wish we could do that by names
2020-02-28 18:52:48 +00:00
////but the shaders don't seem to be adequate quality (oddly named attributes.. texCoord vs texCoord1). need to use semantics instead.
2015-08-20 23:35:53 +00:00
//foreach (var kvp in vertexLayout.Items)
//{
// string name = kvp.Value.Name;
// //if (mapVariables)
// //{
// // foreach (var sw in sws)
// // {
// // if (sw.MapNativeToCode.ContainsKey(name))
// // {
// // name = sw.MapNativeToCode[name];
// // break;
// // }
// // }
// //}
// if(mapVariables) {
// ////proxy for came-from-cgc
// //switch (kvp.Value.Usage)
// //{
// // case AttributeUsage.Position:
// //}
// }
// //GL.BindAttribLocation(pid, kvp.Key, name);
//}
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 )
2019-03-20 04:41:19 +00:00
throw new InvalidOperationException ( $"Error creating pipeline (error returned from glLinkProgram): {errcode}\r\n\r\n{resultLog}" ) ;
2014-02-03 07:43:47 +00:00
else success = false ;
2020-02-25 19:15:43 +00:00
GL . GetProgram ( pid , GetProgramParameterName . LinkStatus , out var linkStatus ) ;
2014-02-03 07:43:47 +00:00
if ( linkStatus = = 0 )
if ( required )
2019-03-20 04:41:19 +00:00
throw new InvalidOperationException ( $"Error creating pipeline (link status false returned from glLinkProgram): \r\n\r\n{resultLog}" ) ;
2014-02-03 07:43:47 +00:00
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.
/ /
2020-02-28 18:52:48 +00:00
//So, this is no big deal. we shouldn't be calling validate right now anyway.
2014-01-28 02:07:50 +00:00
//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)
2019-03-20 04:41:19 +00:00
// throw new InvalidOperationException($"Error creating pipeline (error returned from glValidateProgram): {errcode}\r\n\r\n{resultLog}");
2014-01-28 01:58:54 +00:00
//int validateStatus;
//GL.GetProgram(pid, GetProgramParameterName.ValidateStatus, out validateStatus);
//if (validateStatus == 0)
2019-03-20 04:41:19 +00:00
// 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 ) ;
2015-08-20 23:35:53 +00:00
//get all the attributes (not needed)
List < AttributeInfo > attributes = new List < AttributeInfo > ( ) ;
2020-02-25 19:15:43 +00:00
GL . GetProgram ( pid , GetProgramParameterName . ActiveAttributes , out var nAttributes ) ;
2015-08-20 23:35:53 +00:00
for ( int i = 0 ; i < nAttributes ; i + + )
{
int size , length ;
2018-11-04 17:05:20 +00:00
string name = new System . Text . StringBuilder ( 1024 ) . ToString ( ) ;
2015-08-20 23:35:53 +00:00
ActiveAttribType type ;
2018-11-04 17:05:20 +00:00
GL . GetActiveAttrib ( pid , i , 1024 , out length , out size , out type , out name ) ;
attributes . Add ( new AttributeInfo ( ) { Handle = new IntPtr ( i ) , Name = name } ) ;
2015-08-20 23:35:53 +00:00
}
2014-02-03 05:27:59 +00:00
2014-01-27 00:02:21 +00:00
//get all the uniforms
List < UniformInfo > uniforms = new List < UniformInfo > ( ) ;
2020-02-25 19:15:43 +00:00
GL . GetProgram ( pid , GetProgramParameterName . ActiveUniforms , out var nUniforms ) ;
2015-08-20 23:35:53 +00:00
List < int > samplers = new List < int > ( ) ;
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 ;
2019-11-04 09:50:45 +00:00
string name = new System . Text . StringBuilder ( 1024 ) . ToString ( ) ;
2020-02-25 19:15:43 +00:00
GL . GetActiveUniform ( pid , i , 1024 , out length , out size , out var type , out name ) ;
2014-01-27 09:36:18 +00:00
errcode = GL . GetError ( ) ;
2014-01-27 00:02:21 +00:00
int loc = GL . GetUniformLocation ( pid , name ) ;
2015-08-20 23:35:53 +00:00
//translate name if appropriate
//not sure how effective this approach will be, due to confusion of vertex and fragment uniforms
if ( mapVariables )
{
if ( vsw . MapCodeToNative . ContainsKey ( name ) ) name = vsw . MapCodeToNative [ name ] ;
if ( fsw . MapCodeToNative . ContainsKey ( name ) ) name = fsw . MapCodeToNative [ name ] ;
}
2020-02-28 17:15:06 +00:00
var ui = new UniformInfo { Name = name , Opaque = loc } ;
2014-01-27 00:02:21 +00:00
2015-08-20 23:35:53 +00:00
if ( type = = ActiveUniformType . Sampler2D )
2014-01-27 00:02:21 +00:00
{
2015-10-16 01:10:58 +00:00
ui . IsSampler = true ;
2015-10-19 02:12:58 +00:00
ui . SamplerIndex = samplers . Count ;
2015-08-20 23:35:53 +00:00
ui . Opaque = loc | ( samplers . Count < < 24 ) ;
samplers . Add ( loc ) ;
2014-01-27 00:02:21 +00:00
}
uniforms . Add ( ui ) ;
}
2020-02-28 18:32:45 +00:00
// deactivate the program, so we don't accidentally use it
2014-01-27 09:36:18 +00:00
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 ;
2020-02-28 18:32:45 +00:00
var pw = new PipelineWrapper { pid = pid , VertexShader = vertexShader , FragmentShader = fragmentShader , SamplerLocs = samplers } ;
2015-08-20 23:35:53 +00:00
return new Pipeline ( this , pw , success , vertexLayout , uniforms , memo ) ;
2014-01-27 00:02:21 +00:00
}
2015-08-20 23:35:53 +00:00
public void FreePipeline ( Pipeline pipeline )
{
var pw = pipeline . Opaque as PipelineWrapper ;
2017-07-20 22:18:08 +00:00
2020-02-28 18:32:45 +00:00
// unavailable pipelines will have no opaque
2017-07-20 22:18:08 +00:00
if ( pw = = null )
2020-02-28 18:32:45 +00:00
{
2017-07-20 22:18:08 +00:00
return ;
2020-02-28 18:32:45 +00:00
}
2017-07-20 22:18:08 +00:00
2015-08-20 23:35:53 +00:00
GL . DeleteProgram ( pw . pid ) ;
pw . FragmentShader . Release ( ) ;
pw . VertexShader . Release ( ) ;
}
2014-01-27 00:02:21 +00:00
2015-08-20 23:35:53 +00:00
public void Internal_FreeShader ( Shader shader )
2014-01-27 00:02:21 +00:00
{
2017-04-08 19:31:02 +00:00
var sw = shader . Opaque as ShaderWrapper ;
GL . DeleteShader ( sw . sid ) ;
2015-08-20 23:35:53 +00:00
}
2020-01-01 11:38:41 +00:00
/// <exception cref="InvalidOperationException"><paramref name="pipeline"/>.<see cref="Pipeline.Available"/> is <see langword="false"/></exception>
2015-08-20 23:35:53 +00:00
public void BindPipeline ( Pipeline pipeline )
{
2020-02-28 18:32:45 +00:00
_currPipeline = pipeline ;
2015-08-20 23:35:53 +00:00
if ( pipeline = = null )
{
sStatePendingVertexLayout = null ;
GL . UseProgram ( 0 ) ;
return ;
}
if ( ! pipeline . Available ) throw new InvalidOperationException ( "Attempt to bind unavailable pipeline" ) ;
sStatePendingVertexLayout = pipeline . VertexLayout ;
var pw = pipeline . Opaque as PipelineWrapper ;
GL . UseProgram ( pw . pid ) ;
//this is dumb and confusing, but we have to bind physical sampler numbers to sampler variables.
for ( int i = 0 ; i < pw . SamplerLocs . Count ; i + + )
{
GL . Uniform1 ( pw . SamplerLocs [ i ] , i ) ;
}
}
2020-02-28 18:32:45 +00:00
public VertexLayout CreateVertexLayout ( ) = > new VertexLayout ( this , null ) ;
2015-08-20 23:35:53 +00:00
private void BindTexture2d ( Texture2d tex )
{
GL . BindTexture ( TextureTarget . Texture2D , ( int ) tex . Opaque ) ;
2014-01-27 00:02:21 +00:00
}
2014-04-15 21:46:18 +00:00
public void SetTextureWrapMode ( Texture2d tex , bool clamp )
{
BindTexture2d ( tex ) ;
int mode ;
if ( clamp )
{
2020-02-28 18:32:45 +00:00
mode = ( int ) TextureWrapMode . ClampToEdge ;
2014-04-15 21:46:18 +00:00
}
else
2020-02-28 18:32:45 +00:00
{
mode = ( int ) TextureWrapMode . Repeat ;
}
2014-04-15 21:46:18 +00:00
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
{
2020-02-28 18:32:45 +00:00
GL . DrawArrays ( mode , first , count ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-06 09:45:55 +00:00
public void SetPipelineUniform ( PipelineUniform uniform , bool value )
{
2015-08-20 23:35:53 +00:00
GL . Uniform1 ( ( int ) uniform . Sole . Opaque , value ? 1 : 0 ) ;
2014-02-06 09:45:55 +00:00
}
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
{
2015-08-20 23:35:53 +00:00
//GL.UniformMatrix4((int)uniform.Opaque, 1, transpose, (float*)&mat);
GL . Uniform4 ( ( int ) uniform . Sole . Opaque + 0 , 1 , ( float * ) & mat . Row0 ) ;
GL . Uniform4 ( ( int ) uniform . Sole . Opaque + 1 , 1 , ( float * ) & mat . Row1 ) ;
GL . Uniform4 ( ( int ) uniform . Sole . Opaque + 2 , 1 , ( float * ) & mat . Row2 ) ;
GL . Uniform4 ( ( int ) uniform . Sole . Opaque + 3 , 1 , ( float * ) & mat . Row3 ) ;
2014-01-27 00:02:21 +00:00
}
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 )
2015-08-20 23:35:53 +00:00
GL . UniformMatrix4 ( ( int ) uniform . Sole . Opaque , 1 , transpose , ( float * ) pMat ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public void SetPipelineUniform ( PipelineUniform uniform , Vector4 value )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
GL . Uniform4 ( ( int ) uniform . Sole . Opaque , value . X , value . Y , value . Z , value . W ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public void SetPipelineUniform ( PipelineUniform uniform , Vector2 value )
{
2015-08-20 23:35:53 +00:00
GL . Uniform2 ( ( int ) uniform . Sole . Opaque , value . X , value . Y ) ;
2014-02-03 05:27:59 +00:00
}
public void SetPipelineUniform ( PipelineUniform uniform , float value )
{
2015-08-20 23:35:53 +00:00
if ( uniform . Owner = = null ) return ; //uniform was optimized out
GL . Uniform1 ( ( int ) uniform . Sole . Opaque , value ) ;
2014-02-03 05:27:59 +00:00
}
2014-02-06 09:45:55 +00:00
public unsafe void SetPipelineUniform ( PipelineUniform uniform , Vector4 [ ] values )
{
fixed ( Vector4 * pValues = & values [ 0 ] )
2015-08-20 23:35:53 +00:00
GL . Uniform4 ( ( int ) uniform . Sole . Opaque , values . Length , ( float * ) pValues ) ;
2014-02-06 09:45:55 +00:00
}
2015-08-20 23:35:53 +00:00
public void SetPipelineUniformSampler ( PipelineUniform uniform , Texture2d tex )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
int n = ( ( int ) uniform . Sole . Opaque ) > > 24 ;
2014-01-27 00:02:21 +00:00
//set the sampler index into the uniform first
2015-08-20 23:35:53 +00:00
if ( sActiveTexture ! = n )
2014-01-30 04:54:02 +00:00
{
2015-08-20 23:35:53 +00:00
sActiveTexture = n ;
var selectedUnit = ( TextureUnit ) ( ( int ) TextureUnit . Texture0 + n ) ;
2014-01-30 04:54:02 +00:00
GL . ActiveTexture ( selectedUnit ) ;
}
2015-08-20 23:35:53 +00:00
2020-02-28 18:32:45 +00:00
// now bind the texture
2015-08-20 23:35:53 +00:00
GL . BindTexture ( TextureTarget . Texture2D , ( int ) tex . Opaque ) ;
2014-01-27 00:02:21 +00:00
}
2020-02-28 18:32:45 +00:00
public void TexParameter2d ( Texture2d tex , TextureParameterName pName , int param )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
BindTexture2d ( tex ) ;
2020-02-28 18:32:45 +00:00
GL . TexParameter ( TextureTarget . Texture2D , pName , param ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public Texture2d LoadTexture ( sd . Bitmap bitmap )
2014-01-27 00:02:21 +00:00
{
2020-02-28 17:20:05 +00:00
using var bmp = new BitmapBuffer ( bitmap , new BitmapLoadOptions ( ) ) ;
return ( this as IGL ) . LoadTexture ( bmp ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public Texture2d LoadTexture ( Stream stream )
2014-01-27 00:02:21 +00:00
{
2020-02-28 17:20:05 +00:00
using var bmp = new BitmapBuffer ( stream , new BitmapLoadOptions ( ) ) ;
return ( this as IGL ) . LoadTexture ( bmp ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public Texture2d CreateTexture ( int width , int height )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
int id = GenTexture ( ) ;
return new Texture2d ( this , id , width , height ) ;
2014-01-27 00:02:21 +00:00
}
2014-04-15 21:46:18 +00:00
public Texture2d WrapGLTexture2d ( IntPtr glTexId , int width , int height )
{
2016-02-22 06:23:20 +00:00
return new Texture2d ( this as IGL , glTexId . ToInt32 ( ) , width , height ) ;
2014-04-15 21:46:18 +00:00
}
2014-02-03 05:27:59 +00:00
public void LoadTextureData ( Texture2d tex , BitmapBuffer bmp )
2014-01-27 00:02:21 +00:00
{
2020-02-28 18:32:45 +00:00
sdi . BitmapData bmpData = bmp . LockBits ( ) ;
2014-01-27 00:02:21 +00:00
try
{
2015-08-20 23:35:53 +00:00
GL . BindTexture ( TextureTarget . Texture2D , ( int ) tex . Opaque ) ;
2020-02-28 18:32:45 +00:00
GL . TexSubImage2D ( TextureTarget . Texture2D , 0 , 0 , 0 , bmp . Width , bmp . Height , PixelFormat . Bgra , PixelType . UnsignedByte , bmpData . Scan0 ) ;
2014-01-27 00:02:21 +00:00
}
finally
{
2020-02-28 18:32:45 +00:00
bmp . UnlockBits ( bmpData ) ;
2014-01-27 00:02:21 +00:00
}
}
2014-02-03 05:27:59 +00:00
public void FreeRenderTarget ( RenderTarget rt )
2014-01-28 19:33:49 +00:00
{
rt . Texture2d . Dispose ( ) ;
2015-08-20 23:35:53 +00:00
GL . Ext . DeleteFramebuffer ( ( int ) rt . Opaque ) ;
2014-01-28 19:33:49 +00:00
}
2020-01-01 11:38:41 +00:00
/// <exception cref="InvalidOperationException">framebuffer creation unsuccessful</exception>
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
2020-02-28 18:32:45 +00:00
int texId = GenTexture ( ) ;
Texture2d tex = new Texture2d ( this , texId , w , h ) ;
GL . BindTexture ( TextureTarget . Texture2D , texId ) ;
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 ) ;
2020-02-28 18:32:45 +00:00
// create the FBO
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
2020-02-28 18:32:45 +00:00
GL . Ext . FramebufferTexture2D ( FramebufferTarget . Framebuffer , FramebufferAttachment . ColorAttachment0 , TextureTarget . Texture2D , texId , 0 ) ;
2014-01-27 09:36:18 +00:00
2020-02-28 18:32:45 +00:00
// do something, I guess say which color buffers 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
2020-02-28 18:32:45 +00:00
if ( GL . Ext . CheckFramebufferStatus ( FramebufferTarget . Framebuffer ) ! =
FramebufferErrorCode . FramebufferComplete )
{
2019-03-28 03:17:14 +00:00
throw new InvalidOperationException ( $"Error creating framebuffer (at {nameof(GL.Ext.CheckFramebufferStatus)})" ) ;
2020-02-28 18:32:45 +00:00
}
2014-01-27 09:36:18 +00:00
2020-02-28 18:32:45 +00:00
// 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
2020-02-28 18:32:45 +00:00
return new RenderTarget ( this , fbId , tex ) ;
2014-01-27 09:36:18 +00:00
}
2014-02-03 05:27:59 +00:00
public void BindRenderTarget ( RenderTarget rt )
2014-01-27 09:36:18 +00:00
{
2020-02-28 18:32:45 +00:00
_currRenderTarget = rt ;
if ( rt = = null )
{
2014-02-03 08:04:11 +00:00
GL . Ext . BindFramebuffer ( FramebufferTarget . Framebuffer , 0 ) ;
2020-02-28 18:32:45 +00:00
}
2014-01-27 09:36:18 +00:00
else
2020-02-28 18:32:45 +00:00
{
2015-08-20 23:35:53 +00:00
GL . Ext . BindFramebuffer ( FramebufferTarget . Framebuffer , ( int ) rt . Opaque ) ;
2020-02-28 18:32:45 +00:00
}
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 ;
2015-08-20 23:35:53 +00:00
int id = GenTexture ( ) ;
2014-01-27 00:02:21 +00:00
try
{
2015-08-20 23:35:53 +00:00
ret = new Texture2d ( this , id , bmp . Width , bmp . Height ) ;
GL . BindTexture ( TextureTarget . Texture2D , id ) ;
2014-01-27 00:02:21 +00:00
//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
{
2015-08-20 23:35:53 +00:00
GL . DeleteTexture ( id ) ;
2014-01-27 00:02:21 +00:00
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 ) ;
2016-02-22 06:23:20 +00:00
var err = GL . GetError ( ) ;
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
{
2020-02-28 17:20:05 +00:00
using var fs = new FileStream ( path , FileMode . Open , FileAccess . Read , FileShare . Read ) ;
return ( this as IGL ) . LoadTexture ( fs ) ;
2014-01-27 00:02:21 +00:00
}
2014-02-03 05:27:59 +00:00
public Matrix4 CreateGuiProjectionMatrix ( int w , int h )
{
return CreateGuiProjectionMatrix ( new sd . Size ( w , h ) ) ;
}
2015-08-20 23:35:53 +00:00
public Matrix4 CreateGuiViewMatrix ( int w , int h , bool autoflip )
2014-02-03 05:27:59 +00:00
{
2015-08-20 23:35:53 +00:00
return CreateGuiViewMatrix ( new sd . Size ( w , h ) , autoflip ) ;
2014-02-03 05:27:59 +00:00
}
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 ;
}
2015-08-20 23:35:53 +00:00
public Matrix4 CreateGuiViewMatrix ( sd . Size dims , bool autoflip )
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 ;
2015-08-20 23:35:53 +00:00
ret . M41 = - ( float ) dims . Width * 0.5f ;
ret . M42 = ( float ) dims . Height * 0.5f ;
if ( autoflip )
{
2020-02-28 18:32:45 +00:00
if ( _currRenderTarget = = null ) { }
2015-08-20 23:35:53 +00:00
else
{
//flip as long as we're not a final render target
ret . M22 = 1.0f ;
ret . M42 * = - 1 ;
}
}
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
2015-08-20 23:35:53 +00:00
//BUT ALSO: new specifications.. viewport+scissor make sense together
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 ;
}
2015-08-20 23:35:53 +00:00
Shader CreateShader ( bool cg , ShaderType type , string source , string entry , bool required )
2014-01-27 00:02:21 +00:00
{
2015-08-20 23:35:53 +00:00
var sw = new ShaderWrapper ( ) ;
if ( cg )
{
var cgc = new CGC ( ) ;
2015-10-21 02:21:07 +00:00
var results = cgc . Run ( source , entry , type = = ShaderType . FragmentShader ? "glslf" : "glslv" , false ) ;
2017-07-20 22:18:08 +00:00
2015-08-20 23:35:53 +00:00
if ( ! results . Succeeded )
2017-07-20 22:18:08 +00:00
{
Console . WriteLine ( "CGC failed" ) ;
Console . WriteLine ( results . Errors ) ;
2015-08-20 23:35:53 +00:00
return new Shader ( this , null , false ) ;
2017-07-20 22:18:08 +00:00
}
2015-08-20 23:35:53 +00:00
source = results . Code ;
sw . MapCodeToNative = results . MapCodeToNative ;
sw . MapNativeToCode = results . MapNativeToCode ;
}
2014-02-03 07:43:47 +00:00
int sid = GL . CreateShader ( type ) ;
2015-08-20 23:35:53 +00:00
bool ok = CompileShaderSimple ( sid , source , required ) ;
2014-02-03 07:43:47 +00:00
if ( ! ok )
{
GL . DeleteShader ( sid ) ;
sid = 0 ;
}
2014-02-07 02:36:27 +00:00
2015-08-20 23:35:53 +00:00
sw . sid = sid ;
return new Shader ( this , sw , ok ) ;
2014-02-03 07:43:47 +00:00
}
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 ( ) ;
2014-11-06 19:20:03 +00:00
if ( errcode ! = ErrorCode . NoError )
if ( required )
2019-03-20 04:41:19 +00:00
throw new InvalidOperationException ( $"Error compiling shader (from previous operation) {errcode}" ) ;
2014-11-06 19:20:03 +00:00
else success = false ;
2014-02-06 09:45:55 +00:00
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 )
2019-03-28 03:17:14 +00:00
throw new InvalidOperationException ( $"Error compiling shader ({nameof(GL.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 )
2015-08-24 18:36:25 +00:00
{
2019-03-28 03:17:14 +00:00
string message = $"Error compiling shader ({nameof(GL.CompileShader)}) {errcode}\r\n\r\n{resultLog}" ;
2014-02-03 07:43:47 +00:00
if ( required )
2015-08-24 18:36:25 +00:00
throw new InvalidOperationException ( message ) ;
else
{
Console . WriteLine ( message ) ;
success = false ;
}
}
2014-01-27 18:30:28 +00:00
2020-02-25 19:15:43 +00:00
GL . GetShader ( sid , ShaderParameter . CompileStatus , out var n ) ;
2014-01-27 18:30:28 +00:00
2014-02-03 07:43:47 +00:00
if ( n = = 0 )
if ( required )
2019-03-28 03:17:14 +00:00
throw new InvalidOperationException ( $"Error compiling shader ({nameof(GL.GetShader)})\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 ;
2015-08-20 23:35:53 +00:00
//disable all the client states.. a lot of overhead right now, to be sure
GL . DisableClientState ( ArrayCap . VertexArray ) ;
GL . DisableClientState ( ArrayCap . ColorArray ) ;
for ( int i = 0 ; i < 8 ; i + + )
GL . DisableVertexAttribArray ( i ) ;
for ( int i = 0 ; i < 8 ; i + + )
{
GL . ClientActiveTexture ( TextureUnit . Texture0 + i ) ;
GL . DisableClientState ( ArrayCap . TextureCoordArray ) ;
}
GL . ClientActiveTexture ( TextureUnit . Texture0 ) ;
2014-01-27 00:02:21 +00:00
foreach ( var kvp in layout . Items )
{
2020-02-28 18:32:45 +00:00
if ( _currPipeline . Memo = = "gui" )
2015-08-20 23:35:53 +00:00
{
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 ) ;
}
else
{
2020-02-28 18:32:45 +00:00
var pw = _currPipeline . Opaque as PipelineWrapper ;
2015-08-20 23:35:53 +00:00
//comment SNACKPANTS
switch ( kvp . Value . Usage )
{
case AttributeUsage . Position :
GL . EnableClientState ( ArrayCap . VertexArray ) ;
GL . VertexPointer ( kvp . Value . Components , VertexPointerType . Float , kvp . Value . Stride , new IntPtr ( pData ) + kvp . Value . Offset ) ;
break ;
case AttributeUsage . Texcoord0 :
GL . ClientActiveTexture ( TextureUnit . Texture0 ) ;
GL . EnableClientState ( ArrayCap . TextureCoordArray ) ;
GL . TexCoordPointer ( kvp . Value . Components , TexCoordPointerType . Float , kvp . Value . Stride , new IntPtr ( pData ) + kvp . Value . Offset ) ;
break ;
case AttributeUsage . Texcoord1 :
GL . ClientActiveTexture ( TextureUnit . Texture1 ) ;
GL . EnableClientState ( ArrayCap . TextureCoordArray ) ;
GL . TexCoordPointer ( kvp . Value . Components , TexCoordPointerType . Float , kvp . Value . Stride , new IntPtr ( pData ) + kvp . Value . Offset ) ;
GL . ClientActiveTexture ( TextureUnit . Texture0 ) ;
break ;
case AttributeUsage . Color0 :
break ;
}
}
2014-01-27 00:02:21 +00:00
}
}
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 ( )
{
2015-08-20 23:35:53 +00:00
_rsBlendNoneVerbatim = new CacheBlendState (
2014-12-13 23:04:22 +00:00
false ,
BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ,
BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ) ;
2015-08-20 23:35:53 +00:00
_rsBlendNoneOpaque = new CacheBlendState (
2014-12-13 23:04:22 +00:00
false ,
BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ,
BlendingFactorSrc . ConstantAlpha , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ) ;
2015-08-20 23:35:53 +00:00
_rsBlendNormal = new CacheBlendState (
2014-12-13 23:04:22 +00:00
true ,
2014-01-27 09:45:16 +00:00
BlendingFactorSrc . SrcAlpha , BlendEquationMode . FuncAdd , BlendingFactorDest . OneMinusSrcAlpha ,
2019-02-12 23:17:08 +00:00
BlendingFactorSrc . One , BlendEquationMode . FuncAdd , BlendingFactorDest . Zero ) ;
2014-01-27 00:02:21 +00:00
}
2015-08-20 23:35:53 +00:00
CacheBlendState _rsBlendNoneVerbatim , _rsBlendNoneOpaque , _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
}