WebGLState.js 11 KB

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