@xeokit/xeokit-sdk 2.2.1-beta.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13276,533 +13276,6 @@ class Program {
13276
13276
  }
13277
13277
  }
13278
13278
 
13279
- /*
13280
- * Canvas2Image v0.1
13281
- * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
13282
- * MIT License [http://www.opensource.org/licenses/mit-license.php]
13283
- *
13284
- * Modified by @xeolabs to permit vertical flipping, so that snapshot can be taken from WebGL frame buffers,
13285
- * which vertically flip image data as part of the way that WebGL renders textures.
13286
- */
13287
-
13288
- /**
13289
- * @private
13290
- */
13291
- const Canvas2Image = (function () {
13292
- // check if we have canvas support
13293
- const oCanvas = document.createElement("canvas"), sc = String.fromCharCode;
13294
-
13295
- // no canvas, bail out.
13296
- if (!oCanvas.getContext) {
13297
- return {
13298
- saveAsBMP: function () {
13299
- },
13300
- saveAsPNG: function () {
13301
- },
13302
- saveAsJPEG: function () {
13303
- }
13304
- }
13305
- }
13306
-
13307
- const bHasImageData = !!(oCanvas.getContext("2d").getImageData), bHasDataURL = !!(oCanvas.toDataURL),
13308
- bHasBase64 = !!(window.btoa);
13309
-
13310
- // ok, we're good
13311
- const readCanvasData = function (oCanvas) {
13312
- const iWidth = parseInt(oCanvas.width), iHeight = parseInt(oCanvas.height);
13313
- return oCanvas.getContext("2d").getImageData(0, 0, iWidth, iHeight);
13314
- };
13315
-
13316
- // base64 encodes either a string or an array of charcodes
13317
- const encodeData = function (data) {
13318
- let i, aData, strData = "";
13319
-
13320
- if (typeof data == "string") {
13321
- strData = data;
13322
- } else {
13323
- aData = data;
13324
- for (i = 0; i < aData.length; i++) {
13325
- strData += sc(aData[i]);
13326
- }
13327
- }
13328
- return btoa(strData);
13329
- };
13330
-
13331
- // creates a base64 encoded string containing BMP data takes an imagedata object as argument
13332
- const createBMP = function (oData) {
13333
- let strHeader = '';
13334
- const iWidth = oData.width;
13335
- const iHeight = oData.height;
13336
-
13337
- strHeader += 'BM';
13338
-
13339
- let iFileSize = iWidth * iHeight * 4 + 54; // total header size = 54 bytes
13340
- strHeader += sc(iFileSize % 256);
13341
- iFileSize = Math.floor(iFileSize / 256);
13342
- strHeader += sc(iFileSize % 256);
13343
- iFileSize = Math.floor(iFileSize / 256);
13344
- strHeader += sc(iFileSize % 256);
13345
- iFileSize = Math.floor(iFileSize / 256);
13346
- strHeader += sc(iFileSize % 256);
13347
-
13348
- strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset
13349
- strHeader += sc(40, 0, 0, 0); // info header size
13350
-
13351
- let iImageWidth = iWidth;
13352
- strHeader += sc(iImageWidth % 256);
13353
- iImageWidth = Math.floor(iImageWidth / 256);
13354
- strHeader += sc(iImageWidth % 256);
13355
- iImageWidth = Math.floor(iImageWidth / 256);
13356
- strHeader += sc(iImageWidth % 256);
13357
- iImageWidth = Math.floor(iImageWidth / 256);
13358
- strHeader += sc(iImageWidth % 256);
13359
-
13360
- let iImageHeight = iHeight;
13361
- strHeader += sc(iImageHeight % 256);
13362
- iImageHeight = Math.floor(iImageHeight / 256);
13363
- strHeader += sc(iImageHeight % 256);
13364
- iImageHeight = Math.floor(iImageHeight / 256);
13365
- strHeader += sc(iImageHeight % 256);
13366
- iImageHeight = Math.floor(iImageHeight / 256);
13367
- strHeader += sc(iImageHeight % 256);
13368
-
13369
- strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel
13370
- strHeader += sc(0, 0, 0, 0); // compression = none
13371
-
13372
- let iDataSize = iWidth * iHeight * 4;
13373
- strHeader += sc(iDataSize % 256);
13374
- iDataSize = Math.floor(iDataSize / 256);
13375
- strHeader += sc(iDataSize % 256);
13376
- iDataSize = Math.floor(iDataSize / 256);
13377
- strHeader += sc(iDataSize % 256);
13378
- iDataSize = Math.floor(iDataSize / 256);
13379
- strHeader += sc(iDataSize % 256);
13380
-
13381
- strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used
13382
-
13383
- const aImgData = oData.data;
13384
- let strPixelData = "";
13385
- let x;
13386
- let y = iHeight;
13387
- let iOffsetX;
13388
- let iOffsetY;
13389
- let strPixelRow;
13390
-
13391
- do {
13392
- iOffsetY = iWidth * (y - 1) * 4;
13393
- strPixelRow = "";
13394
- for (x = 0; x < iWidth; x++) {
13395
- iOffsetX = 4 * x;
13396
- strPixelRow += sc(
13397
- aImgData[iOffsetY + iOffsetX + 2], // B
13398
- aImgData[iOffsetY + iOffsetX + 1], // G
13399
- aImgData[iOffsetY + iOffsetX], // R
13400
- aImgData[iOffsetY + iOffsetX + 3] // A
13401
- );
13402
- }
13403
- strPixelData += strPixelRow;
13404
- } while (--y);
13405
-
13406
- return encodeData(strHeader + strPixelData);
13407
- };
13408
-
13409
- // sends the generated file to the client
13410
- const saveFile = function (strData) {
13411
- if (!window.open(strData)) {
13412
- document.location.href = strData;
13413
- }
13414
- };
13415
-
13416
- const makeDataURI = function (strData, strMime) {
13417
- return "data:" + strMime + ";base64," + strData;
13418
- };
13419
-
13420
- // generates a <img> object containing the imagedata
13421
- const makeImageObject = function (strSource) {
13422
- const oImgElement = document.createElement("img");
13423
- oImgElement.src = strSource;
13424
- return oImgElement;
13425
- };
13426
-
13427
- const scaleCanvas = function (oCanvas, iWidth, iHeight, flipy) {
13428
- if (iWidth && iHeight) {
13429
- const oSaveCanvas = document.createElement("canvas");
13430
- oSaveCanvas.width = iWidth;
13431
- oSaveCanvas.height = iHeight;
13432
- oSaveCanvas.style.width = iWidth + "px";
13433
- oSaveCanvas.style.height = iHeight + "px";
13434
- const oSaveCtx = oSaveCanvas.getContext("2d");
13435
- if (flipy) {
13436
- oSaveCtx.save();
13437
- oSaveCtx.scale(1.0, -1.0);
13438
- oSaveCtx.imageSmoothingEnabled = true;
13439
- oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, -iHeight);
13440
- oSaveCtx.restore();
13441
- } else {
13442
- oSaveCtx.imageSmoothingEnabled = true;
13443
- oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iHeight);
13444
- }
13445
- return oSaveCanvas;
13446
- }
13447
- return oCanvas;
13448
- };
13449
-
13450
- return {
13451
- saveAsPNG: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
13452
- if (!bHasDataURL) return false;
13453
- const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
13454
- const strMime = "image/png";
13455
- const strData = oScaledCanvas.toDataURL(strMime);
13456
- if (bReturnImg) {
13457
- return makeImageObject(strData);
13458
- } else {
13459
- saveFile(strData);
13460
- }
13461
- return true;
13462
- },
13463
-
13464
- saveAsJPEG: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
13465
- if (!bHasDataURL) return false;
13466
- const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
13467
- const strMime = "image/jpeg";
13468
- const strData = oScaledCanvas.toDataURL(strMime);
13469
- // check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false
13470
- if (strData.indexOf(strMime) != 5) return false;
13471
- if (bReturnImg) {
13472
- return makeImageObject(strData);
13473
- } else {
13474
- saveFile(strData);
13475
- }
13476
- return true;
13477
- },
13478
-
13479
- saveAsBMP: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
13480
- if (!(bHasDataURL && bHasImageData && bHasBase64)) return false;
13481
- const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
13482
- const strMime = "image/bmp";
13483
- const oData = readCanvasData(oScaledCanvas), strImgData = createBMP(oData);
13484
- if (bReturnImg) {
13485
- return makeImageObject(makeDataURI(strImgData, strMime));
13486
- } else {
13487
- saveFile(makeDataURI(strImgData, strMime));
13488
- }
13489
- return true;
13490
- }
13491
- };
13492
- })();
13493
-
13494
- /**
13495
- * @desc Represents a WebGL render buffer.
13496
- * @private
13497
- */
13498
- class RenderBuffer {
13499
-
13500
- constructor(canvas, gl, options) {
13501
- options = options || {};
13502
- this.gl = gl;
13503
- this.allocated = false;
13504
- this.canvas = canvas;
13505
- this.buffer = null;
13506
- this.bound = false;
13507
- this.size = options.size;
13508
- this._hasDepthTexture = !!options.depthTexture;
13509
- }
13510
-
13511
- setSize(size) {
13512
- this.size = size;
13513
- }
13514
-
13515
- webglContextRestored(gl) {
13516
- this.gl = gl;
13517
- this.buffer = null;
13518
- this.allocated = false;
13519
- this.bound = false;
13520
- }
13521
-
13522
- bind() {
13523
- this._touch();
13524
- if (this.bound) {
13525
- return;
13526
- }
13527
- const gl = this.gl;
13528
- gl.bindFramebuffer(gl.FRAMEBUFFER, this.buffer.framebuf);
13529
- this.bound = true;
13530
- }
13531
-
13532
- _touch() {
13533
-
13534
- let width;
13535
- let height;
13536
- const gl = this.gl;
13537
-
13538
- if (this.size) {
13539
- width = this.size[0];
13540
- height = this.size[1];
13541
-
13542
- } else {
13543
- width = gl.drawingBufferWidth;
13544
- height = gl.drawingBufferHeight;
13545
- }
13546
-
13547
- if (this.buffer) {
13548
-
13549
- if (this.buffer.width === width && this.buffer.height === height) {
13550
- return;
13551
-
13552
- } else {
13553
- gl.deleteTexture(this.buffer.texture);
13554
- gl.deleteFramebuffer(this.buffer.framebuf);
13555
- gl.deleteRenderbuffer(this.buffer.renderbuf);
13556
- }
13557
- }
13558
-
13559
- const colorTexture = gl.createTexture();
13560
- gl.bindTexture(gl.TEXTURE_2D, colorTexture);
13561
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
13562
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
13563
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
13564
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
13565
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
13566
-
13567
- let depthTexture;
13568
-
13569
- if (this._hasDepthTexture) {
13570
- depthTexture = gl.createTexture();
13571
- gl.bindTexture(gl.TEXTURE_2D, depthTexture);
13572
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
13573
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
13574
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
13575
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
13576
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
13577
- }
13578
-
13579
- const renderbuf = gl.createRenderbuffer();
13580
- gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuf);
13581
- gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
13582
-
13583
- const framebuf = gl.createFramebuffer();
13584
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuf);
13585
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
13586
-
13587
- if (this._hasDepthTexture) {
13588
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
13589
- } else {
13590
- gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuf);
13591
- }
13592
-
13593
- gl.bindTexture(gl.TEXTURE_2D, null);
13594
- gl.bindRenderbuffer(gl.RENDERBUFFER, null);
13595
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
13596
-
13597
- // Verify framebuffer is OK
13598
-
13599
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuf);
13600
- if (!gl.isFramebuffer(framebuf)) {
13601
- throw "Invalid framebuffer";
13602
- }
13603
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
13604
-
13605
- const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
13606
-
13607
- switch (status) {
13608
-
13609
- case gl.FRAMEBUFFER_COMPLETE:
13610
- break;
13611
-
13612
- case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
13613
- throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
13614
-
13615
- case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
13616
- throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
13617
-
13618
- case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
13619
- throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
13620
-
13621
- case gl.FRAMEBUFFER_UNSUPPORTED:
13622
- throw "Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED";
13623
-
13624
- default:
13625
- throw "Incomplete framebuffer: " + status;
13626
- }
13627
-
13628
- this.buffer = {
13629
- framebuf: framebuf,
13630
- renderbuf: renderbuf,
13631
- texture: colorTexture,
13632
- depthTexture: depthTexture,
13633
- width: width,
13634
- height: height
13635
- };
13636
-
13637
- this.bound = false;
13638
- }
13639
-
13640
- clear() {
13641
- if (!this.bound) {
13642
- throw "Render buffer not bound";
13643
- }
13644
- const gl = this.gl;
13645
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
13646
- }
13647
-
13648
- read(pickX, pickY) {
13649
- const x = pickX;
13650
- const y = this.gl.drawingBufferHeight - pickY;
13651
- const pix = new Uint8Array(4);
13652
- const gl = this.gl;
13653
- gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix);
13654
- return pix;
13655
- }
13656
-
13657
- readImage(params) {
13658
-
13659
- const gl = this.gl;
13660
- const imageDataCache = this._getImageDataCache();
13661
- const pixelData = imageDataCache.pixelData;
13662
- const canvas = imageDataCache.canvas;
13663
- const imageData = imageDataCache.imageData;
13664
- const context = imageDataCache.context;
13665
-
13666
- gl.readPixels(0, 0, this.buffer.width, this.buffer.height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
13667
-
13668
- imageData.data.set(pixelData);
13669
- context.putImageData(imageData, 0, 0);
13670
-
13671
- const imageWidth = params.width || canvas.width;
13672
- const imageHeight = params.height || canvas.height;
13673
- const format = params.format || "jpeg";
13674
- const flipy = true; // Account for WebGL texture flipping
13675
-
13676
- let image;
13677
-
13678
- switch (format) {
13679
- case "jpeg":
13680
- image = Canvas2Image.saveAsJPEG(canvas, true, imageWidth, imageHeight, flipy);
13681
- break;
13682
- case "png":
13683
- image = Canvas2Image.saveAsPNG(canvas, true, imageWidth, imageHeight, flipy);
13684
- break;
13685
- case "bmp":
13686
- image = Canvas2Image.saveAsBMP(canvas, true, imageWidth, imageHeight, flipy);
13687
- break;
13688
- default:
13689
- console.error("Unsupported image format: '" + format + "' - supported types are 'jpeg', 'bmp' and 'png' - defaulting to 'jpeg'");
13690
- image = Canvas2Image.saveAsJPEG(canvas, true, imageWidth, imageHeight, flipy);
13691
- }
13692
-
13693
- return image.src;
13694
- }
13695
-
13696
- _getImageDataCache() {
13697
-
13698
- const bufferWidth = this.buffer.width;
13699
- const bufferHeight = this.buffer.height;
13700
-
13701
- let imageDataCache = this._imageDataCache;
13702
-
13703
- if (imageDataCache) {
13704
- if (imageDataCache.width !== bufferWidth || imageDataCache.height !== bufferHeight) {
13705
- this._imageDataCache = null;
13706
- imageDataCache = null;
13707
- }
13708
- }
13709
-
13710
- if (!imageDataCache) {
13711
-
13712
- const canvas = document.createElement('canvas');
13713
- canvas.width = bufferWidth;
13714
- canvas.height = bufferHeight;
13715
-
13716
- const context = canvas.getContext('2d');
13717
- const imageData = context.createImageData(bufferWidth, bufferHeight);
13718
-
13719
- imageDataCache = {
13720
- pixelData: new Uint8Array(bufferWidth * bufferHeight * 4),
13721
- canvas: canvas,
13722
- context: context,
13723
- imageData: imageData,
13724
- width: bufferWidth,
13725
- height: bufferHeight
13726
- };
13727
-
13728
- this._imageDataCache = imageDataCache;
13729
- }
13730
-
13731
- return imageDataCache;
13732
- }
13733
-
13734
- unbind() {
13735
- const gl = this.gl;
13736
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
13737
- this.bound = false;
13738
- }
13739
-
13740
- getTexture() {
13741
- const self = this;
13742
- return this._texture || (this._texture = {
13743
- renderBuffer: this,
13744
- bind: function (unit) {
13745
- if (self.buffer && self.buffer.texture) {
13746
- self.gl.activeTexture(self.gl["TEXTURE" + unit]);
13747
- self.gl.bindTexture(self.gl.TEXTURE_2D, self.buffer.texture);
13748
- return true;
13749
- }
13750
- return false;
13751
- },
13752
- unbind: function (unit) {
13753
- if (self.buffer && self.buffer.texture) {
13754
- self.gl.activeTexture(self.gl["TEXTURE" + unit]);
13755
- self.gl.bindTexture(self.gl.TEXTURE_2D, null);
13756
- }
13757
- }
13758
- });
13759
- }
13760
-
13761
- hasDepthTexture() {
13762
- return this._hasDepthTexture;
13763
- }
13764
-
13765
- getDepthTexture() {
13766
- if (!this._hasDepthTexture) {
13767
- return null;
13768
- }
13769
- const self = this;
13770
- return this._depthTexture || (this._dethTexture = {
13771
- renderBuffer: this,
13772
- bind: function (unit) {
13773
- if (self.buffer && self.buffer.depthTexture) {
13774
- self.gl.activeTexture(self.gl["TEXTURE" + unit]);
13775
- self.gl.bindTexture(self.gl.TEXTURE_2D, self.buffer.depthTexture);
13776
- return true;
13777
- }
13778
- return false;
13779
- },
13780
- unbind: function (unit) {
13781
- if (self.buffer && self.buffer.depthTexture) {
13782
- self.gl.activeTexture(self.gl["TEXTURE" + unit]);
13783
- self.gl.bindTexture(self.gl.TEXTURE_2D, null);
13784
- }
13785
- }
13786
- });
13787
- }
13788
-
13789
- destroy() {
13790
- if (this.allocated) {
13791
- const gl = this.gl;
13792
- gl.deleteTexture(this.buffer.texture);
13793
- gl.deleteTexture(this.buffer.depthTexture);
13794
- gl.deleteFramebuffer(this.buffer.framebuf);
13795
- gl.deleteRenderbuffer(this.buffer.renderbuf);
13796
- this.allocated = false;
13797
- this.buffer = null;
13798
- this.bound = false;
13799
- }
13800
- this._imageDataCache = null;
13801
- this._texture = null;
13802
- this._depthTexture = null;
13803
- }
13804
- }
13805
-
13806
13279
  /**
13807
13280
  * @desc Represents a WebGL ArrayBuffer.
13808
13281
  *
@@ -14134,6 +13607,7 @@ class OcclusionLayer {
14134
13607
 
14135
13608
  const MARKER_COLOR = math.vec3([1.0, 0.0, 0.0]);
14136
13609
  const POINT_SIZE = 20;
13610
+ const MARKER_SPRITE_CLIPZ_OFFSET = -0.001; // Amount that we offset sprite clip Z coords to raise them from surfaces
14137
13611
 
14138
13612
  const tempVec3a$$ = math.vec3();
14139
13613
 
@@ -14343,7 +13817,6 @@ class OcclusionTester {
14343
13817
  src.push(" vWorldPosition = worldPosition;");
14344
13818
  }
14345
13819
  src.push(" vec4 clipPos = projMatrix * viewPosition;");
14346
- src.push(" gl_Position = clipPos;");
14347
13820
  src.push(" gl_PointSize = " + POINT_SIZE + ".0;");
14348
13821
  if (scene.logarithmicDepthBufferEnabled) {
14349
13822
  if (WEBGL_INFO$1.SUPPORTED_EXTENSIONS["EXT_frag_depth"]) {
@@ -14352,7 +13825,10 @@ class OcclusionTester {
14352
13825
  src.push("clipPos.z = log2( max( 1e-6, clipPos.w + 1.0 ) ) * logDepthBufFC - 1.0;");
14353
13826
  src.push("clipPos.z *= clipPos.w;");
14354
13827
  }
13828
+ } else {
13829
+ src.push("clipPos.z += " + MARKER_SPRITE_CLIPZ_OFFSET + ";");
14355
13830
  }
13831
+ src.push(" gl_Position = clipPos;");
14356
13832
  src.push("}");
14357
13833
  return src;
14358
13834
  }
@@ -15248,6 +14724,533 @@ function createSampleOffsets(kernelRadius, uvIncrement) {
15248
14724
  return offsets;
15249
14725
  }
15250
14726
 
14727
+ /*
14728
+ * Canvas2Image v0.1
14729
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
14730
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
14731
+ *
14732
+ * Modified by @xeolabs to permit vertical flipping, so that snapshot can be taken from WebGL frame buffers,
14733
+ * which vertically flip image data as part of the way that WebGL renders textures.
14734
+ */
14735
+
14736
+ /**
14737
+ * @private
14738
+ */
14739
+ const Canvas2Image = (function () {
14740
+ // check if we have canvas support
14741
+ const oCanvas = document.createElement("canvas"), sc = String.fromCharCode;
14742
+
14743
+ // no canvas, bail out.
14744
+ if (!oCanvas.getContext) {
14745
+ return {
14746
+ saveAsBMP: function () {
14747
+ },
14748
+ saveAsPNG: function () {
14749
+ },
14750
+ saveAsJPEG: function () {
14751
+ }
14752
+ }
14753
+ }
14754
+
14755
+ const bHasImageData = !!(oCanvas.getContext("2d").getImageData), bHasDataURL = !!(oCanvas.toDataURL),
14756
+ bHasBase64 = !!(window.btoa);
14757
+
14758
+ // ok, we're good
14759
+ const readCanvasData = function (oCanvas) {
14760
+ const iWidth = parseInt(oCanvas.width), iHeight = parseInt(oCanvas.height);
14761
+ return oCanvas.getContext("2d").getImageData(0, 0, iWidth, iHeight);
14762
+ };
14763
+
14764
+ // base64 encodes either a string or an array of charcodes
14765
+ const encodeData = function (data) {
14766
+ let i, aData, strData = "";
14767
+
14768
+ if (typeof data == "string") {
14769
+ strData = data;
14770
+ } else {
14771
+ aData = data;
14772
+ for (i = 0; i < aData.length; i++) {
14773
+ strData += sc(aData[i]);
14774
+ }
14775
+ }
14776
+ return btoa(strData);
14777
+ };
14778
+
14779
+ // creates a base64 encoded string containing BMP data takes an imagedata object as argument
14780
+ const createBMP = function (oData) {
14781
+ let strHeader = '';
14782
+ const iWidth = oData.width;
14783
+ const iHeight = oData.height;
14784
+
14785
+ strHeader += 'BM';
14786
+
14787
+ let iFileSize = iWidth * iHeight * 4 + 54; // total header size = 54 bytes
14788
+ strHeader += sc(iFileSize % 256);
14789
+ iFileSize = Math.floor(iFileSize / 256);
14790
+ strHeader += sc(iFileSize % 256);
14791
+ iFileSize = Math.floor(iFileSize / 256);
14792
+ strHeader += sc(iFileSize % 256);
14793
+ iFileSize = Math.floor(iFileSize / 256);
14794
+ strHeader += sc(iFileSize % 256);
14795
+
14796
+ strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset
14797
+ strHeader += sc(40, 0, 0, 0); // info header size
14798
+
14799
+ let iImageWidth = iWidth;
14800
+ strHeader += sc(iImageWidth % 256);
14801
+ iImageWidth = Math.floor(iImageWidth / 256);
14802
+ strHeader += sc(iImageWidth % 256);
14803
+ iImageWidth = Math.floor(iImageWidth / 256);
14804
+ strHeader += sc(iImageWidth % 256);
14805
+ iImageWidth = Math.floor(iImageWidth / 256);
14806
+ strHeader += sc(iImageWidth % 256);
14807
+
14808
+ let iImageHeight = iHeight;
14809
+ strHeader += sc(iImageHeight % 256);
14810
+ iImageHeight = Math.floor(iImageHeight / 256);
14811
+ strHeader += sc(iImageHeight % 256);
14812
+ iImageHeight = Math.floor(iImageHeight / 256);
14813
+ strHeader += sc(iImageHeight % 256);
14814
+ iImageHeight = Math.floor(iImageHeight / 256);
14815
+ strHeader += sc(iImageHeight % 256);
14816
+
14817
+ strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel
14818
+ strHeader += sc(0, 0, 0, 0); // compression = none
14819
+
14820
+ let iDataSize = iWidth * iHeight * 4;
14821
+ strHeader += sc(iDataSize % 256);
14822
+ iDataSize = Math.floor(iDataSize / 256);
14823
+ strHeader += sc(iDataSize % 256);
14824
+ iDataSize = Math.floor(iDataSize / 256);
14825
+ strHeader += sc(iDataSize % 256);
14826
+ iDataSize = Math.floor(iDataSize / 256);
14827
+ strHeader += sc(iDataSize % 256);
14828
+
14829
+ strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used
14830
+
14831
+ const aImgData = oData.data;
14832
+ let strPixelData = "";
14833
+ let x;
14834
+ let y = iHeight;
14835
+ let iOffsetX;
14836
+ let iOffsetY;
14837
+ let strPixelRow;
14838
+
14839
+ do {
14840
+ iOffsetY = iWidth * (y - 1) * 4;
14841
+ strPixelRow = "";
14842
+ for (x = 0; x < iWidth; x++) {
14843
+ iOffsetX = 4 * x;
14844
+ strPixelRow += sc(
14845
+ aImgData[iOffsetY + iOffsetX + 2], // B
14846
+ aImgData[iOffsetY + iOffsetX + 1], // G
14847
+ aImgData[iOffsetY + iOffsetX], // R
14848
+ aImgData[iOffsetY + iOffsetX + 3] // A
14849
+ );
14850
+ }
14851
+ strPixelData += strPixelRow;
14852
+ } while (--y);
14853
+
14854
+ return encodeData(strHeader + strPixelData);
14855
+ };
14856
+
14857
+ // sends the generated file to the client
14858
+ const saveFile = function (strData) {
14859
+ if (!window.open(strData)) {
14860
+ document.location.href = strData;
14861
+ }
14862
+ };
14863
+
14864
+ const makeDataURI = function (strData, strMime) {
14865
+ return "data:" + strMime + ";base64," + strData;
14866
+ };
14867
+
14868
+ // generates a <img> object containing the imagedata
14869
+ const makeImageObject = function (strSource) {
14870
+ const oImgElement = document.createElement("img");
14871
+ oImgElement.src = strSource;
14872
+ return oImgElement;
14873
+ };
14874
+
14875
+ const scaleCanvas = function (oCanvas, iWidth, iHeight, flipy) {
14876
+ if (iWidth && iHeight) {
14877
+ const oSaveCanvas = document.createElement("canvas");
14878
+ oSaveCanvas.width = iWidth;
14879
+ oSaveCanvas.height = iHeight;
14880
+ oSaveCanvas.style.width = iWidth + "px";
14881
+ oSaveCanvas.style.height = iHeight + "px";
14882
+ const oSaveCtx = oSaveCanvas.getContext("2d");
14883
+ if (flipy) {
14884
+ oSaveCtx.save();
14885
+ oSaveCtx.scale(1.0, -1.0);
14886
+ oSaveCtx.imageSmoothingEnabled = true;
14887
+ oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, -iHeight);
14888
+ oSaveCtx.restore();
14889
+ } else {
14890
+ oSaveCtx.imageSmoothingEnabled = true;
14891
+ oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iHeight);
14892
+ }
14893
+ return oSaveCanvas;
14894
+ }
14895
+ return oCanvas;
14896
+ };
14897
+
14898
+ return {
14899
+ saveAsPNG: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
14900
+ if (!bHasDataURL) return false;
14901
+ const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
14902
+ const strMime = "image/png";
14903
+ const strData = oScaledCanvas.toDataURL(strMime);
14904
+ if (bReturnImg) {
14905
+ return makeImageObject(strData);
14906
+ } else {
14907
+ saveFile(strData);
14908
+ }
14909
+ return true;
14910
+ },
14911
+
14912
+ saveAsJPEG: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
14913
+ if (!bHasDataURL) return false;
14914
+ const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
14915
+ const strMime = "image/jpeg";
14916
+ const strData = oScaledCanvas.toDataURL(strMime);
14917
+ // check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false
14918
+ if (strData.indexOf(strMime) != 5) return false;
14919
+ if (bReturnImg) {
14920
+ return makeImageObject(strData);
14921
+ } else {
14922
+ saveFile(strData);
14923
+ }
14924
+ return true;
14925
+ },
14926
+
14927
+ saveAsBMP: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
14928
+ if (!(bHasDataURL && bHasImageData && bHasBase64)) return false;
14929
+ const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
14930
+ const strMime = "image/bmp";
14931
+ const oData = readCanvasData(oScaledCanvas), strImgData = createBMP(oData);
14932
+ if (bReturnImg) {
14933
+ return makeImageObject(makeDataURI(strImgData, strMime));
14934
+ } else {
14935
+ saveFile(makeDataURI(strImgData, strMime));
14936
+ }
14937
+ return true;
14938
+ }
14939
+ };
14940
+ })();
14941
+
14942
+ /**
14943
+ * @desc Represents a WebGL render buffer.
14944
+ * @private
14945
+ */
14946
+ class RenderBuffer {
14947
+
14948
+ constructor(canvas, gl, options) {
14949
+ options = options || {};
14950
+ this.gl = gl;
14951
+ this.allocated = false;
14952
+ this.canvas = canvas;
14953
+ this.buffer = null;
14954
+ this.bound = false;
14955
+ this.size = options.size;
14956
+ this._hasDepthTexture = !!options.depthTexture;
14957
+ }
14958
+
14959
+ setSize(size) {
14960
+ this.size = size;
14961
+ }
14962
+
14963
+ webglContextRestored(gl) {
14964
+ this.gl = gl;
14965
+ this.buffer = null;
14966
+ this.allocated = false;
14967
+ this.bound = false;
14968
+ }
14969
+
14970
+ bind() {
14971
+ this._touch();
14972
+ if (this.bound) {
14973
+ return;
14974
+ }
14975
+ const gl = this.gl;
14976
+ gl.bindFramebuffer(gl.FRAMEBUFFER, this.buffer.framebuf);
14977
+ this.bound = true;
14978
+ }
14979
+
14980
+ _touch() {
14981
+
14982
+ let width;
14983
+ let height;
14984
+ const gl = this.gl;
14985
+
14986
+ if (this.size) {
14987
+ width = this.size[0];
14988
+ height = this.size[1];
14989
+
14990
+ } else {
14991
+ width = gl.drawingBufferWidth;
14992
+ height = gl.drawingBufferHeight;
14993
+ }
14994
+
14995
+ if (this.buffer) {
14996
+
14997
+ if (this.buffer.width === width && this.buffer.height === height) {
14998
+ return;
14999
+
15000
+ } else {
15001
+ gl.deleteTexture(this.buffer.texture);
15002
+ gl.deleteFramebuffer(this.buffer.framebuf);
15003
+ gl.deleteRenderbuffer(this.buffer.renderbuf);
15004
+ }
15005
+ }
15006
+
15007
+ const colorTexture = gl.createTexture();
15008
+ gl.bindTexture(gl.TEXTURE_2D, colorTexture);
15009
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
15010
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
15011
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
15012
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
15013
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
15014
+
15015
+ let depthTexture;
15016
+
15017
+ if (this._hasDepthTexture) {
15018
+ depthTexture = gl.createTexture();
15019
+ gl.bindTexture(gl.TEXTURE_2D, depthTexture);
15020
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
15021
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
15022
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
15023
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
15024
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
15025
+ }
15026
+
15027
+ const renderbuf = gl.createRenderbuffer();
15028
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuf);
15029
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
15030
+
15031
+ const framebuf = gl.createFramebuffer();
15032
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuf);
15033
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
15034
+
15035
+ if (this._hasDepthTexture) {
15036
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
15037
+ } else {
15038
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuf);
15039
+ }
15040
+
15041
+ gl.bindTexture(gl.TEXTURE_2D, null);
15042
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
15043
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
15044
+
15045
+ // Verify framebuffer is OK
15046
+
15047
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuf);
15048
+ if (!gl.isFramebuffer(framebuf)) {
15049
+ throw "Invalid framebuffer";
15050
+ }
15051
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
15052
+
15053
+ const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
15054
+
15055
+ switch (status) {
15056
+
15057
+ case gl.FRAMEBUFFER_COMPLETE:
15058
+ break;
15059
+
15060
+ case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
15061
+ throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
15062
+
15063
+ case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
15064
+ throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
15065
+
15066
+ case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
15067
+ throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
15068
+
15069
+ case gl.FRAMEBUFFER_UNSUPPORTED:
15070
+ throw "Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED";
15071
+
15072
+ default:
15073
+ throw "Incomplete framebuffer: " + status;
15074
+ }
15075
+
15076
+ this.buffer = {
15077
+ framebuf: framebuf,
15078
+ renderbuf: renderbuf,
15079
+ texture: colorTexture,
15080
+ depthTexture: depthTexture,
15081
+ width: width,
15082
+ height: height
15083
+ };
15084
+
15085
+ this.bound = false;
15086
+ }
15087
+
15088
+ clear() {
15089
+ if (!this.bound) {
15090
+ throw "Render buffer not bound";
15091
+ }
15092
+ const gl = this.gl;
15093
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
15094
+ }
15095
+
15096
+ read(pickX, pickY) {
15097
+ const x = pickX;
15098
+ const y = this.gl.drawingBufferHeight - pickY;
15099
+ const pix = new Uint8Array(4);
15100
+ const gl = this.gl;
15101
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix);
15102
+ return pix;
15103
+ }
15104
+
15105
+ readImage(params) {
15106
+
15107
+ const gl = this.gl;
15108
+ const imageDataCache = this._getImageDataCache();
15109
+ const pixelData = imageDataCache.pixelData;
15110
+ const canvas = imageDataCache.canvas;
15111
+ const imageData = imageDataCache.imageData;
15112
+ const context = imageDataCache.context;
15113
+
15114
+ gl.readPixels(0, 0, this.buffer.width, this.buffer.height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
15115
+
15116
+ imageData.data.set(pixelData);
15117
+ context.putImageData(imageData, 0, 0);
15118
+
15119
+ const imageWidth = params.width || canvas.width;
15120
+ const imageHeight = params.height || canvas.height;
15121
+ const format = params.format || "jpeg";
15122
+ const flipy = true; // Account for WebGL texture flipping
15123
+
15124
+ let image;
15125
+
15126
+ switch (format) {
15127
+ case "jpeg":
15128
+ image = Canvas2Image.saveAsJPEG(canvas, true, imageWidth, imageHeight, flipy);
15129
+ break;
15130
+ case "png":
15131
+ image = Canvas2Image.saveAsPNG(canvas, true, imageWidth, imageHeight, flipy);
15132
+ break;
15133
+ case "bmp":
15134
+ image = Canvas2Image.saveAsBMP(canvas, true, imageWidth, imageHeight, flipy);
15135
+ break;
15136
+ default:
15137
+ console.error("Unsupported image format: '" + format + "' - supported types are 'jpeg', 'bmp' and 'png' - defaulting to 'jpeg'");
15138
+ image = Canvas2Image.saveAsJPEG(canvas, true, imageWidth, imageHeight, flipy);
15139
+ }
15140
+
15141
+ return image.src;
15142
+ }
15143
+
15144
+ _getImageDataCache() {
15145
+
15146
+ const bufferWidth = this.buffer.width;
15147
+ const bufferHeight = this.buffer.height;
15148
+
15149
+ let imageDataCache = this._imageDataCache;
15150
+
15151
+ if (imageDataCache) {
15152
+ if (imageDataCache.width !== bufferWidth || imageDataCache.height !== bufferHeight) {
15153
+ this._imageDataCache = null;
15154
+ imageDataCache = null;
15155
+ }
15156
+ }
15157
+
15158
+ if (!imageDataCache) {
15159
+
15160
+ const canvas = document.createElement('canvas');
15161
+ canvas.width = bufferWidth;
15162
+ canvas.height = bufferHeight;
15163
+
15164
+ const context = canvas.getContext('2d');
15165
+ const imageData = context.createImageData(bufferWidth, bufferHeight);
15166
+
15167
+ imageDataCache = {
15168
+ pixelData: new Uint8Array(bufferWidth * bufferHeight * 4),
15169
+ canvas: canvas,
15170
+ context: context,
15171
+ imageData: imageData,
15172
+ width: bufferWidth,
15173
+ height: bufferHeight
15174
+ };
15175
+
15176
+ this._imageDataCache = imageDataCache;
15177
+ }
15178
+
15179
+ return imageDataCache;
15180
+ }
15181
+
15182
+ unbind() {
15183
+ const gl = this.gl;
15184
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
15185
+ this.bound = false;
15186
+ }
15187
+
15188
+ getTexture() {
15189
+ const self = this;
15190
+ return this._texture || (this._texture = {
15191
+ renderBuffer: this,
15192
+ bind: function (unit) {
15193
+ if (self.buffer && self.buffer.texture) {
15194
+ self.gl.activeTexture(self.gl["TEXTURE" + unit]);
15195
+ self.gl.bindTexture(self.gl.TEXTURE_2D, self.buffer.texture);
15196
+ return true;
15197
+ }
15198
+ return false;
15199
+ },
15200
+ unbind: function (unit) {
15201
+ if (self.buffer && self.buffer.texture) {
15202
+ self.gl.activeTexture(self.gl["TEXTURE" + unit]);
15203
+ self.gl.bindTexture(self.gl.TEXTURE_2D, null);
15204
+ }
15205
+ }
15206
+ });
15207
+ }
15208
+
15209
+ hasDepthTexture() {
15210
+ return this._hasDepthTexture;
15211
+ }
15212
+
15213
+ getDepthTexture() {
15214
+ if (!this._hasDepthTexture) {
15215
+ return null;
15216
+ }
15217
+ const self = this;
15218
+ return this._depthTexture || (this._dethTexture = {
15219
+ renderBuffer: this,
15220
+ bind: function (unit) {
15221
+ if (self.buffer && self.buffer.depthTexture) {
15222
+ self.gl.activeTexture(self.gl["TEXTURE" + unit]);
15223
+ self.gl.bindTexture(self.gl.TEXTURE_2D, self.buffer.depthTexture);
15224
+ return true;
15225
+ }
15226
+ return false;
15227
+ },
15228
+ unbind: function (unit) {
15229
+ if (self.buffer && self.buffer.depthTexture) {
15230
+ self.gl.activeTexture(self.gl["TEXTURE" + unit]);
15231
+ self.gl.bindTexture(self.gl.TEXTURE_2D, null);
15232
+ }
15233
+ }
15234
+ });
15235
+ }
15236
+
15237
+ destroy() {
15238
+ if (this.allocated) {
15239
+ const gl = this.gl;
15240
+ gl.deleteTexture(this.buffer.texture);
15241
+ gl.deleteTexture(this.buffer.depthTexture);
15242
+ gl.deleteFramebuffer(this.buffer.framebuf);
15243
+ gl.deleteRenderbuffer(this.buffer.renderbuf);
15244
+ this.allocated = false;
15245
+ this.buffer = null;
15246
+ this.bound = false;
15247
+ }
15248
+ this._imageDataCache = null;
15249
+ this._texture = null;
15250
+ this._depthTexture = null;
15251
+ }
15252
+ }
15253
+
15251
15254
  /**
15252
15255
  * @private
15253
15256
  */
