2017-08-13 23:41:57 +02:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
(function(){
|
|
|
|
"use strict";
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
const logging = require("./logging");
|
2017-08-13 23:41:57 +02:00
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
let scope;
|
2017-08-13 23:41:57 +02:00
|
|
|
if ((typeof exports) !== "undefined"){
|
|
|
|
scope = exports;
|
|
|
|
}
|
|
|
|
else {
|
2019-03-12 22:24:23 +01:00
|
|
|
scope = require.register("./webgl", {});
|
2017-08-13 23:41:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
scope.copyCanvasToWebgl = function copyCanvasToWebgl(window, canvas, webGLVersion = "webgl"){
|
2019-11-28 01:26:35 +01:00
|
|
|
const webGlCanvas = canvas.cloneNode(true);
|
|
|
|
const context =
|
2017-08-13 23:41:57 +02:00
|
|
|
window.HTMLCanvasElement.prototype.getContext.call(webGlCanvas, webGLVersion) ||
|
|
|
|
window.HTMLCanvasElement.prototype.getContext.call(webGlCanvas, "experimental-" + webGLVersion);
|
|
|
|
if (!context){
|
|
|
|
// unable to get a context...
|
|
|
|
logging.warning("unable to create webgl context.");
|
|
|
|
return {canvas: false, context: false};
|
|
|
|
}
|
|
|
|
|
|
|
|
context.viewport(0, 0, webGlCanvas.width, webGlCanvas.height);
|
2019-11-28 01:26:35 +01:00
|
|
|
|
|
|
|
const program = context.createProgram();
|
|
|
|
|
|
|
|
const vertexShader = context.createShader(context.VERTEX_SHADER);
|
|
|
|
const vertex = "attribute vec4 a_position;\nattribute vec2 a_texCoord;\nvarying vec2 v_texCoord;\n" +
|
2017-10-06 16:06:31 +02:00
|
|
|
"void main(){\n\tgl_Position = a_position;\n\tv_texCoord = a_texCoord;\n}";
|
2019-11-28 01:26:35 +01:00
|
|
|
context.shaderSource(vertexShader, vertex);
|
|
|
|
context.compileShader(vertexShader);
|
|
|
|
if (!context.getShaderParameter(vertexShader, context.COMPILE_STATUS)){
|
|
|
|
context.deleteShader(vertexShader);
|
2017-08-13 23:41:57 +02:00
|
|
|
logging.warning("webgl: failed to compile vertex shader.");
|
|
|
|
return {canvas: false, context: false};
|
|
|
|
}
|
2019-11-28 01:26:35 +01:00
|
|
|
context.attachShader(program, vertexShader);
|
2017-08-13 23:41:57 +02:00
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
const fragmentShader = context.createShader(context.FRAGMENT_SHADER);
|
|
|
|
const fragmenter = "precision mediump float;\nuniform sampler2D u_image;\nvarying vec2 v_texCoord;\n" +
|
2017-10-06 16:06:31 +02:00
|
|
|
"void main(){\n\tgl_FragColor = texture2D(u_image, v_texCoord);\n}";
|
2019-11-28 01:26:35 +01:00
|
|
|
context.shaderSource(fragmentShader, fragmenter);
|
|
|
|
context.compileShader(fragmentShader);
|
|
|
|
if (!context.getShaderParameter(fragmentShader, context.COMPILE_STATUS)){
|
|
|
|
context.deleteShader(fragmentShader);
|
2017-08-13 23:41:57 +02:00
|
|
|
logging.warning("webgl: failed to compile fragmenter shader.");
|
|
|
|
return {canvas: false, context: false};
|
|
|
|
}
|
2019-11-28 01:26:35 +01:00
|
|
|
context.attachShader(program, fragmentShader);
|
2017-08-13 23:41:57 +02:00
|
|
|
|
|
|
|
context.linkProgram(program);
|
2019-11-28 01:26:35 +01:00
|
|
|
if (!context.getProgramParameter(program, context.LINK_STATUS)){
|
2017-08-13 23:41:57 +02:00
|
|
|
context.deleteProgram(program);
|
|
|
|
logging.warning("webgl: failed to link program.");
|
|
|
|
return {canvas: false, context: false};
|
|
|
|
}
|
|
|
|
|
|
|
|
context.useProgram(program);
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
const positionBuffer = context.createBuffer();
|
2017-08-13 23:41:57 +02:00
|
|
|
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
|
|
|
|
context.bufferData(context.ARRAY_BUFFER, new Float32Array([
|
2017-10-05 19:00:00 +02:00
|
|
|
-1, -1,
|
|
|
|
-1, 1,
|
|
|
|
1, -1,
|
|
|
|
1, 1,
|
|
|
|
-1, 1,
|
|
|
|
1, -1
|
2017-08-13 23:41:57 +02:00
|
|
|
]), context.STATIC_DRAW);
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
const positionAttributeLocation = context.getAttribLocation(program, "a_position");
|
2017-08-13 23:41:57 +02:00
|
|
|
context.enableVertexAttribArray(positionAttributeLocation);
|
2021-06-12 00:50:05 +02:00
|
|
|
const size = 2; // 2 components per iteration
|
|
|
|
const type = context.FLOAT; // the data is 32bit floats
|
|
|
|
const normalize = false; // don't normalize the data
|
|
|
|
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
|
|
|
|
const offset = 0; // start at the beginning of the buffer
|
2017-10-05 19:00:00 +02:00
|
|
|
context.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);
|
2017-08-13 23:41:57 +02:00
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
const texCoordLocation = context.getAttribLocation(program, "a_texCoord");
|
2017-08-13 23:41:57 +02:00
|
|
|
|
|
|
|
// provide texture coordinates for the rectangle.
|
2019-11-28 01:26:35 +01:00
|
|
|
const texCoordBuffer = context.createBuffer();
|
2017-08-13 23:41:57 +02:00
|
|
|
context.bindBuffer(context.ARRAY_BUFFER, texCoordBuffer);
|
|
|
|
context.bufferData(context.ARRAY_BUFFER, new Float32Array([
|
|
|
|
0, 1,
|
|
|
|
0, 0,
|
|
|
|
1, 1,
|
|
|
|
1, 0,
|
|
|
|
0, 0,
|
|
|
|
1, 1
|
|
|
|
]), context.STATIC_DRAW);
|
|
|
|
context.enableVertexAttribArray(texCoordLocation);
|
|
|
|
context.vertexAttribPointer(texCoordLocation, 2, context.FLOAT, false, 0, 0);
|
2019-11-28 01:26:35 +01:00
|
|
|
|
|
|
|
context.bindTexture(context.TEXTURE_2D, context.createTexture());
|
2017-08-13 23:41:57 +02:00
|
|
|
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_S, context.CLAMP_TO_EDGE);
|
|
|
|
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_T, context.CLAMP_TO_EDGE);
|
|
|
|
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.NEAREST);
|
|
|
|
context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MAG_FILTER, context.NEAREST);
|
|
|
|
context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, context.RGBA, context.UNSIGNED_BYTE, canvas);
|
2019-11-28 01:26:35 +01:00
|
|
|
|
|
|
|
context.drawArrays(context.TRIANGLES /*primitiveType*/, 0 /*triangleOffset*/, 6 /*count*/);
|
2017-08-13 23:41:57 +02:00
|
|
|
|
|
|
|
return {webGlCanvas, context};
|
|
|
|
};
|
2019-12-29 00:18:05 +01:00
|
|
|
|
|
|
|
let randomSupply = null;
|
|
|
|
scope.setRandomSupply = function(supply){
|
|
|
|
randomSupply = supply;
|
|
|
|
};
|
|
|
|
|
2019-12-29 00:45:20 +01:00
|
|
|
function getNumber({originalValue, max, index, window}){
|
2019-12-29 00:18:05 +01:00
|
|
|
const bitLength = Math.floor(Math.log2(max) + 1);
|
|
|
|
const rng = randomSupply.getBitRng(bitLength, window);
|
|
|
|
let value = 0;
|
|
|
|
for (let i = 0; i < bitLength; i += 1){
|
|
|
|
value <<= 1;
|
|
|
|
value ^= rng(originalValue, index + i);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
const parameterFakeTypes = {
|
2019-12-29 00:45:20 +01:00
|
|
|
preference: function(originalValue, definition, window, prefs){
|
|
|
|
const settingValue = prefs(definition.preferenceName) || originalValue;
|
2021-01-02 11:05:52 +01:00
|
|
|
switch (settingValue){
|
|
|
|
case "{undefined}":
|
|
|
|
return undefined;
|
|
|
|
case "{false}":
|
|
|
|
return false;
|
|
|
|
case "{empty}":
|
|
|
|
return "";
|
2021-01-03 21:11:17 +01:00
|
|
|
case "{disabled}":
|
|
|
|
return null;
|
2021-01-02 11:05:52 +01:00
|
|
|
}
|
2019-12-29 00:45:20 +01:00
|
|
|
return settingValue;
|
|
|
|
},
|
2019-12-29 00:18:05 +01:00
|
|
|
decimal: function(originalValue, definition, window){
|
|
|
|
const int = Math.floor(originalValue);
|
|
|
|
if (int !== originalValue){
|
|
|
|
const decimal = originalValue - int;
|
|
|
|
const rng = randomSupply.getRng(1, window);
|
|
|
|
const newDecimal = decimal * (rng(definition.pname) / 0xFFFFFFFF);
|
|
|
|
return int + newDecimal;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return originalValue;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
shift: function(originalValue, definition, window){
|
2019-12-29 00:45:20 +01:00
|
|
|
const value = getNumber({originalValue, max: definition.max, index: definition.pname, window});
|
2019-12-29 00:18:05 +01:00
|
|
|
return originalValue >>> value;
|
|
|
|
},
|
|
|
|
"-": function(originalValue, definition, window){
|
2019-12-29 00:45:20 +01:00
|
|
|
const value = getNumber({originalValue, max: definition.max, index: definition.pname, window}) *
|
2019-12-29 00:18:05 +01:00
|
|
|
(definition.factor || 1);
|
|
|
|
if (value > originalValue){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return originalValue - value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const parameterChangeDefinition = {
|
|
|
|
2928: {name: "DEPTH_RANGE", type: "decimal", isArray: true},
|
|
|
|
3379: {name: "MAX_TEXTURE_SIZE", type: "shift", max: 1},
|
|
|
|
3386: {name: "MAX_VIEWPORT_DIMS", type: "shift", max: 1, isArray: true},
|
|
|
|
32883: {name: "MAX_3D_TEXTURE_SIZE", type: "shift", max: 1},
|
|
|
|
33000: {name: "MAX_ELEMENTS_VERTICES", type: "-", max: 3, factor: 50},
|
|
|
|
33001: {name: "MAX_ELEMENTS_INDICES", type: "-", max: 3, factor: 50},
|
|
|
|
33901: {name: "ALIASED_POINT_SIZE_RANGE", type: "decimal", isArray: true},
|
|
|
|
33902: {name: "ALIASED_LINE_WIDTH_RANGE", type: "decimal", isArray: true},
|
|
|
|
34024: {name: "MAX_RENDERBUFFER_SIZE", type: "shift", max: 1},
|
|
|
|
34045: {name: "MAX_TEXTURE_LOD_BIAS", type: "-", max: 1, factor: 1},
|
|
|
|
34076: {name: "MAX_CUBE_MAP_TEXTURE_SIZE", type: "shift", max: 1},
|
|
|
|
34921: {name: "MAX_VERTEX_ATTRIBS", type: "shift", max: 1},
|
|
|
|
34930: {name: "MAX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
|
|
|
|
35071: {name: "MAX_ARRAY_TEXTURE_LAYERS", type: "shift", max: 1},
|
|
|
|
35371: {name: "MAX_VERTEX_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
|
|
|
|
35373: {name: "MAX_FRAGMENT_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
|
|
|
|
35374: {name: "MAX_COMBINED_UNIFORM_BLOCKS", type: "-", max: 3, factor: 1},
|
|
|
|
35375: {name: "MAX_UNIFORM_BUFFER_BINDINGS", type: "-", max: 3, factor: 1},
|
|
|
|
35376: {name: "MAX_UNIFORM_BLOCK_SIZE", type: "shift", max: 1},
|
|
|
|
35377: {name: "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
|
|
|
|
35379: {name: "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
|
|
|
|
35657: {name: "MAX_FRAGMENT_UNIFORM_COMPONENTS", type: "shift", max: 1},
|
|
|
|
35658: {name: "MAX_VERTEX_UNIFORM_COMPONENTS", type: "shift", max: 1},
|
|
|
|
35659: {name: "MAX_VARYING_COMPONENTS", type: "shift", max: 1},
|
|
|
|
35660: {name: "MAX_VERTEX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
|
|
|
|
35661: {name: "MAX_COMBINED_TEXTURE_IMAGE_UNITS", type: "-", max: 1, factor: 2},
|
|
|
|
35968: {name: "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", type: "shift", max: 1},
|
|
|
|
35978: {name: "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", type: "shift", max: 1},
|
|
|
|
36203: {name: "MAX_ELEMENT_INDEX", type: "-", max: 15, factor: 1},
|
|
|
|
36347: {name: "MAX_VERTEX_UNIFORM_VECTORS", type: "shift", max: 1},
|
|
|
|
36348: {name: "MAX_VARYING_VECTORS", type: "shift", max: 1},
|
|
|
|
36349: {name: "MAX_FRAGMENT_UNIFORM_VECTORS", type: "shift", max: 1},
|
|
|
|
37154: {name: "MAX_VERTEX_OUTPUT_COMPONENTS", type: "shift", max: 1},
|
|
|
|
37157: {name: "MAX_FRAGMENT_INPUT_COMPONENTS", type: "shift", max: 1},
|
2019-12-29 00:45:20 +01:00
|
|
|
7936: {name: "VENDOR", type: "preference", preferenceName: "webGLVendor"},
|
|
|
|
7937: {name: "RENDERER", type: "preference", preferenceName: "webGLRenderer"},
|
|
|
|
37445: {name: "UNMASKED_VENDOR_WEBGL", type: "preference", preferenceName: "webGLUnmaskedVendor"},
|
|
|
|
37446: {name: "UNMASKED_RENDERER_WEBGL", type: "preference", preferenceName: "webGLUnmaskedRenderer"}
|
2019-12-29 00:18:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
scope.initializeParameterDefinitions = function(){
|
2019-12-29 00:45:20 +01:00
|
|
|
function singleFake(originalValue, window, prefs){
|
2021-01-03 22:23:46 +01:00
|
|
|
const value = parameterFakeTypes[this.type](originalValue, this, window, prefs);
|
|
|
|
const faked = value !== originalValue;
|
2019-12-29 00:45:20 +01:00
|
|
|
this.fake = function(){
|
|
|
|
return {value, faked};
|
|
|
|
};
|
|
|
|
return {value, faked};
|
|
|
|
}
|
|
|
|
function arrayFake(originalValue, window, prefs){
|
|
|
|
let faked = false;
|
|
|
|
let fakedValue = [];
|
|
|
|
for (let i = 0; i < originalValue.length; i += 1){
|
|
|
|
fakedValue[i] = parameterFakeTypes[this.type](originalValue[i], this, window, prefs);
|
2021-06-12 00:58:37 +02:00
|
|
|
faked = faked || originalValue[i] !== fakedValue[i];
|
2019-12-29 00:45:20 +01:00
|
|
|
originalValue[i] = fakedValue[i];
|
|
|
|
}
|
|
|
|
this.fake = function(originalValue){
|
|
|
|
if (faked){
|
|
|
|
for (let i = 0; i < originalValue.length; i += 1){
|
|
|
|
originalValue[i] = fakedValue[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
value: originalValue,
|
|
|
|
faked
|
|
|
|
};
|
|
|
|
};
|
|
|
|
return {
|
|
|
|
value: originalValue,
|
|
|
|
faked
|
|
|
|
};
|
|
|
|
}
|
2019-12-29 00:18:05 +01:00
|
|
|
Object.keys(parameterChangeDefinition).forEach(function(parameterName){
|
|
|
|
const definition = parameterChangeDefinition[parameterName];
|
|
|
|
definition.pname = parameterName;
|
|
|
|
if (!definition.fake){
|
2019-12-29 00:45:20 +01:00
|
|
|
definition.fake = definition.isArray? arrayFake: singleFake;
|
2019-12-29 00:18:05 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
scope.parameterChangeDefinition = parameterChangeDefinition;
|
2017-08-13 23:41:57 +02:00
|
|
|
}());
|