WebGLState.js 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceFront, CullFaceBack, CullFaceNone, DoubleSide, BackSide, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NoBlending, NormalBlending, AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation, ZeroFactor, OneFactor, SrcColorFactor, SrcAlphaFactor, SrcAlphaSaturateFactor, DstColorFactor, DstAlphaFactor, OneMinusSrcColorFactor, OneMinusSrcAlphaFactor, OneMinusDstColorFactor, OneMinusDstAlphaFactor, ConstantColorFactor, OneMinusConstantColorFactor, ConstantAlphaFactor, OneMinusConstantAlphaFactor } from '../../constants.js';
  2. import { Color } from '../../math/Color.js';
  3. import { Vector4 } from '../../math/Vector4.js';
  4. function WebGLState( gl, extensions, capabilities ) {
  5. const isWebGL2 = capabilities.isWebGL2;
  6. function ColorBuffer() {
  7. let locked = false;
  8. const color = new Vector4();
  9. let currentColorMask = null;
  10. const currentColorClear = new Vector4( 0, 0, 0, 0 );
  11. return {
  12. setMask: function ( colorMask ) {
  13. if ( currentColorMask !== colorMask && ! locked ) {
  14. gl.colorMask( colorMask, colorMask, colorMask, colorMask );
  15. currentColorMask = colorMask;
  16. }
  17. },
  18. setLocked: function ( lock ) {
  19. locked = lock;
  20. },
  21. setClear: function ( r, g, b, a, premultipliedAlpha ) {
  22. if ( premultipliedAlpha === true ) {
  23. r *= a; g *= a; b *= a;
  24. }
  25. color.set( r, g, b, a );
  26. if ( currentColorClear.equals( color ) === false ) {
  27. gl.clearColor( r, g, b, a );
  28. currentColorClear.copy( color );
  29. }
  30. },
  31. reset: function () {
  32. locked = false;
  33. currentColorMask = null;
  34. currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
  35. }
  36. };
  37. }
  38. function DepthBuffer() {
  39. let locked = false;
  40. let currentDepthMask = null;
  41. let currentDepthFunc = null;
  42. let currentDepthClear = null;
  43. return {
  44. setTest: function ( depthTest ) {
  45. if ( depthTest ) {
  46. enable( gl.DEPTH_TEST );
  47. } else {
  48. disable( gl.DEPTH_TEST );
  49. }
  50. },
  51. setMask: function ( depthMask ) {
  52. if ( currentDepthMask !== depthMask && ! locked ) {
  53. gl.depthMask( depthMask );
  54. currentDepthMask = depthMask;
  55. }
  56. },
  57. setFunc: function ( depthFunc ) {
  58. if ( currentDepthFunc !== depthFunc ) {
  59. switch ( depthFunc ) {
  60. case NeverDepth:
  61. gl.depthFunc( gl.NEVER );
  62. break;
  63. case AlwaysDepth:
  64. gl.depthFunc( gl.ALWAYS );
  65. break;
  66. case LessDepth:
  67. gl.depthFunc( gl.LESS );
  68. break;
  69. case LessEqualDepth:
  70. gl.depthFunc( gl.LEQUAL );
  71. break;
  72. case EqualDepth:
  73. gl.depthFunc( gl.EQUAL );
  74. break;
  75. case GreaterEqualDepth:
  76. gl.depthFunc( gl.GEQUAL );
  77. break;
  78. case GreaterDepth:
  79. gl.depthFunc( gl.GREATER );
  80. break;
  81. case NotEqualDepth:
  82. gl.depthFunc( gl.NOTEQUAL );
  83. break;
  84. default:
  85. gl.depthFunc( gl.LEQUAL );
  86. }
  87. currentDepthFunc = depthFunc;
  88. }
  89. },
  90. setLocked: function ( lock ) {
  91. locked = lock;
  92. },
  93. setClear: function ( depth ) {
  94. if ( currentDepthClear !== depth ) {
  95. gl.clearDepth( depth );
  96. currentDepthClear = depth;
  97. }
  98. },
  99. reset: function () {
  100. locked = false;
  101. currentDepthMask = null;
  102. currentDepthFunc = null;
  103. currentDepthClear = null;
  104. }
  105. };
  106. }
  107. function StencilBuffer() {
  108. let locked = false;
  109. let currentStencilMask = null;
  110. let currentStencilFunc = null;
  111. let currentStencilRef = null;
  112. let currentStencilFuncMask = null;
  113. let currentStencilFail = null;
  114. let currentStencilZFail = null;
  115. let currentStencilZPass = null;
  116. let currentStencilClear = null;
  117. return {
  118. setTest: function ( stencilTest ) {
  119. if ( ! locked ) {
  120. if ( stencilTest ) {
  121. enable( gl.STENCIL_TEST );
  122. } else {
  123. disable( gl.STENCIL_TEST );
  124. }
  125. }
  126. },
  127. setMask: function ( stencilMask ) {
  128. if ( currentStencilMask !== stencilMask && ! locked ) {
  129. gl.stencilMask( stencilMask );
  130. currentStencilMask = stencilMask;
  131. }
  132. },
  133. setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
  134. if ( currentStencilFunc !== stencilFunc ||
  135. currentStencilRef !== stencilRef ||
  136. currentStencilFuncMask !== stencilMask ) {
  137. gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
  138. currentStencilFunc = stencilFunc;
  139. currentStencilRef = stencilRef;
  140. currentStencilFuncMask = stencilMask;
  141. }
  142. },
  143. setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
  144. if ( currentStencilFail !== stencilFail ||
  145. currentStencilZFail !== stencilZFail ||
  146. currentStencilZPass !== stencilZPass ) {
  147. gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
  148. currentStencilFail = stencilFail;
  149. currentStencilZFail = stencilZFail;
  150. currentStencilZPass = stencilZPass;
  151. }
  152. },
  153. setLocked: function ( lock ) {
  154. locked = lock;
  155. },
  156. setClear: function ( stencil ) {
  157. if ( currentStencilClear !== stencil ) {
  158. gl.clearStencil( stencil );
  159. currentStencilClear = stencil;
  160. }
  161. },
  162. reset: function () {
  163. locked = false;
  164. currentStencilMask = null;
  165. currentStencilFunc = null;
  166. currentStencilRef = null;
  167. currentStencilFuncMask = null;
  168. currentStencilFail = null;
  169. currentStencilZFail = null;
  170. currentStencilZPass = null;
  171. currentStencilClear = null;
  172. }
  173. };
  174. }
  175. //
  176. const colorBuffer = new ColorBuffer();
  177. const depthBuffer = new DepthBuffer();
  178. const stencilBuffer = new StencilBuffer();
  179. const uboBindings = new WeakMap();
  180. const uboProgramMap = new WeakMap();
  181. let enabledCapabilities = {};
  182. let currentBoundFramebuffers = {};
  183. let currentDrawbuffers = new WeakMap();
  184. let defaultDrawbuffers = [];
  185. let currentProgram = null;
  186. let currentBlendingEnabled = false;
  187. let currentBlending = null;
  188. let currentBlendEquation = null;
  189. let currentBlendSrc = null;
  190. let currentBlendDst = null;
  191. let currentBlendEquationAlpha = null;
  192. let currentBlendSrcAlpha = null;
  193. let currentBlendDstAlpha = null;
  194. let currentBlendColor = new Color( 0, 0, 0 );
  195. let currentBlendAlpha = 0;
  196. let currentPremultipledAlpha = false;
  197. let currentFlipSided = null;
  198. let currentCullFace = null;
  199. let currentLineWidth = null;
  200. let currentPolygonOffsetFactor = null;
  201. let currentPolygonOffsetUnits = null;
  202. const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
  203. let lineWidthAvailable = false;
  204. let version = 0;
  205. const glVersion = gl.getParameter( gl.VERSION );
  206. if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
  207. version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
  208. lineWidthAvailable = ( version >= 1.0 );
  209. } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
  210. version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
  211. lineWidthAvailable = ( version >= 2.0 );
  212. }
  213. let currentTextureSlot = null;
  214. let currentBoundTextures = {};
  215. const scissorParam = gl.getParameter( gl.SCISSOR_BOX );
  216. const viewportParam = gl.getParameter( gl.VIEWPORT );
  217. const currentScissor = new Vector4().fromArray( scissorParam );
  218. const currentViewport = new Vector4().fromArray( viewportParam );
  219. function createTexture( type, target, count, dimensions ) {
  220. const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
  221. const texture = gl.createTexture();
  222. gl.bindTexture( type, texture );
  223. gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
  224. gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
  225. for ( let i = 0; i < count; i ++ ) {
  226. if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) {
  227. gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
  228. } else {
  229. gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
  230. }
  231. }
  232. return texture;
  233. }
  234. const emptyTextures = {};
  235. emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
  236. emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
  237. if ( isWebGL2 ) {
  238. emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 );
  239. emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 );
  240. }
  241. // init
  242. colorBuffer.setClear( 0, 0, 0, 1 );
  243. depthBuffer.setClear( 1 );
  244. stencilBuffer.setClear( 0 );
  245. enable( gl.DEPTH_TEST );
  246. depthBuffer.setFunc( LessEqualDepth );
  247. setFlipSided( false );
  248. setCullFace( CullFaceBack );
  249. enable( gl.CULL_FACE );
  250. setBlending( NoBlending );
  251. //
  252. function enable( id ) {
  253. if ( enabledCapabilities[ id ] !== true ) {
  254. gl.enable( id );
  255. enabledCapabilities[ id ] = true;
  256. }
  257. }
  258. function disable( id ) {
  259. if ( enabledCapabilities[ id ] !== false ) {
  260. gl.disable( id );
  261. enabledCapabilities[ id ] = false;
  262. }
  263. }
  264. function bindFramebuffer( target, framebuffer ) {
  265. if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
  266. gl.bindFramebuffer( target, framebuffer );
  267. currentBoundFramebuffers[ target ] = framebuffer;
  268. if ( isWebGL2 ) {
  269. // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER
  270. if ( target === gl.DRAW_FRAMEBUFFER ) {
  271. currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;
  272. }
  273. if ( target === gl.FRAMEBUFFER ) {
  274. currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;
  275. }
  276. }
  277. return true;
  278. }
  279. return false;
  280. }
  281. function drawBuffers( renderTarget, framebuffer ) {
  282. let drawBuffers = defaultDrawbuffers;
  283. let needsUpdate = false;
  284. if ( renderTarget ) {
  285. drawBuffers = currentDrawbuffers.get( framebuffer );
  286. if ( drawBuffers === undefined ) {
  287. drawBuffers = [];
  288. currentDrawbuffers.set( framebuffer, drawBuffers );
  289. }
  290. if ( renderTarget.isWebGLMultipleRenderTargets ) {
  291. const textures = renderTarget.texture;
  292. if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
  293. for ( let i = 0, il = textures.length; i < il; i ++ ) {
  294. drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;
  295. }
  296. drawBuffers.length = textures.length;
  297. needsUpdate = true;
  298. }
  299. } else {
  300. if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
  301. drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0;
  302. needsUpdate = true;
  303. }
  304. }
  305. } else {
  306. if ( drawBuffers[ 0 ] !== gl.BACK ) {
  307. drawBuffers[ 0 ] = gl.BACK;
  308. needsUpdate = true;
  309. }
  310. }
  311. if ( needsUpdate ) {
  312. if ( capabilities.isWebGL2 ) {
  313. gl.drawBuffers( drawBuffers );
  314. } else {
  315. extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers );
  316. }
  317. }
  318. }
  319. function useProgram( program ) {
  320. if ( currentProgram !== program ) {
  321. gl.useProgram( program );
  322. currentProgram = program;
  323. return true;
  324. }
  325. return false;
  326. }
  327. const equationToGL = {
  328. [ AddEquation ]: gl.FUNC_ADD,
  329. [ SubtractEquation ]: gl.FUNC_SUBTRACT,
  330. [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
  331. };
  332. if ( isWebGL2 ) {
  333. equationToGL[ MinEquation ] = gl.MIN;
  334. equationToGL[ MaxEquation ] = gl.MAX;
  335. } else {
  336. const extension = extensions.get( 'EXT_blend_minmax' );
  337. if ( extension !== null ) {
  338. equationToGL[ MinEquation ] = extension.MIN_EXT;
  339. equationToGL[ MaxEquation ] = extension.MAX_EXT;
  340. }
  341. }
  342. const factorToGL = {
  343. [ ZeroFactor ]: gl.ZERO,
  344. [ OneFactor ]: gl.ONE,
  345. [ SrcColorFactor ]: gl.SRC_COLOR,
  346. [ SrcAlphaFactor ]: gl.SRC_ALPHA,
  347. [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
  348. [ DstColorFactor ]: gl.DST_COLOR,
  349. [ DstAlphaFactor ]: gl.DST_ALPHA,
  350. [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
  351. [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
  352. [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
  353. [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,
  354. [ ConstantColorFactor ]: gl.CONSTANT_COLOR,
  355. [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,
  356. [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,
  357. [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA
  358. };
  359. function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {
  360. if ( blending === NoBlending ) {
  361. if ( currentBlendingEnabled === true ) {
  362. disable( gl.BLEND );
  363. currentBlendingEnabled = false;
  364. }
  365. return;
  366. }
  367. if ( currentBlendingEnabled === false ) {
  368. enable( gl.BLEND );
  369. currentBlendingEnabled = true;
  370. }
  371. if ( blending !== CustomBlending ) {
  372. if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
  373. if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
  374. gl.blendEquation( gl.FUNC_ADD );
  375. currentBlendEquation = AddEquation;
  376. currentBlendEquationAlpha = AddEquation;
  377. }
  378. if ( premultipliedAlpha ) {
  379. switch ( blending ) {
  380. case NormalBlending:
  381. gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
  382. break;
  383. case AdditiveBlending:
  384. gl.blendFunc( gl.ONE, gl.ONE );
  385. break;
  386. case SubtractiveBlending:
  387. gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
  388. break;
  389. case MultiplyBlending:
  390. gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
  391. break;
  392. default:
  393. console.error( 'THREE.WebGLState: Invalid blending: ', blending );
  394. break;
  395. }
  396. } else {
  397. switch ( blending ) {
  398. case NormalBlending:
  399. gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
  400. break;
  401. case AdditiveBlending:
  402. gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
  403. break;
  404. case SubtractiveBlending:
  405. gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
  406. break;
  407. case MultiplyBlending:
  408. gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
  409. break;
  410. default:
  411. console.error( 'THREE.WebGLState: Invalid blending: ', blending );
  412. break;
  413. }
  414. }
  415. currentBlendSrc = null;
  416. currentBlendDst = null;
  417. currentBlendSrcAlpha = null;
  418. currentBlendDstAlpha = null;
  419. currentBlendColor.set( 0, 0, 0 );
  420. currentBlendAlpha = 0;
  421. currentBlending = blending;
  422. currentPremultipledAlpha = premultipliedAlpha;
  423. }
  424. return;
  425. }
  426. // custom blending
  427. blendEquationAlpha = blendEquationAlpha || blendEquation;
  428. blendSrcAlpha = blendSrcAlpha || blendSrc;
  429. blendDstAlpha = blendDstAlpha || blendDst;
  430. if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
  431. gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
  432. currentBlendEquation = blendEquation;
  433. currentBlendEquationAlpha = blendEquationAlpha;
  434. }
  435. if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
  436. gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
  437. currentBlendSrc = blendSrc;
  438. currentBlendDst = blendDst;
  439. currentBlendSrcAlpha = blendSrcAlpha;
  440. currentBlendDstAlpha = blendDstAlpha;
  441. }
  442. if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) {
  443. gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha );
  444. currentBlendColor.copy( blendColor );
  445. currentBlendAlpha = blendAlpha;
  446. }
  447. currentBlending = blending;
  448. currentPremultipledAlpha = false;
  449. }
  450. function setMaterial( material, frontFaceCW ) {
  451. material.side === DoubleSide
  452. ? disable( gl.CULL_FACE )
  453. : enable( gl.CULL_FACE );
  454. let flipSided = ( material.side === BackSide );
  455. if ( frontFaceCW ) flipSided = ! flipSided;
  456. setFlipSided( flipSided );
  457. ( material.blending === NormalBlending && material.transparent === false )
  458. ? setBlending( NoBlending )
  459. : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
  460. depthBuffer.setFunc( material.depthFunc );
  461. depthBuffer.setTest( material.depthTest );
  462. depthBuffer.setMask( material.depthWrite );
  463. colorBuffer.setMask( material.colorWrite );
  464. const stencilWrite = material.stencilWrite;
  465. stencilBuffer.setTest( stencilWrite );
  466. if ( stencilWrite ) {
  467. stencilBuffer.setMask( material.stencilWriteMask );
  468. stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
  469. stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
  470. }
  471. setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
  472. material.alphaToCoverage === true
  473. ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
  474. : disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
  475. }
  476. //
  477. function setFlipSided( flipSided ) {
  478. if ( currentFlipSided !== flipSided ) {
  479. if ( flipSided ) {
  480. gl.frontFace( gl.CW );
  481. } else {
  482. gl.frontFace( gl.CCW );
  483. }
  484. currentFlipSided = flipSided;
  485. }
  486. }
  487. function setCullFace( cullFace ) {
  488. if ( cullFace !== CullFaceNone ) {
  489. enable( gl.CULL_FACE );
  490. if ( cullFace !== currentCullFace ) {
  491. if ( cullFace === CullFaceBack ) {
  492. gl.cullFace( gl.BACK );
  493. } else if ( cullFace === CullFaceFront ) {
  494. gl.cullFace( gl.FRONT );
  495. } else {
  496. gl.cullFace( gl.FRONT_AND_BACK );
  497. }
  498. }
  499. } else {
  500. disable( gl.CULL_FACE );
  501. }
  502. currentCullFace = cullFace;
  503. }
  504. function setLineWidth( width ) {
  505. if ( width !== currentLineWidth ) {
  506. if ( lineWidthAvailable ) gl.lineWidth( width );
  507. currentLineWidth = width;
  508. }
  509. }
  510. function setPolygonOffset( polygonOffset, factor, units ) {
  511. if ( polygonOffset ) {
  512. enable( gl.POLYGON_OFFSET_FILL );
  513. if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
  514. gl.polygonOffset( factor, units );
  515. currentPolygonOffsetFactor = factor;
  516. currentPolygonOffsetUnits = units;
  517. }
  518. } else {
  519. disable( gl.POLYGON_OFFSET_FILL );
  520. }
  521. }
  522. function setScissorTest( scissorTest ) {
  523. if ( scissorTest ) {
  524. enable( gl.SCISSOR_TEST );
  525. } else {
  526. disable( gl.SCISSOR_TEST );
  527. }
  528. }
  529. // texture
  530. function activeTexture( webglSlot ) {
  531. if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
  532. if ( currentTextureSlot !== webglSlot ) {
  533. gl.activeTexture( webglSlot );
  534. currentTextureSlot = webglSlot;
  535. }
  536. }
  537. function bindTexture( webglType, webglTexture, webglSlot ) {
  538. if ( webglSlot === undefined ) {
  539. if ( currentTextureSlot === null ) {
  540. webglSlot = gl.TEXTURE0 + maxTextures - 1;
  541. } else {
  542. webglSlot = currentTextureSlot;
  543. }
  544. }
  545. let boundTexture = currentBoundTextures[ webglSlot ];
  546. if ( boundTexture === undefined ) {
  547. boundTexture = { type: undefined, texture: undefined };
  548. currentBoundTextures[ webglSlot ] = boundTexture;
  549. }
  550. if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
  551. if ( currentTextureSlot !== webglSlot ) {
  552. gl.activeTexture( webglSlot );
  553. currentTextureSlot = webglSlot;
  554. }
  555. gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
  556. boundTexture.type = webglType;
  557. boundTexture.texture = webglTexture;
  558. }
  559. }
  560. function unbindTexture() {
  561. const boundTexture = currentBoundTextures[ currentTextureSlot ];
  562. if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
  563. gl.bindTexture( boundTexture.type, null );
  564. boundTexture.type = undefined;
  565. boundTexture.texture = undefined;
  566. }
  567. }
  568. function compressedTexImage2D() {
  569. try {
  570. gl.compressedTexImage2D.apply( gl, arguments );
  571. } catch ( error ) {
  572. console.error( 'THREE.WebGLState:', error );
  573. }
  574. }
  575. function compressedTexImage3D() {
  576. try {
  577. gl.compressedTexImage3D.apply( gl, arguments );
  578. } catch ( error ) {
  579. console.error( 'THREE.WebGLState:', error );
  580. }
  581. }
  582. function texSubImage2D() {
  583. try {
  584. gl.texSubImage2D.apply( gl, arguments );
  585. } catch ( error ) {
  586. console.error( 'THREE.WebGLState:', error );
  587. }
  588. }
  589. function texSubImage3D() {
  590. try {
  591. gl.texSubImage3D.apply( gl, arguments );
  592. } catch ( error ) {
  593. console.error( 'THREE.WebGLState:', error );
  594. }
  595. }
  596. function compressedTexSubImage2D() {
  597. try {
  598. gl.compressedTexSubImage2D.apply( gl, arguments );
  599. } catch ( error ) {
  600. console.error( 'THREE.WebGLState:', error );
  601. }
  602. }
  603. function compressedTexSubImage3D() {
  604. try {
  605. gl.compressedTexSubImage3D.apply( gl, arguments );
  606. } catch ( error ) {
  607. console.error( 'THREE.WebGLState:', error );
  608. }
  609. }
  610. function texStorage2D() {
  611. try {
  612. gl.texStorage2D.apply( gl, arguments );
  613. } catch ( error ) {
  614. console.error( 'THREE.WebGLState:', error );
  615. }
  616. }
  617. function texStorage3D() {
  618. try {
  619. gl.texStorage3D.apply( gl, arguments );
  620. } catch ( error ) {
  621. console.error( 'THREE.WebGLState:', error );
  622. }
  623. }
  624. function texImage2D() {
  625. try {
  626. gl.texImage2D.apply( gl, arguments );
  627. } catch ( error ) {
  628. console.error( 'THREE.WebGLState:', error );
  629. }
  630. }
  631. function texImage3D() {
  632. try {
  633. gl.texImage3D.apply( gl, arguments );
  634. } catch ( error ) {
  635. console.error( 'THREE.WebGLState:', error );
  636. }
  637. }
  638. //
  639. function scissor( scissor ) {
  640. if ( currentScissor.equals( scissor ) === false ) {
  641. gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
  642. currentScissor.copy( scissor );
  643. }
  644. }
  645. function viewport( viewport ) {
  646. if ( currentViewport.equals( viewport ) === false ) {
  647. gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
  648. currentViewport.copy( viewport );
  649. }
  650. }
  651. function updateUBOMapping( uniformsGroup, program ) {
  652. let mapping = uboProgramMap.get( program );
  653. if ( mapping === undefined ) {
  654. mapping = new WeakMap();
  655. uboProgramMap.set( program, mapping );
  656. }
  657. let blockIndex = mapping.get( uniformsGroup );
  658. if ( blockIndex === undefined ) {
  659. blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );
  660. mapping.set( uniformsGroup, blockIndex );
  661. }
  662. }
  663. function uniformBlockBinding( uniformsGroup, program ) {
  664. const mapping = uboProgramMap.get( program );
  665. const blockIndex = mapping.get( uniformsGroup );
  666. if ( uboBindings.get( program ) !== blockIndex ) {
  667. // bind shader specific block index to global block point
  668. gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );
  669. uboBindings.set( program, blockIndex );
  670. }
  671. }
  672. //
  673. function reset() {
  674. // reset state
  675. gl.disable( gl.BLEND );
  676. gl.disable( gl.CULL_FACE );
  677. gl.disable( gl.DEPTH_TEST );
  678. gl.disable( gl.POLYGON_OFFSET_FILL );
  679. gl.disable( gl.SCISSOR_TEST );
  680. gl.disable( gl.STENCIL_TEST );
  681. gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
  682. gl.blendEquation( gl.FUNC_ADD );
  683. gl.blendFunc( gl.ONE, gl.ZERO );
  684. gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
  685. gl.blendColor( 0, 0, 0, 0 );
  686. gl.colorMask( true, true, true, true );
  687. gl.clearColor( 0, 0, 0, 0 );
  688. gl.depthMask( true );
  689. gl.depthFunc( gl.LESS );
  690. gl.clearDepth( 1 );
  691. gl.stencilMask( 0xffffffff );
  692. gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
  693. gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
  694. gl.clearStencil( 0 );
  695. gl.cullFace( gl.BACK );
  696. gl.frontFace( gl.CCW );
  697. gl.polygonOffset( 0, 0 );
  698. gl.activeTexture( gl.TEXTURE0 );
  699. gl.bindFramebuffer( gl.FRAMEBUFFER, null );
  700. if ( isWebGL2 === true ) {
  701. gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
  702. gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
  703. }
  704. gl.useProgram( null );
  705. gl.lineWidth( 1 );
  706. gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
  707. gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
  708. // reset internals
  709. enabledCapabilities = {};
  710. currentTextureSlot = null;
  711. currentBoundTextures = {};
  712. currentBoundFramebuffers = {};
  713. currentDrawbuffers = new WeakMap();
  714. defaultDrawbuffers = [];
  715. currentProgram = null;
  716. currentBlendingEnabled = false;
  717. currentBlending = null;
  718. currentBlendEquation = null;
  719. currentBlendSrc = null;
  720. currentBlendDst = null;
  721. currentBlendEquationAlpha = null;
  722. currentBlendSrcAlpha = null;
  723. currentBlendDstAlpha = null;
  724. currentBlendColor = new Color( 0, 0, 0 );
  725. currentBlendAlpha = 0;
  726. currentPremultipledAlpha = false;
  727. currentFlipSided = null;
  728. currentCullFace = null;
  729. currentLineWidth = null;
  730. currentPolygonOffsetFactor = null;
  731. currentPolygonOffsetUnits = null;
  732. currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
  733. currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );
  734. colorBuffer.reset();
  735. depthBuffer.reset();
  736. stencilBuffer.reset();
  737. }
  738. return {
  739. buffers: {
  740. color: colorBuffer,
  741. depth: depthBuffer,
  742. stencil: stencilBuffer
  743. },
  744. enable: enable,
  745. disable: disable,
  746. bindFramebuffer: bindFramebuffer,
  747. drawBuffers: drawBuffers,
  748. useProgram: useProgram,
  749. setBlending: setBlending,
  750. setMaterial: setMaterial,
  751. setFlipSided: setFlipSided,
  752. setCullFace: setCullFace,
  753. setLineWidth: setLineWidth,
  754. setPolygonOffset: setPolygonOffset,
  755. setScissorTest: setScissorTest,
  756. activeTexture: activeTexture,
  757. bindTexture: bindTexture,
  758. unbindTexture: unbindTexture,
  759. compressedTexImage2D: compressedTexImage2D,
  760. compressedTexImage3D: compressedTexImage3D,
  761. texImage2D: texImage2D,
  762. texImage3D: texImage3D,
  763. updateUBOMapping: updateUBOMapping,
  764. uniformBlockBinding: uniformBlockBinding,
  765. texStorage2D: texStorage2D,
  766. texStorage3D: texStorage3D,
  767. texSubImage2D: texSubImage2D,
  768. texSubImage3D: texSubImage3D,
  769. compressedTexSubImage2D: compressedTexSubImage2D,
  770. compressedTexSubImage3D: compressedTexSubImage3D,
  771. scissor: scissor,
  772. viewport: viewport,
  773. reset: reset
  774. };
  775. }
  776. export { WebGLState };
粤ICP备19079148号