shader.monkey2 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. _name=name
  105. _source=source
  106. _shaders[name]=Self
  107. EnumPasses()
  108. End
  109. #rem monkeydoc The shader name.
  110. #end
  111. Property Name:String()
  112. Return _name
  113. End
  114. #rem monkeydoc The shader source code.
  115. #end
  116. Property Source:String()
  117. Return _source
  118. End
  119. #rem monkeydoc @hidden The renderpasses the shader is involved in.
  120. #end
  121. Property RenderPasses:Int[]()
  122. Return _rpasses
  123. End
  124. #rem monkeydoc @hidden Renderpass bitmask.
  125. #end
  126. Property RenderPassMask:Int()
  127. Return _rpassMask
  128. End
  129. '***** INTERNAL *****
  130. #rem monkeydoc @hidden
  131. #end
  132. Method Bind( renderPass:Int )
  133. If _seq<>glGraphicsSeq
  134. _seq=glGraphicsSeq
  135. Rebuild()
  136. Endif
  137. glUseProgram( _programs[renderPass].GLProgram )
  138. End
  139. #rem monkeydoc @hidden
  140. #end
  141. Method ValidateUniforms( renderPass:Int,ublocks:UniformBlock[],textureFilter:TextureFilter )
  142. _programs[renderPass].ValidateUniforms( ublocks,textureFilter )
  143. End
  144. #rem monkeydoc Gets a shader with a given name.
  145. #end
  146. Function GetShader:Shader( name:String )
  147. Local shader:=_shaders[name]
  148. If shader Return shader
  149. Local source:=LoadString( "asset::shaders/"+name+".glsl" )
  150. If Not source Return Null
  151. Return New Shader( name,source )
  152. End
  153. Private
  154. Global _shaders:=New StringMap<Shader>
  155. Field _name:String
  156. Field _source:String
  157. Field _rpasses:Int[]
  158. Field _rpassMask:Int
  159. Field _programs:=New GLProgram[8]
  160. Field _seq:Int
  161. Method EnumPasses()
  162. Local tag:="//@renderpasses"
  163. Local tagi:=_source.Find( tag )
  164. If tagi=-1
  165. Print "Shader source:~n"+_source
  166. RuntimeError( "Can't find '"+tag+"' tag" )
  167. Endif
  168. tagi+=tag.Length
  169. Local tage:=_source.Find( "~n",tagi )
  170. If tage=-1 tage=_source.Length
  171. Local tagv:=_source.Slice( tagi,tage )
  172. Local rpasses:=tagv.Split( "," )
  173. If Not rpasses
  174. Print "Shader source:~n"+_source
  175. RuntimeError( "Invalid renderpasses value: '"+tagv+"'" )
  176. Endif
  177. _rpasses=New Int[rpasses.Length]
  178. For Local i:=0 Until rpasses.Length
  179. _rpasses[i]=Int( rpasses[i] )
  180. _rpassMask|=(1 Shl _rpasses[i])
  181. Next
  182. End
  183. Method Rebuild()
  184. 'Get renderpasses
  185. '
  186. Local tag:="//@renderpasses"
  187. Local tagi:=_source.Find( tag )
  188. If tagi=-1
  189. Print "Shader source:~n"+_source
  190. RuntimeError( "Can't find '"+tag+"' tag" )
  191. Endif
  192. tagi+=tag.Length
  193. Local tage:=_source.Find( "~n",tagi )
  194. If tage=-1 tage=_source.Length
  195. Local tagv:=_source.Slice( tagi,tage )
  196. Local rpasses:=tagv.Split( "," )
  197. If Not rpasses
  198. Print "Shader source:~n"+_source
  199. RuntimeError( "Invalid renderpasses value: '"+tagv+"'" )
  200. Endif
  201. _rpasses=New Int[rpasses.Length]
  202. For Local i:=0 Until rpasses.Length
  203. _rpasses[i]=Int( rpasses[i] )
  204. _rpassMask|=(1 Shl _rpasses[i])
  205. Next
  206. 'Find vertex/fragment chunks
  207. '
  208. Local i0:=_source.Find( "//@vertex" )
  209. If i0=-1
  210. Print "Shader source:~n"+_source
  211. Assert( False,"Can't find //@vertex chunk" )
  212. Endif
  213. Local i1:=_source.Find( "//@fragment" )
  214. If i1=-1
  215. Print "Shader source:~n"+_source
  216. Assert( False,"Can't find //@fragment chunk" )
  217. Endif
  218. Local cs:=_source.Slice( 0,i0 )+"~n"
  219. Local vs:=cs+_source.Slice( i0,i1 )+"~n"
  220. Local fs:=cs+_source.Slice( i1 )+"~n"
  221. For Local rpass:=Eachin _rpasses
  222. Local defs:="#define MX2_RENDERPASS "+rpass+"~n"
  223. Local vshader:=glCompile( GL_VERTEX_SHADER,defs+vs )
  224. Local fshader:=glCompile( GL_FRAGMENT_SHADER,defs+fs )
  225. Local glprogram:=glCreateProgram()
  226. glAttachShader( glprogram,vshader )
  227. glAttachShader( glprogram,fshader )
  228. glDeleteShader( vshader )
  229. glDeleteShader( fshader )
  230. glBindAttribLocation( glprogram,0,"mx2_Vertex" )
  231. glBindAttribLocation( glprogram,1,"mx2_TexCoord0" )
  232. glBindAttribLocation( glprogram,2,"mx2_TexCoord1" )
  233. glBindAttribLocation( glprogram,3,"mx2_Color" )
  234. glLink( glprogram )
  235. Local program:=New GLProgram( glprogram )
  236. _programs[rpass]=program
  237. Next
  238. End
  239. End