CubeMapFace.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import Check from "../Core/Check.js";
  2. import defaultValue from "../Core/defaultValue.js";
  3. import defined from "../Core/defined.js";
  4. import DeveloperError from "../Core/DeveloperError.js";
  5. import PixelFormat from "../Core/PixelFormat.js";
  6. import PixelDatatype from "./PixelDatatype.js";
  7. /**
  8. * @private
  9. */
  10. function CubeMapFace(
  11. context,
  12. texture,
  13. textureTarget,
  14. targetFace,
  15. internalFormat,
  16. pixelFormat,
  17. pixelDatatype,
  18. size,
  19. preMultiplyAlpha,
  20. flipY,
  21. initialized
  22. ) {
  23. this._context = context;
  24. this._texture = texture;
  25. this._textureTarget = textureTarget;
  26. this._targetFace = targetFace;
  27. this._pixelDatatype = pixelDatatype;
  28. this._internalFormat = internalFormat;
  29. this._pixelFormat = pixelFormat;
  30. this._size = size;
  31. this._preMultiplyAlpha = preMultiplyAlpha;
  32. this._flipY = flipY;
  33. this._initialized = initialized;
  34. }
  35. Object.defineProperties(CubeMapFace.prototype, {
  36. pixelFormat: {
  37. get: function () {
  38. return this._pixelFormat;
  39. },
  40. },
  41. pixelDatatype: {
  42. get: function () {
  43. return this._pixelDatatype;
  44. },
  45. },
  46. _target: {
  47. get: function () {
  48. return this._targetFace;
  49. },
  50. },
  51. });
  52. /**
  53. * Copies texels from the source to the cubemap's face.
  54. *
  55. * @param {Object} source The source ImageData, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, or an object with a width, height, and typed array as shown in the example.
  56. * @param {Number} [xOffset=0] An offset in the x direction in the cubemap where copying begins.
  57. * @param {Number} [yOffset=0] An offset in the y direction in the cubemap where copying begins.
  58. *
  59. * @exception {DeveloperError} xOffset must be greater than or equal to zero.
  60. * @exception {DeveloperError} yOffset must be greater than or equal to zero.
  61. * @exception {DeveloperError} xOffset + source.width must be less than or equal to width.
  62. * @exception {DeveloperError} yOffset + source.height must be less than or equal to height.
  63. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  64. *
  65. * @example
  66. * // Create a cubemap with 1x1 faces, and make the +x face red.
  67. * var cubeMap = new CubeMap({
  68. * context : context
  69. * width : 1,
  70. * height : 1
  71. * });
  72. * cubeMap.positiveX.copyFrom({
  73. * width : 1,
  74. * height : 1,
  75. * arrayBufferView : new Uint8Array([255, 0, 0, 255])
  76. * });
  77. */
  78. CubeMapFace.prototype.copyFrom = function (source, xOffset, yOffset) {
  79. xOffset = defaultValue(xOffset, 0);
  80. yOffset = defaultValue(yOffset, 0);
  81. //>>includeStart('debug', pragmas.debug);
  82. Check.defined("source", source);
  83. Check.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0);
  84. Check.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0);
  85. if (xOffset + source.width > this._size) {
  86. throw new DeveloperError(
  87. "xOffset + source.width must be less than or equal to width."
  88. );
  89. }
  90. if (yOffset + source.height > this._size) {
  91. throw new DeveloperError(
  92. "yOffset + source.height must be less than or equal to height."
  93. );
  94. }
  95. //>>includeEnd('debug');
  96. var gl = this._context._gl;
  97. var target = this._textureTarget;
  98. var targetFace = this._targetFace;
  99. gl.activeTexture(gl.TEXTURE0);
  100. gl.bindTexture(target, this._texture);
  101. var width = source.width;
  102. var height = source.height;
  103. var arrayBufferView = source.arrayBufferView;
  104. var size = this._size;
  105. var pixelFormat = this._pixelFormat;
  106. var internalFormat = this._internalFormat;
  107. var pixelDatatype = this._pixelDatatype;
  108. var preMultiplyAlpha = this._preMultiplyAlpha;
  109. var flipY = this._flipY;
  110. var unpackAlignment = 4;
  111. if (defined(arrayBufferView)) {
  112. unpackAlignment = PixelFormat.alignmentInBytes(
  113. pixelFormat,
  114. pixelDatatype,
  115. width
  116. );
  117. }
  118. gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment);
  119. var uploaded = false;
  120. if (!this._initialized) {
  121. if (xOffset === 0 && yOffset === 0 && width === size && height === size) {
  122. // initialize the entire texture
  123. if (defined(arrayBufferView)) {
  124. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
  125. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
  126. if (flipY) {
  127. arrayBufferView = PixelFormat.flipY(
  128. arrayBufferView,
  129. pixelFormat,
  130. pixelDatatype,
  131. size,
  132. size
  133. );
  134. }
  135. gl.texImage2D(
  136. targetFace,
  137. 0,
  138. internalFormat,
  139. size,
  140. size,
  141. 0,
  142. pixelFormat,
  143. PixelDatatype.toWebGLConstant(pixelDatatype, this._context),
  144. arrayBufferView
  145. );
  146. } else {
  147. // Only valid for DOM-Element uploads
  148. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha);
  149. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
  150. gl.texImage2D(
  151. targetFace,
  152. 0,
  153. internalFormat,
  154. pixelFormat,
  155. PixelDatatype.toWebGLConstant(pixelDatatype, this._context),
  156. source
  157. );
  158. }
  159. uploaded = true;
  160. } else {
  161. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
  162. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
  163. // initialize the entire texture to zero
  164. var bufferView = PixelFormat.createTypedArray(
  165. pixelFormat,
  166. pixelDatatype,
  167. size,
  168. size
  169. );
  170. gl.texImage2D(
  171. targetFace,
  172. 0,
  173. internalFormat,
  174. size,
  175. size,
  176. 0,
  177. pixelFormat,
  178. PixelDatatype.toWebGLConstant(pixelDatatype, this._context),
  179. bufferView
  180. );
  181. }
  182. this._initialized = true;
  183. }
  184. if (!uploaded) {
  185. if (defined(arrayBufferView)) {
  186. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
  187. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
  188. if (flipY) {
  189. arrayBufferView = PixelFormat.flipY(
  190. arrayBufferView,
  191. pixelFormat,
  192. pixelDatatype,
  193. width,
  194. height
  195. );
  196. }
  197. gl.texSubImage2D(
  198. targetFace,
  199. 0,
  200. xOffset,
  201. yOffset,
  202. width,
  203. height,
  204. pixelFormat,
  205. PixelDatatype.toWebGLConstant(pixelDatatype, this._context),
  206. arrayBufferView
  207. );
  208. } else {
  209. // Only valid for DOM-Element uploads
  210. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha);
  211. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
  212. // Source: ImageData, HTMLImageElement, HTMLCanvasElement, or HTMLVideoElement
  213. gl.texSubImage2D(
  214. targetFace,
  215. 0,
  216. xOffset,
  217. yOffset,
  218. pixelFormat,
  219. PixelDatatype.toWebGLConstant(pixelDatatype, this._context),
  220. source
  221. );
  222. }
  223. }
  224. gl.bindTexture(target, null);
  225. };
  226. /**
  227. * Copies texels from the framebuffer to the cubemap's face.
  228. *
  229. * @param {Number} [xOffset=0] An offset in the x direction in the cubemap where copying begins.
  230. * @param {Number} [yOffset=0] An offset in the y direction in the cubemap where copying begins.
  231. * @param {Number} [framebufferXOffset=0] An offset in the x direction in the framebuffer where copying begins from.
  232. * @param {Number} [framebufferYOffset=0] An offset in the y direction in the framebuffer where copying begins from.
  233. * @param {Number} [width=CubeMap's width] The width of the subimage to copy.
  234. * @param {Number} [height=CubeMap's height] The height of the subimage to copy.
  235. *
  236. * @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT.
  237. * @exception {DeveloperError} Cannot call copyFromFramebuffer when the texture pixel data type is HALF_FLOAT.
  238. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  239. * @exception {DeveloperError} xOffset must be greater than or equal to zero.
  240. * @exception {DeveloperError} yOffset must be greater than or equal to zero.
  241. * @exception {DeveloperError} framebufferXOffset must be greater than or equal to zero.
  242. * @exception {DeveloperError} framebufferYOffset must be greater than or equal to zero.
  243. * @exception {DeveloperError} xOffset + source.width must be less than or equal to width.
  244. * @exception {DeveloperError} yOffset + source.height must be less than or equal to height.
  245. * @exception {DeveloperError} This CubeMap was destroyed, i.e., destroy() was called.
  246. *
  247. * @example
  248. * // Copy the framebuffer contents to the +x cube map face.
  249. * cubeMap.positiveX.copyFromFramebuffer();
  250. */
  251. CubeMapFace.prototype.copyFromFramebuffer = function (
  252. xOffset,
  253. yOffset,
  254. framebufferXOffset,
  255. framebufferYOffset,
  256. width,
  257. height
  258. ) {
  259. xOffset = defaultValue(xOffset, 0);
  260. yOffset = defaultValue(yOffset, 0);
  261. framebufferXOffset = defaultValue(framebufferXOffset, 0);
  262. framebufferYOffset = defaultValue(framebufferYOffset, 0);
  263. width = defaultValue(width, this._size);
  264. height = defaultValue(height, this._size);
  265. //>>includeStart('debug', pragmas.debug);
  266. Check.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0);
  267. Check.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0);
  268. Check.typeOf.number.greaterThanOrEquals(
  269. "framebufferXOffset",
  270. framebufferXOffset,
  271. 0
  272. );
  273. Check.typeOf.number.greaterThanOrEquals(
  274. "framebufferYOffset",
  275. framebufferYOffset,
  276. 0
  277. );
  278. if (xOffset + width > this._size) {
  279. throw new DeveloperError(
  280. "xOffset + source.width must be less than or equal to width."
  281. );
  282. }
  283. if (yOffset + height > this._size) {
  284. throw new DeveloperError(
  285. "yOffset + source.height must be less than or equal to height."
  286. );
  287. }
  288. if (this._pixelDatatype === PixelDatatype.FLOAT) {
  289. throw new DeveloperError(
  290. "Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT."
  291. );
  292. }
  293. if (this._pixelDatatype === PixelDatatype.HALF_FLOAT) {
  294. throw new DeveloperError(
  295. "Cannot call copyFromFramebuffer when the texture pixel data type is HALF_FLOAT."
  296. );
  297. }
  298. //>>includeEnd('debug');
  299. var gl = this._context._gl;
  300. var target = this._textureTarget;
  301. gl.activeTexture(gl.TEXTURE0);
  302. gl.bindTexture(target, this._texture);
  303. gl.copyTexSubImage2D(
  304. this._targetFace,
  305. 0,
  306. xOffset,
  307. yOffset,
  308. framebufferXOffset,
  309. framebufferYOffset,
  310. width,
  311. height
  312. );
  313. gl.bindTexture(target, null);
  314. this._initialized = true;
  315. };
  316. export default CubeMapFace;