@@ -31846,6 +31849,7 @@ function buildVertex$1(mesh) {
31846
31849
  }
31847
31850
  src.push("void main(void) {");
31848
31851
  src.push("vec4 localPosition = vec4(position, 1.0); ");
31852
+ src.push("vec4 worldPosition;");
31849
31853
  if (quantizedGeometry) {
31850
31854
  src.push("localPosition = positionsDecodeMatrix * localPosition;");
31851
31855
  }
@@ -31858,10 +31862,15 @@ function buildVertex$1(mesh) {
31858
31862
  src.push("mat4 modelViewMatrix = viewMatrix2 * modelMatrix2;");
31859
31863
  src.push("billboard(modelMatrix2);");
31860
31864
  src.push("billboard(viewMatrix2);");
31865
+ src.push("billboard(modelViewMatrix);");
31866
+ src.push("worldPosition = modelMatrix2 * localPosition;");
31867
+ src.push("worldPosition.xyz = worldPosition.xyz + offset;");
31868
+ src.push("vec4 viewPosition = modelViewMatrix * localPosition;");
31869
+ } else {
31870
+ src.push("worldPosition = modelMatrix2 * localPosition;");
31871
+ src.push("worldPosition.xyz = worldPosition.xyz + offset;");
31872
+ src.push("vec4 viewPosition = viewMatrix2 * worldPosition; ");
31861
31873
  }
