WebGLState.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. import {
  2. CullFaceNone, CullFaceBack, CullFaceFront, DoubleSide, BackSide,
  3. NormalBlending, NoBlending, CustomBlending, AddEquation,
  4. AdditiveBlending, SubtractiveBlending, MultiplyBlending, SubtractEquation, ReverseSubtractEquation,
  5. ZeroFactor, OneFactor, SrcColorFactor, SrcAlphaFactor, SrcAlphaSaturateFactor, DstColorFactor, DstAlphaFactor,
  6. OneMinusSrcColorFactor, OneMinusSrcAlphaFactor, OneMinusDstColorFactor, OneMinusDstAlphaFactor,
  7. NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth
  8. } from 'three';
  9. let initialized = false, equationToGL, factorToGL;
  10. class WebGLState {
  11. constructor( backend ) {
  12. this.backend = backend;
  13. this.gl = this.backend.gl;
  14. this.enabled = {};
  15. this.currentFlipSided = null;
  16. this.currentCullFace = null;
  17. this.currentProgram = null;
  18. this.currentBlendingEnabled = null;
  19. this.currentBlending = null;
  20. this.currentBlendSrc = null;
  21. this.currentBlendDst = null;
  22. this.currentBlendSrcAlpha = null;
  23. this.currentBlendDstAlpha = null;
  24. this.currentPremultipledAlpha = null;
  25. this.currentPolygonOffsetFactor = null;
  26. this.currentPolygonOffsetUnits = null;
  27. this.currentDepthFunc = null;
  28. this.currentDepthMask = null;
  29. this.currentStencilFunc = null;
  30. this.currentStencilRef = null;
  31. this.currentStencilFuncMask = null;
  32. this.currentStencilFail = null;
  33. this.currentStencilZFail = null;
  34. this.currentStencilZPass = null;
  35. this.currentStencilMask = null;
  36. if ( initialized === false ) {
  37. this._init( this.gl );
  38. initialized = true;
  39. }
  40. }
  41. _init( gl ) {
  42. // Store only WebGL constants here.
  43. equationToGL = {
  44. [ AddEquation ]: gl.FUNC_ADD,
  45. [ SubtractEquation ]: gl.FUNC_SUBTRACT,
  46. [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
  47. };
  48. factorToGL = {
  49. [ ZeroFactor ]: gl.ZERO,
  50. [ OneFactor ]: gl.ONE,
  51. [ SrcColorFactor ]: gl.SRC_COLOR,
  52. [ SrcAlphaFactor ]: gl.SRC_ALPHA,
  53. [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
  54. [ DstColorFactor ]: gl.DST_COLOR,
  55. [ DstAlphaFactor ]: gl.DST_ALPHA,
  56. [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
  57. [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
  58. [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
  59. [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA
  60. };
  61. }
  62. enable( id ) {
  63. const { enabled } = this;
  64. if ( enabled[ id ] !== true ) {
  65. this.gl.enable( id );
  66. enabled[ id ] = true;
  67. }
  68. }
  69. disable( id ) {
  70. const { enabled } = this;
  71. if ( enabled[ id ] !== false ) {
  72. this.gl.disable( id );
  73. enabled[ id ] = false;
  74. }
  75. }
  76. setFlipSided( flipSided ) {
  77. if ( this.currentFlipSided !== flipSided ) {
  78. const { gl } = this;
  79. if ( flipSided ) {
  80. gl.frontFace( gl.CW );
  81. } else {
  82. gl.frontFace( gl.CCW );
  83. }
  84. this.currentFlipSided = flipSided;
  85. }
  86. }
  87. setCullFace( cullFace ) {
  88. const { gl } = this;
  89. if ( cullFace !== CullFaceNone ) {
  90. this.enable( gl.CULL_FACE );
  91. if ( cullFace !== this.currentCullFace ) {
  92. if ( cullFace === CullFaceBack ) {
  93. gl.cullFace( gl.BACK );
  94. } else if ( cullFace === CullFaceFront ) {
  95. gl.cullFace( gl.FRONT );
  96. } else {
  97. gl.cullFace( gl.FRONT_AND_BACK );
  98. }
  99. }
  100. } else {
  101. this.disable( gl.CULL_FACE );
  102. }
  103. this.currentCullFace = cullFace;
  104. }
  105. setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
  106. const { gl } = this;
  107. if ( blending === NoBlending ) {
  108. if ( this.currentBlendingEnabled === true ) {
  109. this.disable( gl.BLEND );
  110. this.currentBlendingEnabled = false;
  111. }
  112. return;
  113. }
  114. if ( this.currentBlendingEnabled === false ) {
  115. this.enable( gl.BLEND );
  116. this.currentBlendingEnabled = true;
  117. }
  118. if ( blending !== CustomBlending ) {
  119. if ( blending !== this.currentBlending || premultipliedAlpha !== this.currentPremultipledAlpha ) {
  120. if ( this.currentBlendEquation !== AddEquation || this.currentBlendEquationAlpha !== AddEquation ) {
  121. gl.blendEquation( gl.FUNC_ADD );
  122. this.currentBlendEquation = AddEquation;
  123. this.currentBlendEquationAlpha = AddEquation;
  124. }
  125. if ( premultipliedAlpha ) {
  126. switch ( blending ) {
  127. case NormalBlending:
  128. gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
  129. break;
  130. case AdditiveBlending:
  131. gl.blendFunc( gl.ONE, gl.ONE );
  132. break;
  133. case SubtractiveBlending:
  134. gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
  135. break;
  136. case MultiplyBlending:
  137. gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
  138. break;
  139. default:
  140. console.error( 'THREE.WebGLState: Invalid blending: ', blending );
  141. break;
  142. }
  143. } else {
  144. switch ( blending ) {
  145. case NormalBlending:
  146. gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
  147. break;
  148. case AdditiveBlending:
  149. gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
  150. break;
  151. case SubtractiveBlending:
  152. gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
  153. break;
  154. case MultiplyBlending:
  155. gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
  156. break;
  157. default:
  158. console.error( 'THREE.WebGLState: Invalid blending: ', blending );
  159. break;
  160. }
  161. }
  162. this.currentBlendSrc = null;
  163. this.currentBlendDst = null;
  164. this.currentBlendSrcAlpha = null;
  165. this.currentBlendDstAlpha = null;
  166. this.currentBlending = blending;
  167. this.currentPremultipledAlpha = premultipliedAlpha;
  168. }
  169. return;
  170. }
  171. // custom blending
  172. blendEquationAlpha = blendEquationAlpha || blendEquation;
  173. blendSrcAlpha = blendSrcAlpha || blendSrc;
  174. blendDstAlpha = blendDstAlpha || blendDst;
  175. if ( blendEquation !== this.currentBlendEquation || blendEquationAlpha !== this.currentBlendEquationAlpha ) {
  176. gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
  177. this.currentBlendEquation = blendEquation;
  178. this.currentBlendEquationAlpha = blendEquationAlpha;
  179. }
  180. if ( blendSrc !== this.currentBlendSrc || blendDst !== this.currentBlendDst || blendSrcAlpha !== this.currentBlendSrcAlpha || blendDstAlpha !== this.currentBlendDstAlpha ) {
  181. gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
  182. this.currentBlendSrc = blendSrc;
  183. this.currentBlendDst = blendDst;
  184. this.currentBlendSrcAlpha = blendSrcAlpha;
  185. this.currentBlendDstAlpha = blendDstAlpha;
  186. }
  187. this.currentBlending = blending;
  188. this.currentPremultipledAlpha = false;
  189. }
  190. setDepthTest( depthTest ) {
  191. const { gl } = this;
  192. if ( depthTest ) {
  193. this.enable( gl.DEPTH_TEST );
  194. } else {
  195. this.disable( gl.DEPTH_TEST );
  196. }
  197. }
  198. setDepthMask( depthMask ) {
  199. if ( this.currentDepthMask !== depthMask ) {
  200. this.gl.depthMask( depthMask );
  201. this.currentDepthMask = depthMask;
  202. }
  203. }
  204. setDepthFunc( depthFunc ) {
  205. if ( this.currentDepthFunc !== depthFunc ) {
  206. const { gl } = this;
  207. switch ( depthFunc ) {
  208. case NeverDepth:
  209. gl.depthFunc( gl.NEVER );
  210. break;
  211. case AlwaysDepth:
  212. gl.depthFunc( gl.ALWAYS );
  213. break;
  214. case LessDepth:
  215. gl.depthFunc( gl.LESS );
  216. break;
  217. case LessEqualDepth:
  218. gl.depthFunc( gl.LEQUAL );
  219. break;
  220. case EqualDepth:
  221. gl.depthFunc( gl.EQUAL );
  222. break;
  223. case GreaterEqualDepth:
  224. gl.depthFunc( gl.GEQUAL );
  225. break;
  226. case GreaterDepth:
  227. gl.depthFunc( gl.GREATER );
  228. break;
  229. case NotEqualDepth:
  230. gl.depthFunc( gl.NOTEQUAL );
  231. break;
  232. default:
  233. gl.depthFunc( gl.LEQUAL );
  234. }
  235. this.currentDepthFunc = depthFunc;
  236. }
  237. }
  238. setStencilTest( stencilTest ) {
  239. const { gl } = this;
  240. if ( stencilTest ) {
  241. this.enable( gl.STENCIL_TEST );
  242. } else {
  243. this.disable( gl.STENCIL_TEST );
  244. }
  245. }
  246. setStencilMask( stencilMask ) {
  247. if ( this.currentStencilMask !== stencilMask ) {
  248. this.gl.stencilMask( stencilMask );
  249. this.currentStencilMask = stencilMask;
  250. }
  251. }
  252. setStencilFunc( stencilFunc, stencilRef, stencilMask ) {
  253. if ( this.currentStencilFunc !== stencilFunc ||
  254. this.currentStencilRef !== stencilRef ||
  255. this.currentStencilFuncMask !== stencilMask ) {
  256. this.gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
  257. this.currentStencilFunc = stencilFunc;
  258. this.currentStencilRef = stencilRef;
  259. this.currentStencilFuncMask = stencilMask;
  260. }
  261. }
  262. setStencilOp( stencilFail, stencilZFail, stencilZPass ) {
  263. if ( this.currentStencilFail !== stencilFail ||
  264. this.currentStencilZFail !== stencilZFail ||
  265. this.currentStencilZPass !== stencilZPass ) {
  266. this.gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
  267. this.currentStencilFail = stencilFail;
  268. this.currentStencilZFail = stencilZFail;
  269. this.currentStencilZPass = stencilZPass;
  270. }
  271. }
  272. setMaterial( material, frontFaceCW ) {
  273. const { gl } = this;
  274. material.side === DoubleSide
  275. ? this.disable( gl.CULL_FACE )
  276. : this.enable( gl.CULL_FACE );
  277. let flipSided = ( material.side === BackSide );
  278. if ( frontFaceCW ) flipSided = ! flipSided;
  279. this.setFlipSided( flipSided );
  280. ( material.blending === NormalBlending && material.transparent === false )
  281. ? this.setBlending( NoBlending )
  282. : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
  283. this.setDepthFunc( material.depthFunc );
  284. this.setDepthTest( material.depthTest );
  285. this.setDepthMask( material.depthWrite );
  286. this.setDepthMask( material.colorWrite );
  287. const stencilWrite = material.stencilWrite;
  288. this.setStencilTest( stencilWrite );
  289. if ( stencilWrite ) {
  290. this.setStencilMask( material.stencilWriteMask );
  291. this.setStencilFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
  292. this.setStencilOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
  293. }
  294. this.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
  295. material.alphaToCoverage === true
  296. ? this.enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
  297. : this.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
  298. }
  299. setPolygonOffset( polygonOffset, factor, units ) {
  300. const { gl } = this;
  301. if ( polygonOffset ) {
  302. this.enable( gl.POLYGON_OFFSET_FILL );
  303. if ( this.currentPolygonOffsetFactor !== factor || this.currentPolygonOffsetUnits !== units ) {
  304. gl.polygonOffset( factor, units );
  305. this.currentPolygonOffsetFactor = factor;
  306. this.currentPolygonOffsetUnits = units;
  307. }
  308. } else {
  309. this.disable( gl.POLYGON_OFFSET_FILL );
  310. }
  311. }
  312. useProgram( program ) {
  313. if ( this.currentProgram !== program ) {
  314. this.gl.useProgram( program );
  315. this.currentProgram = program;
  316. return true;
  317. }
  318. return false;
  319. }
  320. }
  321. export default WebGLState;