123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- Namespace mojo.graphics
- #Import "shaders/@/shaders"
- Internal
- Const A_POSITION:=0
- Const A_TEXCOORD0:=1
- Const A_TEXCOORD1:=2
- Const A_COLOR:=3
- Const A_NORMAL:=4
- Const A_TANGENT:=5
- Const A_WEIGHTS:=6
- Const A_BONES:=7
- Private
- Class GLUniform
- Field name:String
- Field location:Int
- Field texunit:Int
- Field size:Int
- Field type:Int
- Field block:Int
- Field uniformId:Int
- Method New( name:String,location:Int,texunit:Int,size:Int,type:Int )
- Self.name=name
- Self.location=location
- Self.texunit=texunit
- Self.size=size
- Self.type=type
-
- If name.StartsWith( "g_" )
- name=name.Slice( 2 )
- block=0
- Else If name.StartsWith( "r_" )
- name=name.Slice( 2 )
- block=1
- Else If name.StartsWith( "i_" )
- name=name.Slice( 2 )
- block=2
- Else If name.StartsWith( "m_" )
- name=name.Slice( 2 )
- block=3
- Else If name.StartsWith( "x_" )
- name=name.Slice( 2 )
- block=4
- Endif
-
- uniformId=UniformBlock.GetUniformId( name,block )
- End
-
- End
- Class GLProgram
- Field _glprogram:GLuint
- Field _uniforms:=New GLUniform[8][]
- Field _textures:=New GLUniform[8][]
- Field _ublockSeqs:=New Int[8]
- Field _glRetroSeq:Int
- Method New( glprogram:GLuint )
- _glprogram=glprogram
-
- Local uniforms:=New Stack<GLUniform>[8]
- Local textures:=New Stack<GLUniform>[8]
- For Local i:=0 Until 8
- uniforms[i]=New Stack<GLUniform>
- textures[i]=New Stack<GLUniform>
- Next
-
- Local n:Int
- glGetProgramiv( _glprogram,GL_ACTIVE_UNIFORMS,Varptr n )
-
- Local size:Int,type:UInt,length:Int,nameBuf:=New Byte[256],texunit:=0
-
- For Local i:=0 Until n
-
- glGetActiveUniform( _glprogram,i,nameBuf.Length,Varptr length,Varptr size,Varptr type,Cast<GLchar Ptr>( nameBuf.Data ) )
-
- Local name:=String.FromCString( nameBuf.Data )
-
- Local i:=name.Find( "[" )
- If i<>-1
- name=name.Slice( 0,i )
- Endif
-
- Local location:=glGetUniformLocation( _glprogram,name )
- If location=-1 Continue 'IE fix...
-
- Local uniform:=New GLUniform( name,location,texunit,size,type )
-
- uniforms[uniform.block].Push( uniform )
-
- Select type
- Case GL_SAMPLER_2D,GL_SAMPLER_CUBE
- textures[uniform.block].Push( uniform )
- texunit+=1
- End
-
- Next
-
- For Local i:=0 until 8
- _uniforms[i]=uniforms[i].ToArray()
- _textures[i]=textures[i].ToArray()
- _ublockSeqs[i]=-1
- Next
- End
-
- Property GLProgram:GLuint()
-
- Return _glprogram
- End
- Method ValidateUniforms( ublocks:UniformBlock[] )
-
- For Local i:=0 Until 8
- Local ublock:=ublocks[ i ]
-
- If Not ublock Or ublock.Seq=_ublockSeqs[i] Continue
-
- _ublockSeqs[i]=ublock.Seq
-
- For Local u:=Eachin _uniforms[i]
-
- Select u.type
- Case GL_BOOL
- glUniform1i( u.location,ublock.GetInt( u.uniformId ) )
- Case GL_INT
- glUniform1i( u.location,ublock.GetInt( u.uniformId ) )
- Case GL_FLOAT
- glUniform1f( u.location,ublock.GetFloat( u.uniformId ) )
- Case GL_FLOAT_VEC2
- glUniform2fv( u.location,1,ublock.GetVec2fv( u.uniformId ) )
- Case GL_FLOAT_VEC3
- glUniform3fv( u.location,1,ublock.GetVec3fv( u.uniformId ) )
-
- Case GL_FLOAT_VEC4
-
- glUniform4fv( u.location,1,ublock.GetVec4fv( u.uniformId ) )
-
- Case GL_FLOAT_MAT3
-
- glUniformMatrix3fv( u.location,1,False,ublock.GetMat3fv( u.uniformId ) )
-
- Case GL_FLOAT_MAT4
-
- Local size:=u.size
-
- If size>1 size=ublock.GetMat4fArray( u.uniformId ).Length
-
- glUniformMatrix4fv( u.location,size,False,ublock.GetMat4fv( u.uniformId ) )
-
- Case GL_SAMPLER_2D,GL_SAMPLER_CUBE
-
- glUniform1i( u.location,u.texunit )
- End
-
- Next
-
- Next
-
- For Local i:=0 Until 8
-
- If Not _textures[i] Continue
-
- For Local u:=Eachin _textures[i]
-
- Local tex:=ublocks[i].GetTexture( u.uniformId )
- If Not tex
- Print( "Can't bind shader texture uniform '"+u.name+"' - no texture!" )
- Continue
- Endif
-
- tex.Bind( u.texunit )
- Next
-
- Next
-
- glActiveTexture( GL_TEXTURE0 )
-
- End
-
- End
- Public
- #rem monkeydoc The Shader class.
- #end
- Class Shader
- #rem monkeydoc Creates a new shader.
- #end
- Method New( name:String,source:String,defs:String )
-
- _name=name
- _source=source
-
- For Local def:=Eachin defs.Replace( ";","~n" ).Split( "~n" )
-
- def=def.Trim()
- If Not def Continue
- if Not def.Contains( " " ) def+=" 1"
-
- _defs+="#define "+def+"~n"
- Next
-
- EnumPasses()
- End
-
- #rem monkeydoc The shader name.
- #end
- Property Name:String()
-
- Return _name
- End
-
- #rem monkeydoc The shader source code.
- #end
- Property Source:String()
-
- Return _source
- End
-
- #rem monkeydoc The renderpasses the shader is valid for.
- #end
- Property RenderPasses:Int[]()
-
- Return _rpasses
- End
-
- #rem monkeydoc Renderpass bitmask.
- #end
- Property RenderPassMask:Int()
-
- Return _rpassMask
- End
-
- #rem monkeydoc Shader global uniforms.
- #end
- Property Uniforms:UniformBlock()
-
- If Not _uniforms _uniforms=New UniformBlock( 0 )
-
- Return _uniforms
- End
-
- '***** INTERNAL *****
-
- #rem monkeydoc @hidden
- #end
- Method Bind( renderPass:Int )
-
- If _glSeq<>glGraphicsSeq
- _glSeq=glGraphicsSeq
- Rebuild()
- Endif
-
- glUseProgram( _programs[renderPass].GLProgram )
- End
-
- #rem monkeydoc @hidden
- #end
- Method ValidateUniforms( renderPass:Int,ublocks:UniformBlock[] )
-
- _programs[renderPass].ValidateUniforms( ublocks )
- End
- #rem monkeydoc Gets a shader with a given name.
- #end
- Function GetShader:Shader( name:String,defs:String="" )
-
- Local tag:=name+";"+defs
-
- If _cache.Contains( tag ) Return _cache[tag]
-
- local source:=LoadString( "asset::shaders/"+name+".glsl" )
-
- Local shader:=source ? New Shader( name,source,defs ) Else Null
-
- _cache[tag]=shader
-
- Return shader
- End
-
- #rem monkeydoc Gets a shader with a given name.
- #end
- Function Open:Shader( name:String,defs:String="" )
-
- Return GetShader( name,defs )
- End
-
- Private
-
- Global _cache:=New StringMap<Shader>
- Field _name:String
- Field _source:String
- Field _defs:String
-
- Field _rpasses:Int[]
- Field _rpassMask:Int
- Field _uniforms:UniformBlock
-
- Field _programs:=New GLProgram[32]
- Field _glSeq:Int
-
- Method EnumPasses()
- Local tag:="//@renderpasses"
- Local tagi:=_source.Find( tag )
- If tagi=-1
- Print "Shader source:~n"+_source
- RuntimeError( "Can't find '"+tag+"' tag" )
- Endif
- tagi+=tag.Length
- Local tage:=_source.Find( "~n",tagi )
- If tage=-1 tage=_source.Length
- Local tagv:=_source.Slice( tagi,tage )
- Local rpasses:=tagv.Split( "," )
- If Not rpasses
- Print "Shader source:~n"+_source
- RuntimeError( "Invalid renderpasses value: '"+tagv+"'" )
- Endif
- _rpasses=New Int[rpasses.Length]
- For Local i:=0 Until rpasses.Length
- _rpasses[i]=Int( rpasses[i] )
- _rpassMask|=(1 Shl _rpasses[i])
- Next
-
- End
-
- 'Find common/vertex/fragment chunks
- '
- Method SplitSource:String[]( source:String )
-
- Local i0:=source.Find( "~n//@vertex" )
- If i0=-1
- Print "Shader source:~n"+source
- RuntimeError( "Can't find //@vertex chunk" )
- Endif
-
- Local i1:=source.Find( "~n//@fragment",i0+1 )
- If i1=-1
- Print "Shader source:~n"+source
- RuntimeError( "Can't find //@fragment chunk" )
- Endif
-
- Local cs:=source.Slice( 0,i0 )+"~n"
- Local vs:=source.Slice( i0,i1 )+"~n"
- Local fs:=source.Slice( i1 )+"~n"
-
- Local chunks:=New String[3]
-
- 'Find //@imports in common section
-
- i0=0
-
- Repeat
- i0=cs.Find( "~n//@import",i0 )
- If i0=-1 Exit
-
- Local i1:=cs.Find( "~n",i0+1 )
- If i1=-1 RuntimeError( "Malformed @import directive in shader" )
-
- Local f:=cs.Slice( i0+11,i1 ).Trim()
- i0=i1
-
- If Not f.StartsWith( "~q" ) Or Not f.EndsWith( "~q" )
- RuntimeError( "Malformed @import directive in shader" )
- Exit
- Endif
-
- f=f.Slice(1,-1)
- Local path:="asset::shaders/imports/"+f+".glsl"
- Local src:=LoadString( path )
- Assert( src,"Can't import shader from "+path )
-
- Local tchunks:=SplitSource( src )
-
- chunks[0]+=tchunks[0]
- chunks[1]+=tchunks[1]
- chunks[2]+=tchunks[2]
-
- ' Print "Imported "+f
-
- Forever
-
- chunks[0]+=cs
- chunks[1]+=vs
- chunks[2]+=fs
-
- Return chunks
- End
-
- Method Rebuild()
-
- glCheck()
-
- Local chunks:=SplitSource( _source )
-
- Local cs:=_defs+chunks[0]
- Local vs:=cs+chunks[1]
- Local fs:=cs+chunks[2]
-
- For Local rpass:=Eachin _rpasses
-
- Local defs:="#define MX2_RENDERPASS "+rpass+"~n"
-
- ' Print "~n~n*************** Vertex Shader ***************~n"+defs+vs
- ' Print "~n~n*************** Fragment Shader ****************~n"+defs+fs
-
- Local vshader:=glCompile( GL_VERTEX_SHADER,defs+vs )
- Local fshader:=glCompile( GL_FRAGMENT_SHADER,defs+fs )
-
- Local glprogram:=glCreateProgram()
-
- glAttachShader( glprogram,vshader )
- glAttachShader( glprogram,fshader )
- glDeleteShader( vshader )
- glDeleteShader( fshader )
-
- glBindAttribLocation( glprogram,A_POSITION,"a_Position" )
- glBindAttribLocation( glprogram,A_TEXCOORD0,"a_TexCoord0" )
- glBindAttribLocation( glprogram,A_TEXCOORD1,"a_TexCoord1" )
- glBindAttribLocation( glprogram,A_COLOR,"a_Color" )
- glBindAttribLocation( glprogram,A_NORMAL,"a_Normal" )
- glBindAttribLocation( glprogram,A_TANGENT,"a_Tangent" )
- glBindAttribLocation( glprogram,A_WEIGHTS,"a_Weights" )
- glBindAttribLocation( glprogram,A_BONES,"a_Bones" )
-
- glLink( glprogram )
-
- Local program:=New GLProgram( glprogram )
-
- _programs[rpass]=program
- Next
-
- glCheck()
- End
- End
|