shader.monkey2 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. Namespace mojo.graphics
  2. #Import "shaders/@/shaders"
  3. Private
  4. Class GLUniform
  5. Field name:String
  6. Field location:Int
  7. Field texunit:Int
  8. Field size:Int
  9. Field type:Int
  10. Field uniformId:Int
  11. Field blockId:Int
  12. Method New( name:String,location:Int,texunit:Int,size:Int,type:Int )
  13. Self.name=name
  14. Self.location=location
  15. Self.texunit=texunit
  16. Self.size=size
  17. Self.type=type
  18. Self.uniformId=UniformBlock.GetUniformId( name )
  19. Self.blockId=UniformBlock.GetUniformBlockId( name )
  20. End
  21. End
  22. Class GLProgram
  23. Field _glprogram:GLuint
  24. Field _uniforms:=New GLUniform[4][]
  25. Field _textures:=New GLUniform[4][]
  26. Field _ublockSeqs:=New Int[4]
  27. Method New( glprogram:GLuint )
  28. _glprogram=glprogram
  29. Local uniforms:=New Stack<GLUniform>[4]
  30. Local textures:=New Stack<GLUniform>[4]
  31. For Local i:=0 Until 4
  32. uniforms[i]=New Stack<GLUniform>
  33. textures[i]=New Stack<GLUniform>
  34. Next
  35. Local n:Int
  36. glGetProgramiv( _glprogram,GL_ACTIVE_UNIFORMS,Varptr n )
  37. Local size:Int,type:UInt,length:Int,nameBuf:=New Byte[256],texunit:=0
  38. For Local i:=0 Until n
  39. glGetActiveUniform( _glprogram,i,nameBuf.Length,Varptr length,Varptr size,Varptr type,Cast<GLchar Ptr>( nameBuf.Data ) )
  40. Local name:=String.FromCString( nameBuf.Data )
  41. Local location:=glGetUniformLocation( _glprogram,name )
  42. If location=-1 Continue 'IE fix...
  43. Local uniform:=New GLUniform( name,location,texunit,size,type )
  44. uniforms[uniform.blockId].Push( uniform )
  45. Select type
  46. Case GL_SAMPLER_2D
  47. textures[uniform.blockId].Push( uniform )
  48. texunit+=1
  49. End
  50. Next
  51. For Local i:=0 Until 4
  52. _uniforms[i]=uniforms[i].ToArray()
  53. _textures[i]=textures[i].ToArray()
  54. _ublockSeqs[i]=-1
  55. Next
  56. End
  57. Property GLProgram:GLuint()
  58. Return _glprogram
  59. End
  60. Method ValidateUniforms( ublocks:UniformBlock[],textureFilter:TextureFilter )
  61. For Local i:=0 Until 4
  62. Local ublock:=ublocks[ i ]
  63. If Not ublock Or ublock.Seq=_ublockSeqs[i] Continue
  64. _ublockSeqs[i]=ublock.Seq
  65. For Local u:=Eachin _uniforms[i]
  66. Select u.type
  67. Case GL_FLOAT
  68. glUniform1f( u.location,ublock.GetScalar( u.uniformId ) )
  69. Case GL_FLOAT_VEC2
  70. glUniform2fv( u.location,1,ublock.GetVector4fv( u.uniformId ) )
  71. Case GL_FLOAT_VEC3
  72. glUniform3fv( u.location,1,ublock.GetVector4fv( u.uniformId ) )
  73. Case GL_FLOAT_VEC4
  74. glUniform4fv( u.location,1,ublock.GetVector4fv( u.uniformId ) )
  75. Case GL_FLOAT_MAT4
  76. glUniformMatrix4fv( u.location,1,False,ublock.GetMatrix4fv( u.uniformId ) )
  77. Case GL_SAMPLER_2D
  78. glUniform1i( u.location,u.texunit )
  79. End
  80. Next
  81. Next
  82. For Local i:=0 Until 4
  83. If Not _textures[i] Continue
  84. For Local u:=Eachin _textures[i]
  85. Local tex:=ublocks[i].GetTexture( u.uniformId )
  86. If tex
  87. tex.Bind( u.texunit,textureFilter )
  88. Else
  89. Print( "Can't bind shader texture uniform '"+u.name+"' - no texture!" )
  90. Endif
  91. Next
  92. Next
  93. glActiveTexture( GL_TEXTURE0 )
  94. End
  95. End
  96. Public
  97. #rem monkeydoc The Shader class.
  98. #end
  99. Class Shader
  100. #rem monkeydoc Creates a new shader.
  101. #end
  102. Method New( name:String,source:String )
  103. Assert( Not _shaders.Contains( name ),"Shader with name '"+name+"' already exists" )
  104. _shaders[name]=Self
  105. _source=source
  106. EnumPasses()
  107. End
  108. #rem monkeydoc The shader source code.
  109. #end
  110. Property Source:String()
  111. Return _source
  112. End
  113. #rem monkeydoc @hidden The renderpasses the shader is involved in.
  114. #end
  115. Property RenderPasses:Int[]()
  116. Return _rpasses
  117. End
  118. #rem monkeydoc @hidden Renderpass bitmask.
  119. #end
  120. Property RenderPassMask:Int()
  121. Return _rpassMask
  122. End
  123. '***** INTERNAL *****
  124. #rem monkeydoc @hidden
  125. #end
  126. Method Bind( renderPass:Int )
  127. If _seq<>glGraphicsSeq
  128. _seq=glGraphicsSeq
  129. Rebuild()
  130. Endif
  131. glUseProgram( _programs[renderPass].GLProgram )
  132. End
  133. #rem monkeydoc @hidden
  134. #end
  135. Method ValidateUniforms( renderPass:Int,ublocks:UniformBlock[],textureFilter:TextureFilter )
  136. _programs[renderPass].ValidateUniforms( ublocks,textureFilter )
  137. End
  138. #rem monkeydoc Gets a shader with a given name.
  139. #end
  140. Function GetShader:Shader( name:String )
  141. Local shader:=_shaders[name]
  142. If shader Return shader
  143. Local source:=LoadString( "asset::shaders/"+name+".glsl" )
  144. If Not source Return Null
  145. Return New Shader( name,source )
  146. End
  147. Private
  148. Global _shaders:=New StringMap<Shader>
  149. Field _source:String
  150. Field _rpasses:Int[]
  151. Field _rpassMask:Int
  152. Field _programs:=New GLProgram[8]
  153. Field _seq:Int
  154. Method EnumPasses()
  155. Local tag:="//@renderpasses"
  156. Local tagi:=_source.Find( tag )
  157. If tagi=-1
  158. Print "Shader source:~n"+_source
  159. RuntimeError( "Can't find '"+tag+"' tag" )
  160. Endif
  161. tagi+=tag.Length
  162. Local tage:=_source.Find( "~n",tagi )
  163. If tage=-1 tage=_source.Length
  164. Local tagv:=_source.Slice( tagi,tage )
  165. Local rpasses:=tagv.Split( "," )
  166. If Not rpasses
  167. Print "Shader source:~n"+_source
  168. RuntimeError( "Invalid renderpasses value: '"+tagv+"'" )
  169. Endif
  170. _rpasses=New Int[rpasses.Length]
  171. For Local i:=0 Until rpasses.Length
  172. _rpasses[i]=Int( rpasses[i] )
  173. _rpassMask|=(1 Shl _rpasses[i])
  174. Next
  175. End
  176. Method Rebuild()
  177. 'Get renderpasses
  178. '
  179. Local tag:="//@renderpasses"
  180. Local tagi:=_source.Find( tag )
  181. If tagi=-1
  182. Print "Shader source:~n"+_source
  183. RuntimeError( "Can't find '"+tag+"' tag" )
  184. Endif
  185. tagi+=tag.Length
  186. Local tage:=_source.Find( "~n",tagi )
  187. If tage=-1 tage=_source.Length
  188. Local tagv:=_source.Slice( tagi,tage )
  189. Local rpasses:=tagv.Split( "," )
  190. If Not rpasses
  191. Print "Shader source:~n"+_source
  192. RuntimeError( "Invalid renderpasses value: '"+tagv+"'" )
  193. Endif
  194. _rpasses=New Int[rpasses.Length]
  195. For Local i:=0 Until rpasses.Length
  196. _rpasses[i]=Int( rpasses[i] )
  197. _rpassMask|=(1 Shl _rpasses[i])
  198. Next
  199. 'Find vertex/fragment chunks
  200. '
  201. Local i0:=_source.Find( "//@vertex" )
  202. If i0=-1
  203. Print "Shader source:~n"+_source
  204. Assert( False,"Can't find //@vertex chunk" )
  205. Endif
  206. Local i1:=_source.Find( "//@fragment" )
  207. If i1=-1
  208. Print "Shader source:~n"+_source
  209. Assert( False,"Can't find //@fragment chunk" )
  210. Endif
  211. Local cs:=_source.Slice( 0,i0 )+"~n"
  212. Local vs:=cs+_source.Slice( i0,i1 )+"~n"
  213. Local fs:=cs+_source.Slice( i1 )+"~n"
  214. For Local rpass:=Eachin _rpasses
  215. Local defs:="#define MX2_RENDERPASS "+rpass+"~n"
  216. Local vshader:=glCompile( GL_VERTEX_SHADER,defs+vs )
  217. Local fshader:=glCompile( GL_FRAGMENT_SHADER,defs+fs )
  218. Local glprogram:=glCreateProgram()
  219. glAttachShader( glprogram,vshader )
  220. glAttachShader( glprogram,fshader )
  221. glDeleteShader( vshader )
  222. glDeleteShader( fshader )
  223. glBindAttribLocation( glprogram,0,"mx2_Vertex" )
  224. glBindAttribLocation( glprogram,1,"mx2_TexCoord0" )
  225. glBindAttribLocation( glprogram,2,"mx2_TexCoord1" )
  226. glBindAttribLocation( glprogram,3,"mx2_Color" )
  227. glLink( glprogram )
  228. Local program:=New GLProgram( glprogram )
  229. _programs[rpass]=program
  230. Next
  231. End
  232. End