2
0

shader.monkey2 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. Namespace mojo.graphics
  2. #Import "shaders/@/shaders"
  3. Internal
  4. Const A_POSITION:=0
  5. Const A_TEXCOORD0:=1
  6. Const A_TEXCOORD1:=2
  7. Const A_COLOR:=3
  8. Const A_NORMAL:=4
  9. Const A_TANGENT:=5
  10. Const A_WEIGHTS:=6
  11. Const A_BONES:=7
  12. Private
  13. Class GLUniform
  14. Field name:String
  15. Field location:Int
  16. Field texunit:Int
  17. Field size:Int
  18. Field type:Int
  19. Field block:Int
  20. Field uniformId:Int
  21. Method New( name:String,location:Int,texunit:Int,size:Int,type:Int )
  22. Self.name=name
  23. Self.location=location
  24. Self.texunit=texunit
  25. Self.size=size
  26. Self.type=type
  27. If name.StartsWith( "g_" )
  28. name=name.Slice( 2 )
  29. block=0
  30. Else If name.StartsWith( "r_" )
  31. name=name.Slice( 2 )
  32. block=1
  33. Else If name.StartsWith( "i_" )
  34. name=name.Slice( 2 )
  35. block=2
  36. Else If name.StartsWith( "m_" )
  37. name=name.Slice( 2 )
  38. block=3
  39. Else If name.StartsWith( "x_" )
  40. name=name.Slice( 2 )
  41. block=4
  42. Endif
  43. uniformId=UniformBlock.GetUniformId( name,block )
  44. End
  45. End
  46. Class GLProgram
  47. Field _glprogram:GLuint
  48. Field _uniforms:=New GLUniform[8][]
  49. Field _textures:=New GLUniform[8][]
  50. Field _ublockSeqs:=New Int[8]
  51. Field _glRetroSeq:Int
  52. Method New( glprogram:GLuint )
  53. _glprogram=glprogram
  54. Local uniforms:=New Stack<GLUniform>[8]
  55. Local textures:=New Stack<GLUniform>[8]
  56. For Local i:=0 Until 8
  57. uniforms[i]=New Stack<GLUniform>
  58. textures[i]=New Stack<GLUniform>
  59. Next
  60. Local n:Int
  61. glGetProgramiv( _glprogram,GL_ACTIVE_UNIFORMS,Varptr n )
  62. Local size:Int,type:UInt,length:Int,nameBuf:=New Byte[256],texunit:=0
  63. For Local i:=0 Until n
  64. glGetActiveUniform( _glprogram,i,nameBuf.Length,Varptr length,Varptr size,Varptr type,Cast<GLchar Ptr>( nameBuf.Data ) )
  65. Local name:=String.FromCString( nameBuf.Data )
  66. Local i:=name.Find( "[" )
  67. If i<>-1
  68. name=name.Slice( 0,i )
  69. Endif
  70. Local location:=glGetUniformLocation( _glprogram,name )
  71. If location=-1 Continue 'IE fix...
  72. Local uniform:=New GLUniform( name,location,texunit,size,type )
  73. uniforms[uniform.block].Push( uniform )
  74. Select type
  75. Case GL_SAMPLER_2D,GL_SAMPLER_CUBE
  76. textures[uniform.block].Push( uniform )
  77. texunit+=1
  78. End
  79. Next
  80. For Local i:=0 until 8
  81. _uniforms[i]=uniforms[i].ToArray()
  82. _textures[i]=textures[i].ToArray()
  83. _ublockSeqs[i]=-1
  84. Next
  85. End
  86. Property GLProgram:GLuint()
  87. Return _glprogram
  88. End
  89. Method ValidateUniforms( ublocks:UniformBlock[] )
  90. For Local i:=0 Until 8
  91. Local ublock:=ublocks[ i ]
  92. If Not ublock Or ublock.Seq=_ublockSeqs[i] Continue
  93. _ublockSeqs[i]=ublock.Seq
  94. For Local u:=Eachin _uniforms[i]
  95. Select u.type
  96. Case GL_INT
  97. glUniform1i( u.location,ublock.GetInt( u.uniformId ) )
  98. Case GL_FLOAT
  99. glUniform1f( u.location,ublock.GetFloat( u.uniformId ) )
  100. Case GL_FLOAT_VEC2
  101. glUniform2fv( u.location,1,ublock.GetVec2fv( u.uniformId ) )
  102. Case GL_FLOAT_VEC3
  103. glUniform3fv( u.location,1,ublock.GetVec3fv( u.uniformId ) )
  104. Case GL_FLOAT_VEC4
  105. glUniform4fv( u.location,1,ublock.GetVec4fv( u.uniformId ) )
  106. Case GL_FLOAT_MAT3
  107. glUniformMatrix3fv( u.location,1,False,ublock.GetMat3fv( u.uniformId ) )
  108. Case GL_FLOAT_MAT4
  109. Local size:=u.size
  110. If size>1 size=ublock.GetMat4fArray( u.uniformId ).Length
  111. glUniformMatrix4fv( u.location,size,False,ublock.GetMat4fv( u.uniformId ) )
  112. Case GL_SAMPLER_2D,GL_SAMPLER_CUBE
  113. glUniform1i( u.location,u.texunit )
  114. End
  115. Next
  116. Next
  117. For Local i:=0 Until 8
  118. If Not _textures[i] Continue
  119. For Local u:=Eachin _textures[i]
  120. Local tex:=ublocks[i].GetTexture( u.uniformId )
  121. If Not tex
  122. Print( "Can't bind shader texture uniform '"+u.name+"' - no texture!" )
  123. Continue
  124. Endif
  125. tex.Bind( u.texunit )
  126. Next
  127. Next
  128. glActiveTexture( GL_TEXTURE0 )
  129. End
  130. End
  131. Public
  132. #rem monkeydoc The Shader class.
  133. #end
  134. Class Shader
  135. #rem monkeydoc Creates a new shader.
  136. #end
  137. Method New( name:String,source:String,defs:String )
  138. _name=name
  139. _source=source
  140. For Local def:=Eachin defs.Replace( ";","~n" ).Split( "~n" )
  141. def=def.Trim()
  142. If Not def Continue
  143. if Not def.Contains( " " ) def+=" 1"
  144. _defs+="#define "+def+"~n"
  145. Next
  146. EnumPasses()
  147. End
  148. #rem monkeydoc The shader name.
  149. #end
  150. Property Name:String()
  151. Return _name
  152. End
  153. #rem monkeydoc The shader source code.
  154. #end
  155. Property Source:String()
  156. Return _source
  157. End
  158. #rem monkeydoc The renderpasses the shader is valid for.
  159. #end
  160. Property RenderPasses:Int[]()
  161. Return _rpasses
  162. End
  163. #rem monkeydoc Renderpass bitmask.
  164. #end
  165. Property RenderPassMask:Int()
  166. Return _rpassMask
  167. End
  168. #rem monkeydoc Shader global uniforms.
  169. #end
  170. Property Uniforms:UniformBlock()
  171. If Not _uniforms _uniforms=New UniformBlock( 0 )
  172. Return _uniforms
  173. End
  174. '***** INTERNAL *****
  175. #rem monkeydoc @hidden
  176. #end
  177. Method Bind( renderPass:Int )
  178. If _glSeq<>glGraphicsSeq
  179. _glSeq=glGraphicsSeq
  180. Rebuild()
  181. Endif
  182. glUseProgram( _programs[renderPass].GLProgram )
  183. End
  184. #rem monkeydoc @hidden
  185. #end
  186. Method ValidateUniforms( renderPass:Int,ublocks:UniformBlock[] )
  187. _programs[renderPass].ValidateUniforms( ublocks )
  188. End
  189. #rem monkeydoc Gets a shader with a given name.
  190. #end
  191. Function GetShader:Shader( name:String,defs:String="" )
  192. Local tag:=name+";"+defs
  193. If _cache.Contains( tag ) Return _cache[tag]
  194. local source:=LoadString( "asset::shaders/"+name+".glsl" )
  195. Local shader:=source ? New Shader( name,source,defs ) Else Null
  196. _cache[tag]=shader
  197. Return shader
  198. End
  199. #rem monkeydoc Gets a shader with a given name.
  200. #end
  201. Function Open:Shader( name:String,defs:String="" )
  202. Return GetShader( name,defs )
  203. End
  204. Private
  205. Global _cache:=New StringMap<Shader>
  206. Field _name:String
  207. Field _source:String
  208. Field _defs:String
  209. Field _rpasses:Int[]
  210. Field _rpassMask:Int
  211. Field _uniforms:UniformBlock
  212. Field _programs:=New GLProgram[32]
  213. Field _glSeq:Int
  214. Method EnumPasses()
  215. Local tag:="//@renderpasses"
  216. Local tagi:=_source.Find( tag )
  217. If tagi=-1
  218. Print "Shader source:~n"+_source
  219. RuntimeError( "Can't find '"+tag+"' tag" )
  220. Endif
  221. tagi+=tag.Length
  222. Local tage:=_source.Find( "~n",tagi )
  223. If tage=-1 tage=_source.Length
  224. Local tagv:=_source.Slice( tagi,tage )
  225. Local rpasses:=tagv.Split( "," )
  226. If Not rpasses
  227. Print "Shader source:~n"+_source
  228. RuntimeError( "Invalid renderpasses value: '"+tagv+"'" )
  229. Endif
  230. _rpasses=New Int[rpasses.Length]
  231. For Local i:=0 Until rpasses.Length
  232. _rpasses[i]=Int( rpasses[i] )
  233. _rpassMask|=(1 Shl _rpasses[i])
  234. Next
  235. End
  236. 'Find common/vertex/fragment chunks
  237. '
  238. Method SplitSource:String[]( source:String )
  239. Local i0:=_source.Find( "~n//@vertex" )
  240. If i0=-1
  241. Print "Shader source:~n"+source
  242. Assert( False,"Can't find //@vertex chunk" )
  243. Endif
  244. Local i1:=source.Find( "~n//@fragment" )
  245. If i1=-1
  246. Print "Shader source:~n"+source
  247. Assert( False,"Can't find //@fragment chunk" )
  248. Endif
  249. Local cs:=source.Slice( 0,i0 )+"~n"
  250. Local vs:=source.Slice( i0,i1 )+"~n"
  251. Local fs:=source.Slice( i1 )+"~n"
  252. Local chunks:=New String[3]
  253. 'Find //@imports in common section
  254. Repeat
  255. Local i:=cs.Find( "~n//@import" )
  256. If i=-1 Exit
  257. Local p:=cs.Slice( 10 ).Trim()
  258. If Not p.StartsWith( "~q" ) Or Not p.EndsWith( "~q" )
  259. Exit
  260. Endif
  261. p=p.Slice(1,-1)
  262. Local s:=LoadString( "asset::shaders/"+p )
  263. If Not s Exit
  264. Local tchunks:=SplitSource( s )
  265. chunks[0]+=tchunks[0]
  266. chunks[1]+=tchunks[1]
  267. chunks[2]+=tchunks[2]
  268. Forever
  269. chunks[0]+=cs
  270. chunks[1]+=vs
  271. chunks[2]+=fs
  272. Return chunks
  273. End
  274. Method Rebuild()
  275. glCheck()
  276. Local chunks:=SplitSource( _source )
  277. Local cs:=_defs+chunks[0]
  278. Local vs:=cs+chunks[1]
  279. Local fs:=cs+chunks[2]
  280. For Local rpass:=Eachin _rpasses
  281. Local defs:="#define MX2_RENDERPASS "+rpass+"~n"
  282. Local vshader:=glCompile( GL_VERTEX_SHADER,defs+vs )
  283. Local fshader:=glCompile( GL_FRAGMENT_SHADER,defs+fs )
  284. Local glprogram:=glCreateProgram()
  285. glAttachShader( glprogram,vshader )
  286. glAttachShader( glprogram,fshader )
  287. glDeleteShader( vshader )
  288. glDeleteShader( fshader )
  289. glBindAttribLocation( glprogram,A_POSITION,"a_Position" )
  290. glBindAttribLocation( glprogram,A_TEXCOORD0,"a_TexCoord0" )
  291. glBindAttribLocation( glprogram,A_TEXCOORD1,"a_TexCoord1" )
  292. glBindAttribLocation( glprogram,A_COLOR,"a_Color" )
  293. glBindAttribLocation( glprogram,A_NORMAL,"a_Normal" )
  294. glBindAttribLocation( glprogram,A_TANGENT,"a_Tangent" )
  295. glBindAttribLocation( glprogram,A_WEIGHTS,"a_Weights" )
  296. glBindAttribLocation( glprogram,A_BONES,"a_Bones" )
  297. glLink( glprogram )
  298. Local program:=New GLProgram( glprogram )
  299. _programs[rpass]=program
  300. Next
  301. glCheck()
  302. End
  303. End