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