智慧水务管理系统 - 精河县供水工程综合管理平台

Context.js 52KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726
  1. import Buffer from "./Buffer.js";
  2. import Check from "../Core/Check.js";
  3. import Color from "../Core/Color.js";
  4. import ComponentDatatype from "../Core/ComponentDatatype.js";
  5. import createGuid from "../Core/createGuid.js";
  6. import Frozen from "../Core/Frozen.js";
  7. import defined from "../Core/defined.js";
  8. import destroyObject from "../Core/destroyObject.js";
  9. import DeveloperError from "../Core/DeveloperError.js";
  10. import Geometry from "../Core/Geometry.js";
  11. import GeometryAttribute from "../Core/GeometryAttribute.js";
  12. import loadKTX2 from "../Core/loadKTX2.js";
  13. import Matrix4 from "../Core/Matrix4.js";
  14. import PixelFormat from "../Core/PixelFormat.js";
  15. import PrimitiveType from "../Core/PrimitiveType.js";
  16. import RuntimeError from "../Core/RuntimeError.js";
  17. import WebGLConstants from "../Core/WebGLConstants.js";
  18. import ViewportQuadVS from "../Shaders/ViewportQuadVS.js";
  19. import BufferUsage from "./BufferUsage.js";
  20. import ClearCommand from "./ClearCommand.js";
  21. import ContextLimits from "./ContextLimits.js";
  22. import CubeMap from "./CubeMap.js";
  23. import DrawCommand from "./DrawCommand.js";
  24. import PassState from "./PassState.js";
  25. import PickId from "./PickId.js";
  26. import PixelDatatype from "./PixelDatatype.js";
  27. import RenderState from "./RenderState.js";
  28. import ShaderCache from "./ShaderCache.js";
  29. import ShaderProgram from "./ShaderProgram.js";
  30. import Texture from "./Texture.js";
  31. import TextureCache from "./TextureCache.js";
  32. import UniformState from "./UniformState.js";
  33. import VertexArray from "./VertexArray.js";
  34. /**
  35. * @private
  36. * @constructor
  37. *
  38. * @param {HTMLCanvasElement} canvas The canvas element to which the context will be associated
  39. * @param {ContextOptions} [options] Options to control WebGL settings for the context
  40. */
  41. function Context(canvas, options) {
  42. //>>includeStart('debug', pragmas.debug);
  43. Check.defined("canvas", canvas);
  44. //>>includeEnd('debug');
  45. const {
  46. getWebGLStub,
  47. requestWebgl1,
  48. webgl: webglOptions = {},
  49. allowTextureFilterAnisotropic = true,
  50. } = options ?? {};
  51. // Override select WebGL defaults
  52. webglOptions.alpha = webglOptions.alpha ?? false; // WebGL default is true
  53. webglOptions.stencil = webglOptions.stencil ?? true; // WebGL default is false
  54. webglOptions.powerPreference =
  55. webglOptions.powerPreference ?? "high-performance"; // WebGL default is "default"
  56. const glContext = defined(getWebGLStub)
  57. ? getWebGLStub(canvas, webglOptions)
  58. : getWebGLContext(canvas, webglOptions, requestWebgl1);
  59. // Get context type. instanceof will throw if WebGL2 is not supported
  60. const webgl2Supported = typeof WebGL2RenderingContext !== "undefined";
  61. const webgl2 = webgl2Supported && glContext instanceof WebGL2RenderingContext;
  62. this._canvas = canvas;
  63. this._originalGLContext = glContext;
  64. this._gl = glContext;
  65. this._webgl2 = webgl2;
  66. this._id = createGuid();
  67. // Validation and logging disabled by default for speed.
  68. this.validateFramebuffer = false;
  69. this.validateShaderProgram = false;
  70. this.logShaderCompilation = false;
  71. this._throwOnWebGLError = false;
  72. this._shaderCache = new ShaderCache(this);
  73. this._textureCache = new TextureCache();
  74. const gl = glContext;
  75. this._stencilBits = gl.getParameter(gl.STENCIL_BITS);
  76. ContextLimits._maximumCombinedTextureImageUnits = gl.getParameter(
  77. gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS,
  78. );
  79. ContextLimits._maximumCubeMapSize = gl.getParameter(
  80. gl.MAX_CUBE_MAP_TEXTURE_SIZE,
  81. );
  82. ContextLimits._maximumFragmentUniformVectors = gl.getParameter(
  83. gl.MAX_FRAGMENT_UNIFORM_VECTORS,
  84. );
  85. ContextLimits._maximumTextureImageUnits = gl.getParameter(
  86. gl.MAX_TEXTURE_IMAGE_UNITS,
  87. );
  88. ContextLimits._maximumRenderbufferSize = gl.getParameter(
  89. gl.MAX_RENDERBUFFER_SIZE,
  90. );
  91. ContextLimits._maximumTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
  92. ContextLimits._maximum3DTextureSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE);
  93. ContextLimits._maximumVaryingVectors = gl.getParameter(
  94. gl.MAX_VARYING_VECTORS,
  95. );
  96. ContextLimits._maximumVertexAttributes = gl.getParameter(
  97. gl.MAX_VERTEX_ATTRIBS,
  98. );
  99. ContextLimits._maximumVertexTextureImageUnits = gl.getParameter(
  100. gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS,
  101. );
  102. ContextLimits._maximumVertexUniformVectors = gl.getParameter(
  103. gl.MAX_VERTEX_UNIFORM_VECTORS,
  104. );
  105. ContextLimits._maximumSamples = this._webgl2
  106. ? gl.getParameter(gl.MAX_SAMPLES)
  107. : 0;
  108. const aliasedLineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); // must include 1
  109. ContextLimits._minimumAliasedLineWidth = aliasedLineWidthRange[0];
  110. ContextLimits._maximumAliasedLineWidth = aliasedLineWidthRange[1];
  111. const aliasedPointSizeRange = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); // must include 1
  112. ContextLimits._minimumAliasedPointSize = aliasedPointSizeRange[0];
  113. ContextLimits._maximumAliasedPointSize = aliasedPointSizeRange[1];
  114. const maximumViewportDimensions = gl.getParameter(gl.MAX_VIEWPORT_DIMS);
  115. ContextLimits._maximumViewportWidth = maximumViewportDimensions[0];
  116. ContextLimits._maximumViewportHeight = maximumViewportDimensions[1];
  117. const highpFloat = gl.getShaderPrecisionFormat(
  118. gl.FRAGMENT_SHADER,
  119. gl.HIGH_FLOAT,
  120. );
  121. ContextLimits._highpFloatSupported = highpFloat.precision !== 0;
  122. const highpInt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_INT);
  123. ContextLimits._highpIntSupported = highpInt.rangeMax !== 0;
  124. this._antialias = gl.getContextAttributes().antialias;
  125. // Query and initialize extensions
  126. this._standardDerivatives = !!getExtension(gl, ["OES_standard_derivatives"]);
  127. this._blendMinmax = !!getExtension(gl, ["EXT_blend_minmax"]);
  128. this._elementIndexUint = !!getExtension(gl, ["OES_element_index_uint"]);
  129. this._depthTexture = !!getExtension(gl, [
  130. "WEBGL_depth_texture",
  131. "WEBKIT_WEBGL_depth_texture",
  132. ]);
  133. this._fragDepth = !!getExtension(gl, ["EXT_frag_depth"]);
  134. this._debugShaders = getExtension(gl, ["WEBGL_debug_shaders"]);
  135. this._textureFloat = !!getExtension(gl, ["OES_texture_float"]);
  136. this._textureHalfFloat = !!getExtension(gl, ["OES_texture_half_float"]);
  137. this._textureFloatLinear = !!getExtension(gl, ["OES_texture_float_linear"]);
  138. this._textureHalfFloatLinear = !!getExtension(gl, [
  139. "OES_texture_half_float_linear",
  140. ]);
  141. this._supportsTextureLod = !!getExtension(gl, ["EXT_shader_texture_lod"]);
  142. this._colorBufferFloat = !!getExtension(gl, [
  143. "EXT_color_buffer_float",
  144. "WEBGL_color_buffer_float",
  145. ]);
  146. this._floatBlend = !!getExtension(gl, ["EXT_float_blend"]);
  147. this._colorBufferHalfFloat = !!getExtension(gl, [
  148. "EXT_color_buffer_half_float",
  149. ]);
  150. this._s3tc = !!getExtension(gl, [
  151. "WEBGL_compressed_texture_s3tc",
  152. "MOZ_WEBGL_compressed_texture_s3tc",
  153. "WEBKIT_WEBGL_compressed_texture_s3tc",
  154. ]);
  155. this._pvrtc = !!getExtension(gl, [
  156. "WEBGL_compressed_texture_pvrtc",
  157. "WEBKIT_WEBGL_compressed_texture_pvrtc",
  158. ]);
  159. this._astc = !!getExtension(gl, ["WEBGL_compressed_texture_astc"]);
  160. this._etc = !!getExtension(gl, ["WEBG_compressed_texture_etc"]);
  161. this._etc1 = !!getExtension(gl, ["WEBGL_compressed_texture_etc1"]);
  162. this._bc7 = !!getExtension(gl, ["EXT_texture_compression_bptc"]);
  163. // It is necessary to pass supported formats to loadKTX2
  164. // because imagery layers don't have access to the context.
  165. loadKTX2.setKTX2SupportedFormats(
  166. this._s3tc,
  167. this._pvrtc,
  168. this._astc,
  169. this._etc,
  170. this._etc1,
  171. this._bc7,
  172. );
  173. const textureFilterAnisotropic = allowTextureFilterAnisotropic
  174. ? getExtension(gl, [
  175. "EXT_texture_filter_anisotropic",
  176. "WEBKIT_EXT_texture_filter_anisotropic",
  177. ])
  178. : undefined;
  179. this._textureFilterAnisotropic = textureFilterAnisotropic;
  180. ContextLimits._maximumTextureFilterAnisotropy = defined(
  181. textureFilterAnisotropic,
  182. )
  183. ? gl.getParameter(textureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT)
  184. : 1.0;
  185. let glCreateVertexArray;
  186. let glBindVertexArray;
  187. let glDeleteVertexArray;
  188. let glDrawElementsInstanced;
  189. let glDrawArraysInstanced;
  190. let glVertexAttribDivisor;
  191. let glDrawBuffers;
  192. let vertexArrayObject;
  193. let instancedArrays;
  194. let drawBuffers;
  195. if (webgl2) {
  196. const that = this;
  197. glCreateVertexArray = function () {
  198. return that._gl.createVertexArray();
  199. };
  200. glBindVertexArray = function (vao) {
  201. that._gl.bindVertexArray(vao);
  202. };
  203. glDeleteVertexArray = function (vao) {
  204. that._gl.deleteVertexArray(vao);
  205. };
  206. glDrawElementsInstanced = function (
  207. mode,
  208. count,
  209. type,
  210. offset,
  211. instanceCount,
  212. ) {
  213. gl.drawElementsInstanced(mode, count, type, offset, instanceCount);
  214. };
  215. glDrawArraysInstanced = function (mode, first, count, instanceCount) {
  216. gl.drawArraysInstanced(mode, first, count, instanceCount);
  217. };
  218. glVertexAttribDivisor = function (index, divisor) {
  219. gl.vertexAttribDivisor(index, divisor);
  220. };
  221. glDrawBuffers = function (buffers) {
  222. gl.drawBuffers(buffers);
  223. };
  224. } else {
  225. vertexArrayObject = getExtension(gl, ["OES_vertex_array_object"]);
  226. if (defined(vertexArrayObject)) {
  227. glCreateVertexArray = function () {
  228. return vertexArrayObject.createVertexArrayOES();
  229. };
  230. glBindVertexArray = function (vertexArray) {
  231. vertexArrayObject.bindVertexArrayOES(vertexArray);
  232. };
  233. glDeleteVertexArray = function (vertexArray) {
  234. vertexArrayObject.deleteVertexArrayOES(vertexArray);
  235. };
  236. }
  237. instancedArrays = getExtension(gl, ["ANGLE_instanced_arrays"]);
  238. if (defined(instancedArrays)) {
  239. glDrawElementsInstanced = function (
  240. mode,
  241. count,
  242. type,
  243. offset,
  244. instanceCount,
  245. ) {
  246. instancedArrays.drawElementsInstancedANGLE(
  247. mode,
  248. count,
  249. type,
  250. offset,
  251. instanceCount,
  252. );
  253. };
  254. glDrawArraysInstanced = function (mode, first, count, instanceCount) {
  255. instancedArrays.drawArraysInstancedANGLE(
  256. mode,
  257. first,
  258. count,
  259. instanceCount,
  260. );
  261. };
  262. glVertexAttribDivisor = function (index, divisor) {
  263. instancedArrays.vertexAttribDivisorANGLE(index, divisor);
  264. };
  265. }
  266. drawBuffers = getExtension(gl, ["WEBGL_draw_buffers"]);
  267. if (defined(drawBuffers)) {
  268. glDrawBuffers = function (buffers) {
  269. drawBuffers.drawBuffersWEBGL(buffers);
  270. };
  271. }
  272. }
  273. this.glCreateVertexArray = glCreateVertexArray;
  274. this.glBindVertexArray = glBindVertexArray;
  275. this.glDeleteVertexArray = glDeleteVertexArray;
  276. this.glDrawElementsInstanced = glDrawElementsInstanced;
  277. this.glDrawArraysInstanced = glDrawArraysInstanced;
  278. this.glVertexAttribDivisor = glVertexAttribDivisor;
  279. this.glDrawBuffers = glDrawBuffers;
  280. this._vertexArrayObject = !!vertexArrayObject;
  281. this._instancedArrays = !!instancedArrays;
  282. this._drawBuffers = !!drawBuffers;
  283. ContextLimits._maximumDrawBuffers = this.drawBuffers
  284. ? gl.getParameter(WebGLConstants.MAX_DRAW_BUFFERS)
  285. : 1;
  286. ContextLimits._maximumColorAttachments = this.drawBuffers
  287. ? gl.getParameter(WebGLConstants.MAX_COLOR_ATTACHMENTS)
  288. : 1;
  289. this._clearColor = new Color(0.0, 0.0, 0.0, 0.0);
  290. this._clearDepth = 1.0;
  291. this._clearStencil = 0;
  292. const us = new UniformState();
  293. const ps = new PassState(this);
  294. const rs = RenderState.fromCache();
  295. this._defaultPassState = ps;
  296. this._defaultRenderState = rs;
  297. // default texture has a value of (1, 1, 1)
  298. // default emissive texture has a value of (0, 0, 0)
  299. // default normal texture is +z which is encoded as (0.5, 0.5, 1)
  300. this._defaultTexture = undefined;
  301. this._defaultEmissiveTexture = undefined;
  302. this._defaultNormalTexture = undefined;
  303. this._defaultCubeMap = undefined;
  304. this._us = us;
  305. this._currentRenderState = rs;
  306. this._currentPassState = ps;
  307. this._currentFramebuffer = undefined;
  308. this._maxFrameTextureUnitIndex = 0;
  309. // Vertex attribute divisor state cache. Workaround for ANGLE (also look at VertexArray.setVertexAttribDivisor)
  310. this._vertexAttribDivisors = [];
  311. this._previousDrawInstanced = false;
  312. for (let i = 0; i < ContextLimits._maximumVertexAttributes; i++) {
  313. this._vertexAttribDivisors.push(0);
  314. }
  315. this._pickObjects = new Map();
  316. this._nextPickColor = new Uint32Array(1);
  317. /**
  318. * The options used to construct this context
  319. *
  320. * @type {ContextOptions}
  321. */
  322. this.options = {
  323. getWebGLStub: getWebGLStub,
  324. requestWebgl1: requestWebgl1,
  325. webgl: webglOptions,
  326. allowTextureFilterAnisotropic: allowTextureFilterAnisotropic,
  327. };
  328. /**
  329. * A cache of objects tied to this context. Just before the Context is destroyed,
  330. * <code>destroy</code> will be invoked on each object in this object literal that has
  331. * such a method. This is useful for caching any objects that might otherwise
  332. * be stored globally, except they're tied to a particular context, and to manage
  333. * their lifetime.
  334. *
  335. * @type {object}
  336. */
  337. this.cache = {};
  338. RenderState.apply(gl, rs, ps);
  339. }
  340. /**
  341. * @typedef {object} ContextOptions
  342. *
  343. * Options to control the setting up of a WebGL Context.
  344. * <p>
  345. * <code>allowTextureFilterAnisotropic</code> defaults to true, which enables
  346. * anisotropic texture filtering when the WebGL extension is supported.
  347. * Setting this to false will improve performance, but hurt visual quality,
  348. * especially for horizon views.
  349. * </p>
  350. *
  351. * @property {boolean} [requestWebgl1=false] If true and the browser supports it, use a WebGL 1 rendering context
  352. * @property {boolean} [allowTextureFilterAnisotropic=true] If true, use anisotropic filtering during texture sampling
  353. * @property {WebGLOptions} [webgl] WebGL options to be passed on to canvas.getContext
  354. * @property {Function} [getWebGLStub] A function to create a WebGL stub for testing
  355. */
  356. /**
  357. * @private
  358. * @param {HTMLCanvasElement} canvas The canvas element to which the context will be associated
  359. * @param {WebGLOptions} webglOptions WebGL options to be passed on to HTMLCanvasElement.getContext()
  360. * @param {boolean} requestWebgl1 Whether to request a WebGLRenderingContext or a WebGL2RenderingContext.
  361. * @returns {WebGLRenderingContext|WebGL2RenderingContext}
  362. */
  363. function getWebGLContext(canvas, webglOptions, requestWebgl1) {
  364. if (typeof WebGLRenderingContext === "undefined") {
  365. throw new RuntimeError(
  366. "The browser does not support WebGL. Visit http://get.webgl.org.",
  367. );
  368. }
  369. // Ensure that WebGL 2 is supported when it is requested. Otherwise, fall back to WebGL 1.
  370. const webgl2Supported = typeof WebGL2RenderingContext !== "undefined";
  371. if (!requestWebgl1 && !webgl2Supported) {
  372. requestWebgl1 = true;
  373. }
  374. const contextType = requestWebgl1 ? "webgl" : "webgl2";
  375. const glContext = canvas.getContext(contextType, webglOptions);
  376. if (!defined(glContext)) {
  377. throw new RuntimeError(
  378. "The browser supports WebGL, but initialization failed.",
  379. );
  380. }
  381. return glContext;
  382. }
  383. /**
  384. * @typedef {object} WebGLOptions
  385. *
  386. * WebGL options to be passed on to HTMLCanvasElement.getContext().
  387. * See {@link https://registry.khronos.org/webgl/specs/latest/1.0/#5.2|WebGLContextAttributes}
  388. * but note the modified defaults for 'alpha', 'stencil', and 'powerPreference'
  389. *
  390. * <p>
  391. * <code>alpha</code> defaults to false, which can improve performance
  392. * compared to the standard WebGL default of true. If an application needs
  393. * to composite Cesium above other HTML elements using alpha-blending, set
  394. * <code>alpha</code> to true.
  395. * </p>
  396. *
  397. * @property {boolean} [alpha=false]
  398. * @property {boolean} [depth=true]
  399. * @property {boolean} [stencil=false]
  400. * @property {boolean} [antialias=true]
  401. * @property {boolean} [premultipliedAlpha=true]
  402. * @property {boolean} [preserveDrawingBuffer=false]
  403. * @property {("default"|"low-power"|"high-performance")} [powerPreference="high-performance"]
  404. * @property {boolean} [failIfMajorPerformanceCaveat=false]
  405. */
  406. function errorToString(gl, error) {
  407. let message = "WebGL Error: ";
  408. switch (error) {
  409. case gl.INVALID_ENUM:
  410. message += "INVALID_ENUM";
  411. break;
  412. case gl.INVALID_VALUE:
  413. message += "INVALID_VALUE";
  414. break;
  415. case gl.INVALID_OPERATION:
  416. message += "INVALID_OPERATION";
  417. break;
  418. case gl.OUT_OF_MEMORY:
  419. message += "OUT_OF_MEMORY";
  420. break;
  421. case gl.CONTEXT_LOST_WEBGL:
  422. message += "CONTEXT_LOST_WEBGL lost";
  423. break;
  424. default:
  425. message += `Unknown (${error})`;
  426. }
  427. return message;
  428. }
  429. function createErrorMessage(gl, glFunc, glFuncArguments, error) {
  430. let message = `${errorToString(gl, error)}: ${glFunc.name}(`;
  431. for (let i = 0; i < glFuncArguments.length; ++i) {
  432. if (i !== 0) {
  433. message += ", ";
  434. }
  435. message += glFuncArguments[i];
  436. }
  437. message += ");";
  438. return message;
  439. }
  440. function throwOnError(gl, glFunc, glFuncArguments) {
  441. const error = gl.getError();
  442. if (error !== gl.NO_ERROR) {
  443. throw new RuntimeError(
  444. createErrorMessage(gl, glFunc, glFuncArguments, error),
  445. );
  446. }
  447. }
  448. function makeGetterSetter(gl, propertyName, logFunction) {
  449. return {
  450. get: function () {
  451. const value = gl[propertyName];
  452. logFunction(gl, `get: ${propertyName}`, value);
  453. return gl[propertyName];
  454. },
  455. set: function (value) {
  456. gl[propertyName] = value;
  457. logFunction(gl, `set: ${propertyName}`, value);
  458. },
  459. };
  460. }
  461. function wrapGL(gl, logFunction) {
  462. if (!defined(logFunction)) {
  463. return gl;
  464. }
  465. function wrapFunction(property) {
  466. return function () {
  467. const result = property.apply(gl, arguments);
  468. logFunction(gl, property, arguments);
  469. return result;
  470. };
  471. }
  472. const glWrapper = {};
  473. // JavaScript linters normally demand that a for..in loop must directly contain an if,
  474. // but in our loop below, we actually intend to iterate all properties, including
  475. // those in the prototype.
  476. /*eslint-disable guard-for-in*/
  477. for (const propertyName in gl) {
  478. const property = gl[propertyName];
  479. // wrap any functions we encounter, otherwise just copy the property to the wrapper.
  480. if (property instanceof Function) {
  481. glWrapper[propertyName] = wrapFunction(property);
  482. } else {
  483. Object.defineProperty(
  484. glWrapper,
  485. propertyName,
  486. makeGetterSetter(gl, propertyName, logFunction),
  487. );
  488. }
  489. }
  490. /*eslint-enable guard-for-in*/
  491. return glWrapper;
  492. }
  493. function getExtension(gl, names) {
  494. const length = names.length;
  495. for (let i = 0; i < length; ++i) {
  496. const extension = gl.getExtension(names[i]);
  497. if (extension) {
  498. return extension;
  499. }
  500. }
  501. return undefined;
  502. }
  503. const defaultFramebufferMarker = {};
  504. Object.defineProperties(Context.prototype, {
  505. id: {
  506. get: function () {
  507. return this._id;
  508. },
  509. },
  510. webgl2: {
  511. get: function () {
  512. return this._webgl2;
  513. },
  514. },
  515. canvas: {
  516. get: function () {
  517. return this._canvas;
  518. },
  519. },
  520. shaderCache: {
  521. get: function () {
  522. return this._shaderCache;
  523. },
  524. },
  525. textureCache: {
  526. get: function () {
  527. return this._textureCache;
  528. },
  529. },
  530. uniformState: {
  531. get: function () {
  532. return this._us;
  533. },
  534. },
  535. /**
  536. * The number of stencil bits per pixel in the default bound framebuffer. The minimum is eight bits.
  537. * @memberof Context.prototype
  538. * @type {number}
  539. * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with <code>STENCIL_BITS</code>.
  540. */
  541. stencilBits: {
  542. get: function () {
  543. return this._stencilBits;
  544. },
  545. },
  546. /**
  547. * <code>true</code> if the WebGL context supports stencil buffers.
  548. * Stencil buffers are not supported by all systems.
  549. * @memberof Context.prototype
  550. * @type {boolean}
  551. */
  552. stencilBuffer: {
  553. get: function () {
  554. return this._stencilBits >= 8;
  555. },
  556. },
  557. /**
  558. * <code>true</code> if the WebGL context supports antialiasing. By default
  559. * antialiasing is requested, but it is not supported by all systems.
  560. * @memberof Context.prototype
  561. * @type {boolean}
  562. */
  563. antialias: {
  564. get: function () {
  565. return this._antialias;
  566. },
  567. },
  568. /**
  569. * <code>true</code> if the WebGL context supports multisample antialiasing. Requires
  570. * WebGL2.
  571. * @memberof Context.prototype
  572. * @type {boolean}
  573. */
  574. msaa: {
  575. get: function () {
  576. return this._webgl2;
  577. },
  578. },
  579. /**
  580. * <code>true</code> if the OES_standard_derivatives extension is supported. This
  581. * extension provides access to <code>dFdx</code>, <code>dFdy</code>, and <code>fwidth</code>
  582. * functions from GLSL. A shader using these functions still needs to explicitly enable the
  583. * extension with <code>#extension GL_OES_standard_derivatives : enable</code>.
  584. * @memberof Context.prototype
  585. * @type {boolean}
  586. * @see {@link http://www.khronos.org/registry/gles/extensions/OES/OES_standard_derivatives.txt|OES_standard_derivatives}
  587. */
  588. standardDerivatives: {
  589. get: function () {
  590. return this._standardDerivatives || this._webgl2;
  591. },
  592. },
  593. /**
  594. * <code>true</code> if the EXT_float_blend extension is supported. This
  595. * extension enables blending with 32-bit float values.
  596. * @memberof Context.prototype
  597. * @type {boolean}
  598. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_float_blend/}
  599. */
  600. floatBlend: {
  601. get: function () {
  602. return this._floatBlend;
  603. },
  604. },
  605. /**
  606. * <code>true</code> if the EXT_blend_minmax extension is supported. This
  607. * extension extends blending capabilities by adding two new blend equations:
  608. * the minimum or maximum color components of the source and destination colors.
  609. * @memberof Context.prototype
  610. * @type {boolean}
  611. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_blend_minmax/}
  612. */
  613. blendMinmax: {
  614. get: function () {
  615. return this._blendMinmax || this._webgl2;
  616. },
  617. },
  618. /**
  619. * <code>true</code> if the OES_element_index_uint extension is supported. This
  620. * extension allows the use of unsigned int indices, which can improve performance by
  621. * eliminating batch breaking caused by unsigned short indices.
  622. * @memberof Context.prototype
  623. * @type {boolean}
  624. * @see {@link http://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/|OES_element_index_uint}
  625. */
  626. elementIndexUint: {
  627. get: function () {
  628. return this._elementIndexUint || this._webgl2;
  629. },
  630. },
  631. /**
  632. * <code>true</code> if WEBGL_depth_texture is supported. This extension provides
  633. * access to depth textures that, for example, can be attached to framebuffers for shadow mapping.
  634. * @memberof Context.prototype
  635. * @type {boolean}
  636. * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture}
  637. */
  638. depthTexture: {
  639. get: function () {
  640. return this._depthTexture || this._webgl2;
  641. },
  642. },
  643. /**
  644. * <code>true</code> if OES_texture_float is supported. This extension provides
  645. * access to floating point textures that, for example, can be attached to framebuffers for high dynamic range.
  646. * @memberof Context.prototype
  647. * @type {boolean}
  648. * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_float/}
  649. */
  650. floatingPointTexture: {
  651. get: function () {
  652. return this._webgl2 || this._textureFloat;
  653. },
  654. },
  655. /**
  656. * <code>true</code> if OES_texture_half_float is supported. This extension provides
  657. * access to floating point textures that, for example, can be attached to framebuffers for high dynamic range.
  658. * @memberof Context.prototype
  659. * @type {boolean}
  660. * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/}
  661. */
  662. halfFloatingPointTexture: {
  663. get: function () {
  664. return this._webgl2 || this._textureHalfFloat;
  665. },
  666. },
  667. /**
  668. * <code>true</code> if OES_texture_float_linear is supported. This extension provides
  669. * access to linear sampling methods for minification and magnification filters of floating-point textures.
  670. * @memberof Context.prototype
  671. * @type {boolean}
  672. * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/}
  673. */
  674. textureFloatLinear: {
  675. get: function () {
  676. return this._textureFloatLinear;
  677. },
  678. },
  679. /**
  680. * <code>true</code> if OES_texture_half_float_linear is supported. This extension provides
  681. * access to linear sampling methods for minification and magnification filters of half floating-point textures.
  682. * @memberof Context.prototype
  683. * @type {boolean}
  684. * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float_linear/}
  685. */
  686. textureHalfFloatLinear: {
  687. get: function () {
  688. return (
  689. (this._webgl2 && this._textureFloatLinear) ||
  690. (!this._webgl2 && this._textureHalfFloatLinear)
  691. );
  692. },
  693. },
  694. /**
  695. * <code>true</code> if EXT_shader_texture_lod is supported. This extension provides
  696. * access to explicit LOD selection in texture sampling functions.
  697. * @memberof Context.prototype
  698. * @type {boolean}
  699. * @see {@link https://registry.khronos.org/webgl/extensions/EXT_shader_texture_lod/}
  700. */
  701. supportsTextureLod: {
  702. get: function () {
  703. return this._webgl2 || this._supportsTextureLod;
  704. },
  705. },
  706. /**
  707. * <code>true</code> if EXT_texture_filter_anisotropic is supported. This extension provides
  708. * access to anisotropic filtering for textured surfaces at an oblique angle from the viewer.
  709. * @memberof Context.prototype
  710. * @type {boolean}
  711. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/}
  712. */
  713. textureFilterAnisotropic: {
  714. get: function () {
  715. return !!this._textureFilterAnisotropic;
  716. },
  717. },
  718. /**
  719. * <code>true</code> if WEBGL_compressed_texture_s3tc is supported. This extension provides
  720. * access to DXT compressed textures.
  721. * @memberof Context.prototype
  722. * @type {boolean}
  723. * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/}
  724. */
  725. s3tc: {
  726. get: function () {
  727. return this._s3tc;
  728. },
  729. },
  730. /**
  731. * <code>true</code> if WEBGL_compressed_texture_pvrtc is supported. This extension provides
  732. * access to PVR compressed textures.
  733. * @memberof Context.prototype
  734. * @type {boolean}
  735. * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/}
  736. */
  737. pvrtc: {
  738. get: function () {
  739. return this._pvrtc;
  740. },
  741. },
  742. /**
  743. * <code>true</code> if WEBGL_compressed_texture_astc is supported. This extension provides
  744. * access to ASTC compressed textures.
  745. * @memberof Context.prototype
  746. * @type {boolean}
  747. * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/}
  748. */
  749. astc: {
  750. get: function () {
  751. return this._astc;
  752. },
  753. },
  754. /**
  755. * <code>true</code> if WEBGL_compressed_texture_etc is supported. This extension provides
  756. * access to ETC compressed textures.
  757. * @memberof Context.prototype
  758. * @type {boolean}
  759. * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/}
  760. */
  761. etc: {
  762. get: function () {
  763. return this._etc;
  764. },
  765. },
  766. /**
  767. * <code>true</code> if WEBGL_compressed_texture_etc1 is supported. This extension provides
  768. * access to ETC1 compressed textures.
  769. * @memberof Context.prototype
  770. * @type {boolean}
  771. * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/}
  772. */
  773. etc1: {
  774. get: function () {
  775. return this._etc1;
  776. },
  777. },
  778. /**
  779. * <code>true</code> if EXT_texture_compression_bptc is supported. This extension provides
  780. * access to BC7 compressed textures.
  781. * @memberof Context.prototype
  782. * @type {boolean}
  783. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_texture_compression_bptc/}
  784. */
  785. bc7: {
  786. get: function () {
  787. return this._bc7;
  788. },
  789. },
  790. /**
  791. * <code>true</code> if S3TC, PVRTC, ASTC, ETC, ETC1, or BC7 compression is supported.
  792. * @memberof Context.prototype
  793. * @type {boolean}
  794. */
  795. supportsBasis: {
  796. get: function () {
  797. return (
  798. this._s3tc ||
  799. this._pvrtc ||
  800. this._astc ||
  801. this._etc ||
  802. this._etc1 ||
  803. this._bc7
  804. );
  805. },
  806. },
  807. /**
  808. * <code>true</code> if the OES_vertex_array_object extension is supported. This
  809. * extension can improve performance by reducing the overhead of switching vertex arrays.
  810. * When enabled, this extension is automatically used by {@link VertexArray}.
  811. * @memberof Context.prototype
  812. * @type {boolean}
  813. * @see {@link http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/|OES_vertex_array_object}
  814. */
  815. vertexArrayObject: {
  816. get: function () {
  817. return this._vertexArrayObject || this._webgl2;
  818. },
  819. },
  820. /**
  821. * <code>true</code> if the EXT_frag_depth extension is supported. This
  822. * extension provides access to the <code>gl_FragDepthEXT</code> built-in output variable
  823. * from GLSL fragment shaders. A shader using these functions still needs to explicitly enable the
  824. * extension with <code>#extension GL_EXT_frag_depth : enable</code>.
  825. * @memberof Context.prototype
  826. * @type {boolean}
  827. * @see {@link http://www.khronos.org/registry/webgl/extensions/EXT_frag_depth/|EXT_frag_depth}
  828. */
  829. fragmentDepth: {
  830. get: function () {
  831. return this._fragDepth || this._webgl2;
  832. },
  833. },
  834. /**
  835. * <code>true</code> if the ANGLE_instanced_arrays extension is supported. This
  836. * extension provides access to instanced rendering.
  837. * @memberof Context.prototype
  838. * @type {boolean}
  839. * @see {@link https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays}
  840. */
  841. instancedArrays: {
  842. get: function () {
  843. return this._instancedArrays || this._webgl2;
  844. },
  845. },
  846. /**
  847. * <code>true</code> if the EXT_color_buffer_float extension is supported. This
  848. * extension makes the gl.RGBA32F format color renderable.
  849. * @memberof Context.prototype
  850. * @type {boolean}
  851. * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_color_buffer_float/}
  852. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/}
  853. */
  854. colorBufferFloat: {
  855. get: function () {
  856. return this._colorBufferFloat;
  857. },
  858. },
  859. /**
  860. * <code>true</code> if the EXT_color_buffer_half_float extension is supported. This
  861. * extension makes the format gl.RGBA16F format color renderable.
  862. * @memberof Context.prototype
  863. * @type {boolean}
  864. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_half_float/}
  865. * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/}
  866. */
  867. colorBufferHalfFloat: {
  868. get: function () {
  869. return (
  870. (this._webgl2 && this._colorBufferFloat) ||
  871. (!this._webgl2 && this._colorBufferHalfFloat)
  872. );
  873. },
  874. },
  875. /**
  876. * <code>true</code> if the WEBGL_draw_buffers extension is supported. This
  877. * extensions provides support for multiple render targets. The framebuffer object can have mutiple
  878. * color attachments and the GLSL fragment shader can write to the built-in output array <code>gl_FragData</code>.
  879. * A shader using this feature needs to explicitly enable the extension with
  880. * <code>#extension GL_EXT_draw_buffers : enable</code>.
  881. * @memberof Context.prototype
  882. * @type {boolean}
  883. * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_draw_buffers/|WEBGL_draw_buffers}
  884. */
  885. drawBuffers: {
  886. get: function () {
  887. return this._drawBuffers || this._webgl2;
  888. },
  889. },
  890. debugShaders: {
  891. get: function () {
  892. return this._debugShaders;
  893. },
  894. },
  895. throwOnWebGLError: {
  896. get: function () {
  897. return this._throwOnWebGLError;
  898. },
  899. set: function (value) {
  900. this._throwOnWebGLError = value;
  901. this._gl = wrapGL(
  902. this._originalGLContext,
  903. value ? throwOnError : undefined,
  904. );
  905. },
  906. },
  907. /**
  908. * A 1x1 RGBA texture initialized to [255, 255, 255, 255]. This can
  909. * be used as a placeholder texture while other textures are downloaded.
  910. * @memberof Context.prototype
  911. * @type {Texture}
  912. */
  913. defaultTexture: {
  914. get: function () {
  915. if (this._defaultTexture === undefined) {
  916. this._defaultTexture = new Texture({
  917. context: this,
  918. source: {
  919. width: 1,
  920. height: 1,
  921. arrayBufferView: new Uint8Array([255, 255, 255, 255]),
  922. },
  923. flipY: false,
  924. });
  925. }
  926. return this._defaultTexture;
  927. },
  928. },
  929. /**
  930. * A 1x1 RGB texture initialized to [0, 0, 0] representing a material that is
  931. * not emissive. This can be used as a placeholder texture for emissive
  932. * textures while other textures are downloaded.
  933. * @memberof Context.prototype
  934. * @type {Texture}
  935. */
  936. defaultEmissiveTexture: {
  937. get: function () {
  938. if (this._defaultEmissiveTexture === undefined) {
  939. this._defaultEmissiveTexture = new Texture({
  940. context: this,
  941. pixelFormat: PixelFormat.RGB,
  942. source: {
  943. width: 1,
  944. height: 1,
  945. arrayBufferView: new Uint8Array([0, 0, 0]),
  946. },
  947. flipY: false,
  948. });
  949. }
  950. return this._defaultEmissiveTexture;
  951. },
  952. },
  953. /**
  954. * A 1x1 RGBA texture initialized to [128, 128, 255] to encode a tangent
  955. * space normal pointing in the +z direction, i.e. (0, 0, 1). This can
  956. * be used as a placeholder normal texture while other textures are
  957. * downloaded.
  958. * @memberof Context.prototype
  959. * @type {Texture}
  960. */
  961. defaultNormalTexture: {
  962. get: function () {
  963. if (this._defaultNormalTexture === undefined) {
  964. this._defaultNormalTexture = new Texture({
  965. context: this,
  966. pixelFormat: PixelFormat.RGB,
  967. source: {
  968. width: 1,
  969. height: 1,
  970. arrayBufferView: new Uint8Array([128, 128, 255]),
  971. },
  972. flipY: false,
  973. });
  974. }
  975. return this._defaultNormalTexture;
  976. },
  977. },
  978. /**
  979. * A cube map, where each face is a 1x1 RGBA texture initialized to
  980. * [255, 255, 255, 255]. This can be used as a placeholder cube map while
  981. * other cube maps are downloaded.
  982. * @memberof Context.prototype
  983. * @type {CubeMap}
  984. */
  985. defaultCubeMap: {
  986. get: function () {
  987. if (this._defaultCubeMap === undefined) {
  988. const face = {
  989. width: 1,
  990. height: 1,
  991. arrayBufferView: new Uint8Array([255, 255, 255, 255]),
  992. };
  993. this._defaultCubeMap = new CubeMap({
  994. context: this,
  995. source: {
  996. positiveX: face,
  997. negativeX: face,
  998. positiveY: face,
  999. negativeY: face,
  1000. positiveZ: face,
  1001. negativeZ: face,
  1002. },
  1003. flipY: false,
  1004. });
  1005. }
  1006. return this._defaultCubeMap;
  1007. },
  1008. },
  1009. /**
  1010. * The drawingBufferHeight of the underlying GL context.
  1011. * @memberof Context.prototype
  1012. * @type {number}
  1013. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight}
  1014. */
  1015. drawingBufferHeight: {
  1016. get: function () {
  1017. return this._gl.drawingBufferHeight;
  1018. },
  1019. },
  1020. /**
  1021. * The drawingBufferWidth of the underlying GL context.
  1022. * @memberof Context.prototype
  1023. * @type {number}
  1024. * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferWidth|drawingBufferWidth}
  1025. */
  1026. drawingBufferWidth: {
  1027. get: function () {
  1028. return this._gl.drawingBufferWidth;
  1029. },
  1030. },
  1031. /**
  1032. * Gets an object representing the currently bound framebuffer. While this instance is not an actual
  1033. * {@link Framebuffer}, it is used to represent the default framebuffer in calls to
  1034. * {@link Texture.fromFramebuffer}.
  1035. * @memberof Context.prototype
  1036. * @type {object}
  1037. */
  1038. defaultFramebuffer: {
  1039. get: function () {
  1040. return defaultFramebufferMarker;
  1041. },
  1042. },
  1043. });
  1044. /**
  1045. * Validates a framebuffer.
  1046. * Available in debug builds only.
  1047. * @private
  1048. */
  1049. function validateFramebuffer(context) {
  1050. //>>includeStart('debug', pragmas.debug);
  1051. if (context.validateFramebuffer) {
  1052. const gl = context._gl;
  1053. const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  1054. if (status !== gl.FRAMEBUFFER_COMPLETE) {
  1055. let message;
  1056. switch (status) {
  1057. case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  1058. message =
  1059. "Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.";
  1060. break;
  1061. case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
  1062. message =
  1063. "Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height.";
  1064. break;
  1065. case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  1066. message =
  1067. "Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer.";
  1068. break;
  1069. case gl.FRAMEBUFFER_UNSUPPORTED:
  1070. message =
  1071. "Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.";
  1072. break;
  1073. }
  1074. throw new DeveloperError(message);
  1075. }
  1076. }
  1077. //>>includeEnd('debug');
  1078. }
  1079. function applyRenderState(context, renderState, passState, clear) {
  1080. const previousRenderState = context._currentRenderState;
  1081. const previousPassState = context._currentPassState;
  1082. context._currentRenderState = renderState;
  1083. context._currentPassState = passState;
  1084. RenderState.partialApply(
  1085. context._gl,
  1086. previousRenderState,
  1087. renderState,
  1088. previousPassState,
  1089. passState,
  1090. clear,
  1091. );
  1092. }
  1093. let scratchBackBufferArray;
  1094. // this check must use typeof, not defined, because defined doesn't work with undeclared variables.
  1095. if (typeof WebGLRenderingContext !== "undefined") {
  1096. scratchBackBufferArray = [WebGLConstants.BACK];
  1097. }
  1098. function bindFramebuffer(context, framebuffer) {
  1099. if (framebuffer !== context._currentFramebuffer) {
  1100. context._currentFramebuffer = framebuffer;
  1101. let buffers = scratchBackBufferArray;
  1102. if (defined(framebuffer)) {
  1103. framebuffer._bind();
  1104. validateFramebuffer(context);
  1105. // TODO: Need a way for a command to give what draw buffers are active.
  1106. buffers = framebuffer._getActiveColorAttachments();
  1107. } else {
  1108. const gl = context._gl;
  1109. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  1110. }
  1111. if (context.drawBuffers) {
  1112. context.glDrawBuffers(buffers);
  1113. }
  1114. }
  1115. }
  1116. const defaultClearCommand = new ClearCommand();
  1117. Context.prototype.clear = function (clearCommand, passState) {
  1118. clearCommand = clearCommand ?? defaultClearCommand;
  1119. passState = passState ?? this._defaultPassState;
  1120. const gl = this._gl;
  1121. let bitmask = 0;
  1122. const c = clearCommand.color;
  1123. const d = clearCommand.depth;
  1124. const s = clearCommand.stencil;
  1125. if (defined(c)) {
  1126. if (!Color.equals(this._clearColor, c)) {
  1127. Color.clone(c, this._clearColor);
  1128. gl.clearColor(c.red, c.green, c.blue, c.alpha);
  1129. }
  1130. bitmask |= gl.COLOR_BUFFER_BIT;
  1131. }
  1132. if (defined(d)) {
  1133. if (d !== this._clearDepth) {
  1134. this._clearDepth = d;
  1135. gl.clearDepth(d);
  1136. }
  1137. bitmask |= gl.DEPTH_BUFFER_BIT;
  1138. }
  1139. if (defined(s)) {
  1140. if (s !== this._clearStencil) {
  1141. this._clearStencil = s;
  1142. gl.clearStencil(s);
  1143. }
  1144. bitmask |= gl.STENCIL_BUFFER_BIT;
  1145. }
  1146. const rs = clearCommand.renderState ?? this._defaultRenderState;
  1147. applyRenderState(this, rs, passState, true);
  1148. // The command's framebuffer takes presidence over the pass' framebuffer, e.g., for off-screen rendering.
  1149. const framebuffer = clearCommand.framebuffer ?? passState.framebuffer;
  1150. bindFramebuffer(this, framebuffer);
  1151. gl.clear(bitmask);
  1152. };
  1153. function beginDraw(
  1154. context,
  1155. framebuffer,
  1156. passState,
  1157. shaderProgram,
  1158. renderState,
  1159. ) {
  1160. //>>includeStart('debug', pragmas.debug);
  1161. if (defined(framebuffer) && renderState.depthTest) {
  1162. if (renderState.depthTest.enabled && !framebuffer.hasDepthAttachment) {
  1163. throw new DeveloperError(
  1164. "The depth test can not be enabled (drawCommand.renderState.depthTest.enabled) because the framebuffer (drawCommand.framebuffer) does not have a depth or depth-stencil renderbuffer.",
  1165. );
  1166. }
  1167. }
  1168. //>>includeEnd('debug');
  1169. bindFramebuffer(context, framebuffer);
  1170. applyRenderState(context, renderState, passState, false);
  1171. shaderProgram._bind();
  1172. context._maxFrameTextureUnitIndex = Math.max(
  1173. context._maxFrameTextureUnitIndex,
  1174. shaderProgram.maximumTextureUnitIndex,
  1175. );
  1176. }
  1177. function continueDraw(context, drawCommand, shaderProgram, uniformMap) {
  1178. const primitiveType = drawCommand._primitiveType;
  1179. const va = drawCommand._vertexArray;
  1180. let offset = drawCommand._offset;
  1181. let count = drawCommand._count;
  1182. const instanceCount = drawCommand.instanceCount;
  1183. //>>includeStart('debug', pragmas.debug);
  1184. if (!PrimitiveType.validate(primitiveType)) {
  1185. throw new DeveloperError(
  1186. "drawCommand.primitiveType is required and must be valid.",
  1187. );
  1188. }
  1189. Check.defined("drawCommand.vertexArray", va);
  1190. Check.typeOf.number.greaterThanOrEquals("drawCommand.offset", offset, 0);
  1191. if (defined(count)) {
  1192. Check.typeOf.number.greaterThanOrEquals("drawCommand.count", count, 0);
  1193. }
  1194. Check.typeOf.number.greaterThanOrEquals(
  1195. "drawCommand.instanceCount",
  1196. instanceCount,
  1197. 0,
  1198. );
  1199. if (instanceCount > 0 && !context.instancedArrays) {
  1200. throw new DeveloperError("Instanced arrays extension is not supported");
  1201. }
  1202. //>>includeEnd('debug');
  1203. context._us.model = drawCommand._modelMatrix ?? Matrix4.IDENTITY;
  1204. shaderProgram._setUniforms(
  1205. uniformMap,
  1206. context._us,
  1207. context.validateShaderProgram,
  1208. );
  1209. va._bind();
  1210. const indexBuffer = va.indexBuffer;
  1211. if (defined(indexBuffer)) {
  1212. offset = offset * indexBuffer.bytesPerIndex; // offset in vertices to offset in bytes
  1213. if (defined(count)) {
  1214. count = Math.min(count, indexBuffer.numberOfIndices);
  1215. } else {
  1216. count = indexBuffer.numberOfIndices;
  1217. }
  1218. if (instanceCount === 0) {
  1219. context._gl.drawElements(
  1220. primitiveType,
  1221. count,
  1222. indexBuffer.indexDatatype,
  1223. offset,
  1224. );
  1225. } else {
  1226. context.glDrawElementsInstanced(
  1227. primitiveType,
  1228. count,
  1229. indexBuffer.indexDatatype,
  1230. offset,
  1231. instanceCount,
  1232. );
  1233. }
  1234. } else {
  1235. if (defined(count)) {
  1236. count = Math.min(count, va.numberOfVertices);
  1237. } else {
  1238. count = va.numberOfVertices;
  1239. }
  1240. if (instanceCount === 0) {
  1241. context._gl.drawArrays(primitiveType, offset, count);
  1242. } else {
  1243. context.glDrawArraysInstanced(
  1244. primitiveType,
  1245. offset,
  1246. count,
  1247. instanceCount,
  1248. );
  1249. }
  1250. }
  1251. va._unBind();
  1252. }
  1253. Context.prototype.draw = function (
  1254. drawCommand,
  1255. passState,
  1256. shaderProgram,
  1257. uniformMap,
  1258. ) {
  1259. //>>includeStart('debug', pragmas.debug);
  1260. Check.defined("drawCommand", drawCommand);
  1261. Check.defined("drawCommand.shaderProgram", drawCommand._shaderProgram);
  1262. //>>includeEnd('debug');
  1263. passState = passState ?? this._defaultPassState;
  1264. // The command's framebuffer takes precedence over the pass' framebuffer, e.g., for off-screen rendering.
  1265. const framebuffer = drawCommand._framebuffer ?? passState.framebuffer;
  1266. const renderState = drawCommand._renderState ?? this._defaultRenderState;
  1267. shaderProgram = shaderProgram ?? drawCommand._shaderProgram;
  1268. uniformMap = uniformMap ?? drawCommand._uniformMap;
  1269. beginDraw(this, framebuffer, passState, shaderProgram, renderState);
  1270. continueDraw(this, drawCommand, shaderProgram, uniformMap);
  1271. };
  1272. Context.prototype.beginFrame = function () {
  1273. // A no-op. Overridden when drawing to a SharedContext.
  1274. };
  1275. Context.prototype.endFrame = function () {
  1276. const gl = this._gl;
  1277. gl.useProgram(null);
  1278. this._currentFramebuffer = undefined;
  1279. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  1280. const buffers = scratchBackBufferArray;
  1281. if (this.drawBuffers) {
  1282. this.glDrawBuffers(buffers);
  1283. }
  1284. const length = this._maxFrameTextureUnitIndex;
  1285. this._maxFrameTextureUnitIndex = 0;
  1286. for (let i = 0; i < length; ++i) {
  1287. gl.activeTexture(gl.TEXTURE0 + i);
  1288. gl.bindTexture(gl.TEXTURE_2D, null);
  1289. gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
  1290. }
  1291. };
  1292. /**
  1293. * @typedef {object} ReadState
  1294. *
  1295. * Options defining a rectangle to read pixels from.
  1296. *
  1297. * @private
  1298. * @property {number} [x=0] The x offset of the rectangle to read from.
  1299. * @property {number} [y=0] The y offset of the rectangle to read from.
  1300. * @property {number} [width=this.drawingBufferWidth] The width of the rectangle to read from.
  1301. * @property {number} [height=this.drawingBufferHeight] The height of the rectangle to read from.
  1302. * @property {FrameBuffer|undefined} [framebuffer] The framebuffer to read from. If undefined, the read will be from the default framebuffer.
  1303. */
  1304. /**
  1305. * Read pixels from a framebuffer into a Pixel Buffer Object (PBO).
  1306. *
  1307. * @private
  1308. * @param {ReadState} readState Options defining a rectangle to read pixels from.
  1309. * @returns {Buffer} A PixelBuffer containing the pixels read from the specified rectangle.
  1310. *
  1311. * @exception {DeveloperError} A WebGL 2 context is required to read pixels using a PBO.
  1312. */
  1313. Context.prototype.readPixelsToPBO = function (readState) {
  1314. const gl = this._gl;
  1315. readState = readState ?? Frozen.EMPTY_OBJECT;
  1316. const x = Math.max(readState.x ?? 0, 0);
  1317. const y = Math.max(readState.y ?? 0, 0);
  1318. const width = readState.width ?? this.drawingBufferWidth;
  1319. const height = readState.height ?? this.drawingBufferHeight;
  1320. const framebuffer = readState.framebuffer;
  1321. if (!this._webgl2) {
  1322. throw new DeveloperError(
  1323. "A WebGL 2 context is required to read pixels using a PBO.",
  1324. );
  1325. }
  1326. //>>includeStart('debug', pragmas.debug);
  1327. Check.typeOf.number.greaterThan("readState.width", width, 0);
  1328. Check.typeOf.number.greaterThan("readState.height", height, 0);
  1329. //>>includeEnd('debug');
  1330. let pixelDatatype = PixelDatatype.UNSIGNED_BYTE;
  1331. let pixelFormat = PixelFormat.RGBA;
  1332. if (defined(framebuffer) && framebuffer.numberOfColorAttachments > 0) {
  1333. pixelDatatype = framebuffer.getColorTexture(0).pixelDatatype;
  1334. pixelFormat = framebuffer.getColorTexture(0).pixelFormat;
  1335. }
  1336. const pixels = Buffer.createPixelBuffer({
  1337. context: this,
  1338. sizeInBytes: PixelFormat.textureSizeInBytes(
  1339. pixelFormat,
  1340. pixelDatatype,
  1341. width,
  1342. height,
  1343. ),
  1344. usage: BufferUsage.DYNAMIC_READ,
  1345. });
  1346. bindFramebuffer(this, framebuffer);
  1347. pixels._bind();
  1348. gl.readPixels(
  1349. x,
  1350. y,
  1351. width,
  1352. height,
  1353. pixelFormat,
  1354. PixelDatatype.toWebGLConstant(pixelDatatype, this),
  1355. 0,
  1356. );
  1357. pixels._unBind();
  1358. return pixels;
  1359. };
  1360. /**
  1361. * Read pixels from a framebuffer into a typed array.
  1362. *
  1363. * @private
  1364. * @param {ReadState} readState Options defining a rectangle to read pixels from.
  1365. * @returns {Uint8Array|Uint16Array|Float32Array|Uint32Array} The pixels in the specified rectangle.
  1366. */
  1367. Context.prototype.readPixels = function (readState) {
  1368. const gl = this._gl;
  1369. readState = readState ?? Frozen.EMPTY_OBJECT;
  1370. const x = Math.max(readState.x ?? 0, 0);
  1371. const y = Math.max(readState.y ?? 0, 0);
  1372. const width = readState.width ?? this.drawingBufferWidth;
  1373. const height = readState.height ?? this.drawingBufferHeight;
  1374. const framebuffer = readState.framebuffer;
  1375. //>>includeStart('debug', pragmas.debug);
  1376. Check.typeOf.number.greaterThan("readState.width", width, 0);
  1377. Check.typeOf.number.greaterThan("readState.height", height, 0);
  1378. //>>includeEnd('debug');
  1379. let pixelDatatype = PixelDatatype.UNSIGNED_BYTE;
  1380. let pixelFormat = PixelFormat.RGBA;
  1381. if (defined(framebuffer) && framebuffer.numberOfColorAttachments > 0) {
  1382. pixelDatatype = framebuffer.getColorTexture(0).pixelDatatype;
  1383. pixelFormat = framebuffer.getColorTexture(0).pixelFormat;
  1384. }
  1385. const pixels = PixelFormat.createTypedArray(
  1386. pixelFormat,
  1387. pixelDatatype,
  1388. width,
  1389. height,
  1390. );
  1391. bindFramebuffer(this, framebuffer);
  1392. gl.readPixels(
  1393. x,
  1394. y,
  1395. width,
  1396. height,
  1397. PixelFormat.RGBA,
  1398. PixelDatatype.toWebGLConstant(pixelDatatype, this),
  1399. pixels,
  1400. );
  1401. return pixels;
  1402. };
  1403. const viewportQuadAttributeLocations = {
  1404. position: 0,
  1405. textureCoordinates: 1,
  1406. };
  1407. Context.prototype.getViewportQuadVertexArray = function () {
  1408. // Per-context cache for viewport quads
  1409. let vertexArray = this.cache.viewportQuad_vertexArray;
  1410. if (!defined(vertexArray)) {
  1411. const geometry = new Geometry({
  1412. attributes: {
  1413. position: new GeometryAttribute({
  1414. componentDatatype: ComponentDatatype.FLOAT,
  1415. componentsPerAttribute: 2,
  1416. values: [-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0],
  1417. }),
  1418. textureCoordinates: new GeometryAttribute({
  1419. componentDatatype: ComponentDatatype.FLOAT,
  1420. componentsPerAttribute: 2,
  1421. values: [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0],
  1422. }),
  1423. },
  1424. // Workaround Internet Explorer 11.0.8 lack of TRIANGLE_FAN
  1425. indices: new Uint16Array([0, 1, 2, 0, 2, 3]),
  1426. primitiveType: PrimitiveType.TRIANGLES,
  1427. });
  1428. vertexArray = VertexArray.fromGeometry({
  1429. context: this,
  1430. geometry: geometry,
  1431. attributeLocations: viewportQuadAttributeLocations,
  1432. bufferUsage: BufferUsage.STATIC_DRAW,
  1433. interleave: true,
  1434. });
  1435. this.cache.viewportQuad_vertexArray = vertexArray;
  1436. }
  1437. return vertexArray;
  1438. };
  1439. Context.prototype.createViewportQuadCommand = function (
  1440. fragmentShaderSource,
  1441. overrides,
  1442. ) {
  1443. overrides = overrides ?? Frozen.EMPTY_OBJECT;
  1444. return new DrawCommand({
  1445. vertexArray: this.getViewportQuadVertexArray(),
  1446. primitiveType: PrimitiveType.TRIANGLES,
  1447. renderState: overrides.renderState,
  1448. shaderProgram: ShaderProgram.fromCache({
  1449. context: this,
  1450. vertexShaderSource: ViewportQuadVS,
  1451. fragmentShaderSource: fragmentShaderSource,
  1452. attributeLocations: viewportQuadAttributeLocations,
  1453. }),
  1454. uniformMap: overrides.uniformMap,
  1455. owner: overrides.owner,
  1456. framebuffer: overrides.framebuffer,
  1457. pass: overrides.pass,
  1458. });
  1459. };
  1460. /**
  1461. * Gets the object associated with a pick color.
  1462. *
  1463. * @param {number} pickColor The unsigned 32-bit RGBA pick color
  1464. * @returns {object} The object associated with the pick color, or undefined if no object is associated with that color.
  1465. *
  1466. * @example
  1467. * const object = context.getObjectByPickColor(pickColor);
  1468. *
  1469. * @see Context#createPickId
  1470. */
  1471. Context.prototype.getObjectByPickColor = function (pickColor) {
  1472. //>>includeStart('debug', pragmas.debug);
  1473. Check.defined("pickColor", pickColor);
  1474. //>>includeEnd('debug');
  1475. return this._pickObjects.get(pickColor);
  1476. };
  1477. /**
  1478. * Creates a unique ID associated with the input object for use with color-buffer picking.
  1479. * The ID has an RGBA color value unique to this context. You must call destroy()
  1480. * on the pick ID when destroying the input object.
  1481. *
  1482. * @param {object} object The object to associate with the pick ID.
  1483. * @returns {PickId} A PickId object with a <code>color</code> property.
  1484. *
  1485. * @exception {RuntimeError} Out of unique Pick IDs.
  1486. *
  1487. *
  1488. * @example
  1489. * this._pickId = context.createPickId({
  1490. * primitive : this,
  1491. * id : this.id
  1492. * });
  1493. *
  1494. * @see Context#getObjectByPickColor
  1495. */
  1496. Context.prototype.createPickId = function (object) {
  1497. //>>includeStart('debug', pragmas.debug);
  1498. Check.defined("object", object);
  1499. //>>includeEnd('debug');
  1500. // the increment and assignment have to be separate statements to
  1501. // actually detect overflow in the Uint32 value
  1502. ++this._nextPickColor[0];
  1503. const key = this._nextPickColor[0];
  1504. if (key === 0) {
  1505. // In case of overflow
  1506. throw new RuntimeError("Out of unique Pick IDs.");
  1507. }
  1508. this._pickObjects.set(key, object);
  1509. return new PickId(this._pickObjects, key, Color.fromRgba(key));
  1510. };
  1511. Context.prototype.isDestroyed = function () {
  1512. return false;
  1513. };
  1514. Context.prototype.destroy = function () {
  1515. // Destroy all objects in the cache that have a destroy method.
  1516. const cache = this.cache;
  1517. for (const property in cache) {
  1518. if (cache.hasOwnProperty(property)) {
  1519. const propertyValue = cache[property];
  1520. if (defined(propertyValue.destroy)) {
  1521. propertyValue.destroy();
  1522. }
  1523. }
  1524. }
  1525. this._shaderCache = this._shaderCache.destroy();
  1526. this._textureCache = this._textureCache.destroy();
  1527. this._defaultTexture = this._defaultTexture && this._defaultTexture.destroy();
  1528. this._defaultEmissiveTexture =
  1529. this._defaultEmissiveTexture && this._defaultEmissiveTexture.destroy();
  1530. this._defaultNormalTexture =
  1531. this._defaultNormalTexture && this._defaultNormalTexture.destroy();
  1532. this._defaultCubeMap = this._defaultCubeMap && this._defaultCubeMap.destroy();
  1533. return destroyObject(this);
  1534. };
  1535. export default Context;