@xeokit/xeokit-sdk 2.2.1-beta.1 → 2.2.1-beta.2
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/dist/xeokit-sdk.cjs.js +539 -538
- package/dist/xeokit-sdk.es.js +539 -538
- 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.es.js
CHANGED
|
@@ -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
|
*
|
|
@@ -15248,6 +14721,533 @@ function createSampleOffsets(kernelRadius, uvIncrement) {
|
|
|
15248
14721
|
return offsets;
|
|
15249
14722
|
}
|
|
15250
14723
|
|
|
14724
|
+
/*
|
|
14725
|
+
* Canvas2Image v0.1
|
|
14726
|
+
* Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
|
|
14727
|
+
* MIT License [http://www.opensource.org/licenses/mit-license.php]
|
|
14728
|
+
*
|
|
14729
|
+
* Modified by @xeolabs to permit vertical flipping, so that snapshot can be taken from WebGL frame buffers,
|
|
14730
|
+
* which vertically flip image data as part of the way that WebGL renders textures.
|
|
14731
|
+
*/
|
|
14732
|
+
|
|
14733
|
+
/**
|
|
14734
|
+
* @private
|
|
14735
|
+
*/
|
|
14736
|
+
const Canvas2Image = (function () {
|
|
14737
|
+
// check if we have canvas support
|
|
14738
|
+
const oCanvas = document.createElement("canvas"), sc = String.fromCharCode;
|
|
14739
|
+
|
|
14740
|
+
// no canvas, bail out.
|
|
14741
|
+
if (!oCanvas.getContext) {
|
|
14742
|
+
return {
|
|
14743
|
+
saveAsBMP: function () {
|
|
14744
|
+
},
|
|
14745
|
+
saveAsPNG: function () {
|
|
14746
|
+
},
|
|
14747
|
+
saveAsJPEG: function () {
|
|
14748
|
+
}
|
|
14749
|
+
}
|
|
14750
|
+
}
|
|
14751
|
+
|
|
14752
|
+
const bHasImageData = !!(oCanvas.getContext("2d").getImageData), bHasDataURL = !!(oCanvas.toDataURL),
|
|
14753
|
+
bHasBase64 = !!(window.btoa);
|
|
14754
|
+
|
|
14755
|
+
// ok, we're good
|
|
14756
|
+
const readCanvasData = function (oCanvas) {
|
|
14757
|
+
const iWidth = parseInt(oCanvas.width), iHeight = parseInt(oCanvas.height);
|
|
14758
|
+
return oCanvas.getContext("2d").getImageData(0, 0, iWidth, iHeight);
|
|
14759
|
+
};
|
|
14760
|
+
|
|
14761
|
+
// base64 encodes either a string or an array of charcodes
|
|
14762
|
+
const encodeData = function (data) {
|
|
14763
|
+
let i, aData, strData = "";
|
|
14764
|
+
|
|
14765
|
+
if (typeof data == "string") {
|
|
14766
|
+
strData = data;
|
|
14767
|
+
} else {
|
|
14768
|
+
aData = data;
|
|
14769
|
+
for (i = 0; i < aData.length; i++) {
|
|
14770
|
+
strData += sc(aData[i]);
|
|
14771
|
+
}
|
|
14772
|
+
}
|
|
14773
|
+
return btoa(strData);
|
|
14774
|
+
};
|
|
14775
|
+
|
|
14776
|
+
// creates a base64 encoded string containing BMP data takes an imagedata object as argument
|
|
14777
|
+
const createBMP = function (oData) {
|
|
14778
|
+
let strHeader = '';
|
|
14779
|
+
const iWidth = oData.width;
|
|
14780
|
+
const iHeight = oData.height;
|
|
14781
|
+
|
|
14782
|
+
strHeader += 'BM';
|
|
14783
|
+
|
|
14784
|
+
let iFileSize = iWidth * iHeight * 4 + 54; // total header size = 54 bytes
|
|
14785
|
+
strHeader += sc(iFileSize % 256);
|
|
14786
|
+
iFileSize = Math.floor(iFileSize / 256);
|
|
14787
|
+
strHeader += sc(iFileSize % 256);
|
|
14788
|
+
iFileSize = Math.floor(iFileSize / 256);
|
|
14789
|
+
strHeader += sc(iFileSize % 256);
|
|
14790
|
+
iFileSize = Math.floor(iFileSize / 256);
|
|
14791
|
+
strHeader += sc(iFileSize % 256);
|
|
14792
|
+
|
|
14793
|
+
strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset
|
|
14794
|
+
strHeader += sc(40, 0, 0, 0); // info header size
|
|
14795
|
+
|
|
14796
|
+
let iImageWidth = iWidth;
|
|
14797
|
+
strHeader += sc(iImageWidth % 256);
|
|
14798
|
+
iImageWidth = Math.floor(iImageWidth / 256);
|
|
14799
|
+
strHeader += sc(iImageWidth % 256);
|
|
14800
|
+
iImageWidth = Math.floor(iImageWidth / 256);
|
|
14801
|
+
strHeader += sc(iImageWidth % 256);
|
|
14802
|
+
iImageWidth = Math.floor(iImageWidth / 256);
|
|
14803
|
+
strHeader += sc(iImageWidth % 256);
|
|
14804
|
+
|
|
14805
|
+
let iImageHeight = iHeight;
|
|
14806
|
+
strHeader += sc(iImageHeight % 256);
|
|
14807
|
+
iImageHeight = Math.floor(iImageHeight / 256);
|
|
14808
|
+
strHeader += sc(iImageHeight % 256);
|
|
14809
|
+
iImageHeight = Math.floor(iImageHeight / 256);
|
|
14810
|
+
strHeader += sc(iImageHeight % 256);
|
|
14811
|
+
iImageHeight = Math.floor(iImageHeight / 256);
|
|
14812
|
+
strHeader += sc(iImageHeight % 256);
|
|
14813
|
+
|
|
14814
|
+
strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel
|
|
14815
|
+
strHeader += sc(0, 0, 0, 0); // compression = none
|
|
14816
|
+
|
|
14817
|
+
let iDataSize = iWidth * iHeight * 4;
|
|
14818
|
+
strHeader += sc(iDataSize % 256);
|
|
14819
|
+
iDataSize = Math.floor(iDataSize / 256);
|
|
14820
|
+
strHeader += sc(iDataSize % 256);
|
|
14821
|
+
iDataSize = Math.floor(iDataSize / 256);
|
|
14822
|
+
strHeader += sc(iDataSize % 256);
|
|
14823
|
+
iDataSize = Math.floor(iDataSize / 256);
|
|
14824
|
+
strHeader += sc(iDataSize % 256);
|
|
14825
|
+
|
|
14826
|
+
strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used
|
|
14827
|
+
|
|
14828
|
+
const aImgData = oData.data;
|
|
14829
|
+
let strPixelData = "";
|
|
14830
|
+
let x;
|
|
14831
|
+
let y = iHeight;
|
|
14832
|
+
let iOffsetX;
|
|
14833
|
+
let iOffsetY;
|
|
14834
|
+
let strPixelRow;
|
|
14835
|
+
|
|
14836
|
+
do {
|
|
14837
|
+
iOffsetY = iWidth * (y - 1) * 4;
|
|
14838
|
+
strPixelRow = "";
|
|
14839
|
+
for (x = 0; x < iWidth; x++) {
|
|
14840
|
+
iOffsetX = 4 * x;
|
|
14841
|
+
strPixelRow += sc(
|
|
14842
|
+
aImgData[iOffsetY + iOffsetX + 2], // B
|
|
14843
|
+
aImgData[iOffsetY + iOffsetX + 1], // G
|
|
14844
|
+
aImgData[iOffsetY + iOffsetX], // R
|
|
14845
|
+
aImgData[iOffsetY + iOffsetX + 3] // A
|
|
14846
|
+
);
|
|
14847
|
+
}
|
|
14848
|
+
strPixelData += strPixelRow;
|
|
14849
|
+
} while (--y);
|
|
14850
|
+
|
|
14851
|
+
return encodeData(strHeader + strPixelData);
|
|
14852
|
+
};
|
|
14853
|
+
|
|
14854
|
+
// sends the generated file to the client
|
|
14855
|
+
const saveFile = function (strData) {
|
|
14856
|
+
if (!window.open(strData)) {
|
|
14857
|
+
document.location.href = strData;
|
|
14858
|
+
}
|
|
14859
|
+
};
|
|
14860
|
+
|
|
14861
|
+
const makeDataURI = function (strData, strMime) {
|
|
14862
|
+
return "data:" + strMime + ";base64," + strData;
|
|
14863
|
+
};
|
|
14864
|
+
|
|
14865
|
+
// generates a <img> object containing the imagedata
|
|
14866
|
+
const makeImageObject = function (strSource) {
|
|
14867
|
+
const oImgElement = document.createElement("img");
|
|
14868
|
+
oImgElement.src = strSource;
|
|
14869
|
+
return oImgElement;
|
|
14870
|
+
};
|
|
14871
|
+
|
|
14872
|
+
const scaleCanvas = function (oCanvas, iWidth, iHeight, flipy) {
|
|
14873
|
+
if (iWidth && iHeight) {
|
|
14874
|
+
const oSaveCanvas = document.createElement("canvas");
|
|
14875
|
+
oSaveCanvas.width = iWidth;
|
|
14876
|
+
oSaveCanvas.height = iHeight;
|
|
14877
|
+
oSaveCanvas.style.width = iWidth + "px";
|
|
14878
|
+
oSaveCanvas.style.height = iHeight + "px";
|
|
14879
|
+
const oSaveCtx = oSaveCanvas.getContext("2d");
|
|
14880
|
+
if (flipy) {
|
|
14881
|
+
oSaveCtx.save();
|
|
14882
|
+
oSaveCtx.scale(1.0, -1.0);
|
|
14883
|
+
oSaveCtx.imageSmoothingEnabled = true;
|
|
14884
|
+
oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, -iHeight);
|
|
14885
|
+
oSaveCtx.restore();
|
|
14886
|
+
} else {
|
|
14887
|
+
oSaveCtx.imageSmoothingEnabled = true;
|
|
14888
|
+
oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iHeight);
|
|
14889
|
+
}
|
|
14890
|
+
return oSaveCanvas;
|
|
14891
|
+
}
|
|
14892
|
+
return oCanvas;
|
|
14893
|
+
};
|
|
14894
|
+
|
|
14895
|
+
return {
|
|
14896
|
+
saveAsPNG: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
|
|
14897
|
+
if (!bHasDataURL) return false;
|
|
14898
|
+
const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
|
|
14899
|
+
const strMime = "image/png";
|
|
14900
|
+
const strData = oScaledCanvas.toDataURL(strMime);
|
|
14901
|
+
if (bReturnImg) {
|
|
14902
|
+
return makeImageObject(strData);
|
|
14903
|
+
} else {
|
|
14904
|
+
saveFile(strData);
|
|
14905
|
+
}
|
|
14906
|
+
return true;
|
|
14907
|
+
},
|
|
14908
|
+
|
|
14909
|
+
saveAsJPEG: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
|
|
14910
|
+
if (!bHasDataURL) return false;
|
|
14911
|
+
const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
|
|
14912
|
+
const strMime = "image/jpeg";
|
|
14913
|
+
const strData = oScaledCanvas.toDataURL(strMime);
|
|
14914
|
+
// check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false
|
|
14915
|
+
if (strData.indexOf(strMime) != 5) return false;
|
|
14916
|
+
if (bReturnImg) {
|
|
14917
|
+
return makeImageObject(strData);
|
|
14918
|
+
} else {
|
|
14919
|
+
saveFile(strData);
|
|
14920
|
+
}
|
|
14921
|
+
return true;
|
|
14922
|
+
},
|
|
14923
|
+
|
|
14924
|
+
saveAsBMP: function (oCanvas, bReturnImg, iWidth, iHeight, flipy) {
|
|
14925
|
+
if (!(bHasDataURL && bHasImageData && bHasBase64)) return false;
|
|
14926
|
+
const oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight, flipy);
|
|
14927
|
+
const strMime = "image/bmp";
|
|
14928
|
+
const oData = readCanvasData(oScaledCanvas), strImgData = createBMP(oData);
|
|
14929
|
+
if (bReturnImg) {
|
|
14930
|
+
return makeImageObject(makeDataURI(strImgData, strMime));
|
|
14931
|
+
} else {
|
|
14932
|
+
saveFile(makeDataURI(strImgData, strMime));
|
|
14933
|
+
}
|
|
14934
|
+
return true;
|
|
14935
|
+
}
|
|
14936
|
+
};
|
|
14937
|
+
})();
|
|
14938
|
+
|
|
14939
|
+
/**
|
|
14940
|
+
* @desc Represents a WebGL render buffer.
|
|
14941
|
+
* @private
|
|
14942
|
+
*/
|
|
14943
|
+
class RenderBuffer {
|
|
14944
|
+
|
|
14945
|
+
constructor(canvas, gl, options) {
|
|
14946
|
+
options = options || {};
|
|
14947
|
+
this.gl = gl;
|
|
14948
|
+
this.allocated = false;
|
|
14949
|
+
this.canvas = canvas;
|
|
14950
|
+
this.buffer = null;
|
|
14951
|
+
this.bound = false;
|
|
14952
|
+
this.size = options.size;
|
|
14953
|
+
this._hasDepthTexture = !!options.depthTexture;
|
|
14954
|
+
}
|
|
14955
|
+
|
|
14956
|
+
setSize(size) {
|
|
14957
|
+
this.size = size;
|
|
14958
|
+
}
|
|
14959
|
+
|
|
14960
|
+
webglContextRestored(gl) {
|
|
14961
|
+
this.gl = gl;
|
|
14962
|
+
this.buffer = null;
|
|
14963
|
+
this.allocated = false;
|
|
14964
|
+
this.bound = false;
|
|
14965
|
+
}
|
|
14966
|
+
|
|
14967
|
+
bind() {
|
|
14968
|
+
this._touch();
|
|
14969
|
+
if (this.bound) {
|
|
14970
|
+
return;
|
|
14971
|
+
}
|
|
14972
|
+
const gl = this.gl;
|
|
14973
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.buffer.framebuf);
|
|
14974
|
+
this.bound = true;
|
|
14975
|
+
}
|
|
14976
|
+
|
|
14977
|
+
_touch() {
|
|
14978
|
+
|
|
14979
|
+
let width;
|
|
14980
|
+
let height;
|
|
14981
|
+
const gl = this.gl;
|
|
14982
|
+
|
|
14983
|
+
if (this.size) {
|
|
14984
|
+
width = this.size[0];
|
|
14985
|
+
height = this.size[1];
|
|
14986
|
+
|
|
14987
|
+
} else {
|
|
14988
|
+
width = gl.drawingBufferWidth;
|
|
14989
|
+
height = gl.drawingBufferHeight;
|
|
14990
|
+
}
|
|
14991
|
+
|
|
14992
|
+
if (this.buffer) {
|
|
14993
|
+
|
|
14994
|
+
if (this.buffer.width === width && this.buffer.height === height) {
|
|
14995
|
+
return;
|
|
14996
|
+
|
|
14997
|
+
} else {
|
|
14998
|
+
gl.deleteTexture(this.buffer.texture);
|
|
14999
|
+
gl.deleteFramebuffer(this.buffer.framebuf);
|
|
15000
|
+
gl.deleteRenderbuffer(this.buffer.renderbuf);
|
|
15001
|
+
}
|
|
15002
|
+
}
|
|
15003
|
+
|
|
15004
|
+
const colorTexture = gl.createTexture();
|
|
15005
|
+
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
15006
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
15007
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
15008
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
15009
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
15010
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
15011
|
+
|
|
15012
|
+
let depthTexture;
|
|
15013
|
+
|
|
15014
|
+
if (this._hasDepthTexture) {
|
|
15015
|
+
depthTexture = gl.createTexture();
|
|
15016
|
+
gl.bindTexture(gl.TEXTURE_2D, depthTexture);
|
|
15017
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
15018
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
15019
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
15020
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
15021
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
|
|
15022
|
+
}
|
|
15023
|
+
|
|
15024
|
+
const renderbuf = gl.createRenderbuffer();
|
|
15025
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuf);
|
|
15026
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
|
|
15027
|
+
|
|
15028
|
+
const framebuf = gl.createFramebuffer();
|
|
15029
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuf);
|
|
15030
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
|
|
15031
|
+
|
|
15032
|
+
if (this._hasDepthTexture) {
|
|
15033
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
|
|
15034
|
+
} else {
|
|
15035
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuf);
|
|
15036
|
+
}
|
|
15037
|
+
|
|
15038
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
15039
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
15040
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
15041
|
+
|
|
15042
|
+
// Verify framebuffer is OK
|
|
15043
|
+
|
|
15044
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuf);
|
|
15045
|
+
if (!gl.isFramebuffer(framebuf)) {
|
|
15046
|
+
throw "Invalid framebuffer";
|
|
15047
|
+
}
|
|
15048
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
15049
|
+
|
|
15050
|
+
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
|
15051
|
+
|
|
15052
|
+
switch (status) {
|
|
15053
|
+
|
|
15054
|
+
case gl.FRAMEBUFFER_COMPLETE:
|
|
15055
|
+
break;
|
|
15056
|
+
|
|
15057
|
+
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
|
15058
|
+
throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
|
15059
|
+
|
|
15060
|
+
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
|
15061
|
+
throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
|
15062
|
+
|
|
15063
|
+
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
|
|
15064
|
+
throw "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
|
|
15065
|
+
|
|
15066
|
+
case gl.FRAMEBUFFER_UNSUPPORTED:
|
|
15067
|
+
throw "Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED";
|
|
15068
|
+
|
|
15069
|
+
default:
|
|
15070
|
+
throw "Incomplete framebuffer: " + status;
|
|
15071
|
+
}
|
|
15072
|
+
|
|
15073
|
+
this.buffer = {
|
|
15074
|
+
framebuf: framebuf,
|
|
15075
|
+
renderbuf: renderbuf,
|
|
15076
|
+
texture: colorTexture,
|
|
15077
|
+
depthTexture: depthTexture,
|
|
15078
|
+
width: width,
|
|
15079
|
+
height: height
|
|
15080
|
+
};
|
|
15081
|
+
|
|
15082
|
+
this.bound = false;
|
|
15083
|
+
}
|
|
15084
|
+
|
|
15085
|
+
clear() {
|
|
15086
|
+
if (!this.bound) {
|
|
15087
|
+
throw "Render buffer not bound";
|
|
15088
|
+
}
|
|
15089
|
+
const gl = this.gl;
|
|
15090
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
15091
|
+
}
|
|
15092
|
+
|
|
15093
|
+
read(pickX, pickY) {
|
|
15094
|
+
const x = pickX;
|
|
15095
|
+
const y = this.gl.drawingBufferHeight - pickY;
|
|
15096
|
+
const pix = new Uint8Array(4);
|
|
15097
|
+
const gl = this.gl;
|
|
15098
|
+
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix);
|
|
15099
|
+
return pix;
|
|
15100
|
+
}
|
|
15101
|
+
|
|
15102
|
+
readImage(params) {
|
|
15103
|
+
|
|
15104
|
+
const gl = this.gl;
|
|
15105
|
+
const imageDataCache = this._getImageDataCache();
|
|
15106
|
+
const pixelData = imageDataCache.pixelData;
|
|
15107
|
+
const canvas = imageDataCache.canvas;
|
|
15108
|
+
const imageData = imageDataCache.imageData;
|
|
15109
|
+
const context = imageDataCache.context;
|
|
15110
|
+
|
|
15111
|
+
gl.readPixels(0, 0, this.buffer.width, this.buffer.height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
|
|
15112
|
+
|
|
15113
|
+
imageData.data.set(pixelData);
|
|
15114
|
+
context.putImageData(imageData, 0, 0);
|
|
15115
|
+
|
|
15116
|
+
const imageWidth = params.width || canvas.width;
|
|
15117
|
+
const imageHeight = params.height || canvas.height;
|
|
15118
|
+
const format = params.format || "jpeg";
|
|
15119
|
+
const flipy = true; // Account for WebGL texture flipping
|
|
15120
|
+
|
|
15121
|
+
let image;
|
|
15122
|
+
|
|
15123
|
+
switch (format) {
|
|
15124
|
+
case "jpeg":
|
|
15125
|
+
image = Canvas2Image.saveAsJPEG(canvas, true, imageWidth, imageHeight, flipy);
|
|
15126
|
+
break;
|
|
15127
|
+
case "png":
|
|
15128
|
+
image = Canvas2Image.saveAsPNG(canvas, true, imageWidth, imageHeight, flipy);
|
|
15129
|
+
break;
|
|
15130
|
+
case "bmp":
|
|
15131
|
+
image = Canvas2Image.saveAsBMP(canvas, true, imageWidth, imageHeight, flipy);
|
|
15132
|
+
break;
|
|
15133
|
+
default:
|
|
15134
|
+
console.error("Unsupported image format: '" + format + "' - supported types are 'jpeg', 'bmp' and 'png' - defaulting to 'jpeg'");
|
|
15135
|
+
image = Canvas2Image.saveAsJPEG(canvas, true, imageWidth, imageHeight, flipy);
|
|
15136
|
+
}
|
|
15137
|
+
|
|
15138
|
+
return image.src;
|
|
15139
|
+
}
|
|
15140
|
+
|
|
15141
|
+
_getImageDataCache() {
|
|
15142
|
+
|
|
15143
|
+
const bufferWidth = this.buffer.width;
|
|
15144
|
+
const bufferHeight = this.buffer.height;
|
|
15145
|
+
|
|
15146
|
+
let imageDataCache = this._imageDataCache;
|
|
15147
|
+
|
|
15148
|
+
if (imageDataCache) {
|
|
15149
|
+
if (imageDataCache.width !== bufferWidth || imageDataCache.height !== bufferHeight) {
|
|
15150
|
+
this._imageDataCache = null;
|
|
15151
|
+
imageDataCache = null;
|
|
15152
|
+
}
|
|
15153
|
+
}
|
|
15154
|
+
|
|
15155
|
+
if (!imageDataCache) {
|
|
15156
|
+
|
|
15157
|
+
const canvas = document.createElement('canvas');
|
|
15158
|
+
canvas.width = bufferWidth;
|
|
15159
|
+
canvas.height = bufferHeight;
|
|
15160
|
+
|
|
15161
|
+
const context = canvas.getContext('2d');
|
|
15162
|
+
const imageData = context.createImageData(bufferWidth, bufferHeight);
|
|
15163
|
+
|
|
15164
|
+
imageDataCache = {
|
|
15165
|
+
pixelData: new Uint8Array(bufferWidth * bufferHeight * 4),
|
|
15166
|
+
canvas: canvas,
|
|
15167
|
+
context: context,
|
|
15168
|
+
imageData: imageData,
|
|
15169
|
+
width: bufferWidth,
|
|
15170
|
+
height: bufferHeight
|
|
15171
|
+
};
|
|
15172
|
+
|
|
15173
|
+
this._imageDataCache = imageDataCache;
|
|
15174
|
+
}
|
|
15175
|
+
|
|
15176
|
+
return imageDataCache;
|
|
15177
|
+
}
|
|
15178
|
+
|
|
15179
|
+
unbind() {
|
|
15180
|
+
const gl = this.gl;
|
|
15181
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
15182
|
+
this.bound = false;
|
|
15183
|
+
}
|
|
15184
|
+
|
|
15185
|
+
getTexture() {
|
|
15186
|
+
const self = this;
|
|
15187
|
+
return this._texture || (this._texture = {
|
|
15188
|
+
renderBuffer: this,
|
|
15189
|
+
bind: function (unit) {
|
|
15190
|
+
if (self.buffer && self.buffer.texture) {
|
|
15191
|
+
self.gl.activeTexture(self.gl["TEXTURE" + unit]);
|
|
15192
|
+
self.gl.bindTexture(self.gl.TEXTURE_2D, self.buffer.texture);
|
|
15193
|
+
return true;
|
|
15194
|
+
}
|
|
15195
|
+
return false;
|
|
15196
|
+
},
|
|
15197
|
+
unbind: function (unit) {
|
|
15198
|
+
if (self.buffer && self.buffer.texture) {
|
|
15199
|
+
self.gl.activeTexture(self.gl["TEXTURE" + unit]);
|
|
15200
|
+
self.gl.bindTexture(self.gl.TEXTURE_2D, null);
|
|
15201
|
+
}
|
|
15202
|
+
}
|
|
15203
|
+
});
|
|
15204
|
+
}
|
|
15205
|
+
|
|
15206
|
+
hasDepthTexture() {
|
|
15207
|
+
return this._hasDepthTexture;
|
|
15208
|
+
}
|
|
15209
|
+
|
|
15210
|
+
getDepthTexture() {
|
|
15211
|
+
if (!this._hasDepthTexture) {
|
|
15212
|
+
return null;
|
|
15213
|
+
}
|
|
15214
|
+
const self = this;
|
|
15215
|
+
return this._depthTexture || (this._dethTexture = {
|
|
15216
|
+
renderBuffer: this,
|
|
15217
|
+
bind: function (unit) {
|
|
15218
|
+
if (self.buffer && self.buffer.depthTexture) {
|
|
15219
|
+
self.gl.activeTexture(self.gl["TEXTURE" + unit]);
|
|
15220
|
+
self.gl.bindTexture(self.gl.TEXTURE_2D, self.buffer.depthTexture);
|
|
15221
|
+
return true;
|
|
15222
|
+
}
|
|
15223
|
+
return false;
|
|
15224
|
+
},
|
|
15225
|
+
unbind: function (unit) {
|
|
15226
|
+
if (self.buffer && self.buffer.depthTexture) {
|
|
15227
|
+
self.gl.activeTexture(self.gl["TEXTURE" + unit]);
|
|
15228
|
+
self.gl.bindTexture(self.gl.TEXTURE_2D, null);
|
|
15229
|
+
}
|
|
15230
|
+
}
|
|
15231
|
+
});
|
|
15232
|
+
}
|
|
15233
|
+
|
|
15234
|
+
destroy() {
|
|
15235
|
+
if (this.allocated) {
|
|
15236
|
+
const gl = this.gl;
|
|
15237
|
+
gl.deleteTexture(this.buffer.texture);
|
|
15238
|
+
gl.deleteTexture(this.buffer.depthTexture);
|
|
15239
|
+
gl.deleteFramebuffer(this.buffer.framebuf);
|
|
15240
|
+
gl.deleteRenderbuffer(this.buffer.renderbuf);
|
|
15241
|
+
this.allocated = false;
|
|
15242
|
+
this.buffer = null;
|
|
15243
|
+
this.bound = false;
|
|
15244
|
+
}
|
|
15245
|
+
this._imageDataCache = null;
|
|
15246
|
+
this._texture = null;
|
|
15247
|
+
this._depthTexture = null;
|
|
15248
|
+
}
|
|
15249
|
+
}
|
|
15250
|
+
|
|
15251
15251
|
/**
|
|
15252
15252
|
* @private
|
|
15253
15253
|
*/
|
|
@@ -31846,6 +31846,7 @@ function buildVertex$1(mesh) {
|
|
|
31846
31846
|
}
|
|
31847
31847
|
src.push("void main(void) {");
|
|
31848
31848
|
src.push("vec4 localPosition = vec4(position, 1.0); ");
|
|
31849
|
+
src.push("vec4 worldPosition;");
|
|
31849
31850
|
if (quantizedGeometry) {
|
|
31850
31851
|
src.push("localPosition = positionsDecodeMatrix * localPosition;");
|
|
31851
31852
|
}
|
|
@@ -31858,10 +31859,15 @@ function buildVertex$1(mesh) {
|
|
|
31858
31859
|
src.push("mat4 modelViewMatrix = viewMatrix2 * modelMatrix2;");
|
|
31859
31860
|
src.push("billboard(modelMatrix2);");
|
|
31860
31861
|
src.push("billboard(viewMatrix2);");
|
|
31862
|
+
src.push("billboard(modelViewMatrix);");
|
|
31863
|
+
src.push("worldPosition = modelMatrix2 * localPosition;");
|
|
31864
|
+
src.push("worldPosition.xyz = worldPosition.xyz + offset;");
|
|
31865
|
+
src.push("vec4 viewPosition = modelViewMatrix * localPosition;");
|
|
31866
|
+
} else {
|
|
31867
|
+
src.push("worldPosition = modelMatrix2 * localPosition;");
|
|
31868
|
+
src.push("worldPosition.xyz = worldPosition.xyz + offset;");
|
|
31869
|
+
src.push("vec4 viewPosition = viewMatrix2 * worldPosition; ");
|
|
31861
31870
|
}
|
|
31862
|
-
src.push(" vec4 worldPosition = modelMatrix2 * localPosition;");
|
|
31863
|
-
src.push(" worldPosition.xyz = worldPosition.xyz + offset;");
|
|
31864
|
-
src.push(" vec4 viewPosition = viewMatrix2 * worldPosition;");
|
|
31865
31871
|
if (clipping) {
|
|
31866
31872
|
src.push(" vWorldPosition = worldPosition;");
|
|
31867
31873
|
}
|
|
@@ -31968,7 +31974,7 @@ OcclusionRenderer.get = function (mesh) {
|
|
|
31968
31974
|
mesh.scene.canvas.canvas.id,
|
|
31969
31975
|
mesh.scene._sectionPlanesState.getHash(),
|
|
31970
31976
|
mesh._geometry._state.hash,
|
|
31971
|
-
mesh._state.
|
|
31977
|
+
mesh._state.occlusionHash
|
|
31972
31978
|
].join(";");
|
|
31973
31979
|
let renderer = renderers$1[hash];
|
|
31974
31980
|
if (!renderer) {
|
|
@@ -148534,7 +148540,7 @@ class Configs {
|
|
|
148534
148540
|
}
|
|
148535
148541
|
|
|
148536
148542
|
/**
|
|
148537
|
-
*
|
|
148543
|
+
* {@link Viewer} plugin that uses [web-ifc](https://github.com/tomvandig/web-ifc) to load BIM models directly from IFC files.
|
|
148538
148544
|
*
|
|
148539
148545
|
* <a href="https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_WebIFCLoaderPlugin_Duplex"><img src="https://xeokit.io/img/docs/WebIFCLoaderPlugin/WebIFCLoaderPlugin.png"></a>
|
|
148540
148546
|
*
|
|
@@ -152104,12 +152110,7 @@ class LASLoaderPlugin extends Plugin {
|
|
|
152104
152110
|
}
|
|
152105
152111
|
|
|
152106
152112
|
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
|
|
152113
|
+
isModel: true
|
|
152113
152114
|
}));
|
|
152114
152115
|
|
|
152115
152116
|
if (!params.src && !params.las) {
|