31862
- src.push(" vec4 worldPosition = modelMatrix2 * localPosition;");
31863
- src.push(" worldPosition.xyz = worldPosition.xyz + offset;");
31864
- src.push(" vec4 viewPosition = viewMatrix2 * worldPosition;");
31865
31874
  if (clipping) {
31866
31875
  src.push(" vWorldPosition = worldPosition;");
31867
31876
  }
@@ -31968,7 +31977,7 @@ OcclusionRenderer.get = function (mesh) {
31968
31977
  mesh.scene.canvas.canvas.id,
31969
31978
  mesh.scene._sectionPlanesState.getHash(),
31970
31979
  mesh._geometry._state.hash,
31971
- mesh._state.hash
31980
+ mesh._state.occlusionHash
31972
31981
  ].join(";");
31973
31982
  let renderer = renderers$1[hash];
31974
31983
  if (!renderer) {
@@ -148534,7 +148543,7 @@ class Configs {
148534
148543
  }
148535
148544
 
148536
148545
  /**
148537
- * Experimental {@link Viewer} plugin that uses [web-ifc](https://github.com/tomvandig/web-ifc) to load BIM models directly from IFC files.
148546
+ * {@link Viewer} plugin that uses [web-ifc](https://github.com/tomvandig/web-ifc) to load BIM models directly from IFC files.
148538
148547
  *
148539
148548
  * <a href="https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_WebIFCLoaderPlugin_Duplex"><img src="https://xeokit.io/img/docs/WebIFCLoaderPlugin/WebIFCLoaderPlugin.png"></a>
148540
148549
  *
@@ -152104,12 +152113,7 @@ class LASLoaderPlugin extends Plugin {
152104
152113
  }
152105
152114
 
152106
152115
  const performanceModel = new PerformanceModel(this.viewer.scene, utils.apply(params, {
152107
- isModel: true,
152108
- origin: params.origin,
152109
- position: params.position,
152110
- scale: params.scale,
152111
- rotation: params.rotation,
152112
- matrix: params.matrix
152116
+ isModel: true
152113
152117
  }));
152114
152118
 
152115
152119
  if (!params.src && !params.las) {