From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../deqp/framework/delibs/debase/deMath.js | 1143 ++++++++++++++++++++ 1 file changed, 1143 insertions(+) create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js') diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js new file mode 100644 index 0000000000..fbb2a61fd7 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js @@ -0,0 +1,1143 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES Utilities + * ------------------------------------------------ + * + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; +goog.provide('framework.delibs.debase.deMath'); + +/** @typedef { (Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array) } */ +goog.TypedArray; + +/** @typedef { (Array|Array|goog.TypedArray) } */ +goog.NumberArray; + +goog.scope(function() { + +var deMath = framework.delibs.debase.deMath; + +var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); +}; + +/** @const */ deMath.INT32_SIZE = 4; + +deMath.deInRange32 = function(a, mn, mx) { + return (a >= mn) && (a <= mx); +}; + +deMath.deInBounds32 = function(a, mn, mx) { + return (a >= mn) && (a < mx); +}; + +/** + * @param {number} a + * @return {number} + */ +deMath.deFloatFrac = function(a) { return a - Math.floor(a); }; + +/** + * Transform a 64-bit float number into a 32-bit float number. + * Native dEQP uses 32-bit numbers, so sometimes 64-bit floating numbers in JS should be transformed into 32-bit ones to ensure the correctness of the result. + * @param {number} a + * @return {number} + */ +deMath.toFloat32 = (function() { + var FLOAT32ARRAY1 = new Float32Array(1); + return function(a) { + FLOAT32ARRAY1[0] = a; + return FLOAT32ARRAY1[0]; + }; +})(); + +/** @const */ deMath.INV_LOG_2_FLOAT32 = deMath.toFloat32(1.44269504089); /** 1.0 / log_e(2.0) */ + +/** + * Check if a value is a power-of-two. + * @param {number} a Input value. + * @return {boolean} return True if input is a power-of-two value, false otherwise. + * (Also returns true for zero). + */ +deMath.deIsPowerOfTwo32 = function(a) { + return ((a & (a - 1)) == 0); +}; + +/** + * Align an integer to given power-of-two size. + * @param {number} val The number to align. + * @param {number} align The size to align to. + * @return {number} The aligned value + */ +deMath.deAlign32 = function(val, align) { + if (!deMath.deIsPowerOfTwo32(align)) + throw new Error('Not a power of 2: ' + align); + return ((val + align - 1) & ~(align - 1)) & 0xFFFFFFFF; //0xFFFFFFFF make sure it returns a 32 bit calculation in 64 bit browsers. +}; + +/** + * Compute the bit population count of an integer. + * @param {number} a + * @return {number} The number of one bits in + */ +deMath.dePop32 = function(a) { + /** @type {number} */ var mask0 = 0x55555555; /* 1-bit values. */ + /** @type {number} */ var mask1 = 0x33333333; /* 2-bit values. */ + /** @type {number} */ var mask2 = 0x0f0f0f0f; /* 4-bit values. */ + /** @type {number} */ var mask3 = 0x00ff00ff; /* 8-bit values. */ + /** @type {number} */ var mask4 = 0x0000ffff; /* 16-bit values. */ + /** @type {number} */ var t = a & 0xFFFFFFFF; /* Crop to 32-bit value */ + t = (t & mask0) + ((t >> 1) & mask0); + t = (t & mask1) + ((t >> 2) & mask1); + t = (t & mask2) + ((t >> 4) & mask2); + t = (t & mask3) + ((t >> 8) & mask3); + t = (t & mask4) + (t >> 16); + return t; +}; + +deMath.clamp = function(val, minParm, maxParm) { + return Math.min(Math.max(val, minParm), maxParm); +}; + +/** + * @param {Array} values + * @param {number} minParm + * @param {number} maxParm + * @return {Array} + */ +deMath.clampVector = function(values, minParm, maxParm) { + var result = []; + for (var i = 0; i < values.length; i++) + result.push(deMath.clamp(values[i], minParm, maxParm)); + return result; +}; + +deMath.imod = function(a, b) { + var m = a % b; + return m < 0 ? m + b : m; +}; + +deMath.mirror = function(a) { + return a >= 0 ? a : -(1 + a); +}; + +/** + * @param {goog.NumberArray} a Source array + * @param {goog.NumberArray} indices + * @return {Array} Swizzled array + */ +deMath.swizzle = function(a, indices) { + if (!indices.length) + throw new Error('Argument must be an array'); + var dst = []; + for (var i = 0; i < indices.length; i++) + dst.push(a[indices[i]]); + return dst; +}; + +/** + * Shift left elements of array a by elements of array b + * dst[n] a[n] << b[n] + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} Result array + */ +deMath.arrayShiftLeft = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] << b[i]); + return dst; +}; + +/** + * Multiply two vectors, element by element + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} Result array + */ + +deMath.multiply = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] * b[i]); + return dst; +}; + +/** + * Divide two vectors, element by element + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} Result array + * @throws {Error} + */ + +deMath.divide = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) { + if (b[i] === 0) + throw new Error('Division by 0'); + dst.push(a[i] / b[i]); + } + return dst; +}; + +/** + * Divide vector by a scalar + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} Result array + */ +deMath.divideScale = function(a, b) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] / b); + return dst; +}; + +/** + * @param {number} a + * @param {number} b + * @return {number} + */ +deMath.mod = function(a, b) { + return a - b * Math.floor(a / b); +}; + +/** + * Modulus vector by a scalar + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} Result array + */ +deMath.modScale = function(a, b) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(deMath.mod(a[i], b)); + return dst; +}; + +/** + * Multiply vector by a scalar + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} Result array + */ +deMath.scale = function(a, b) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] * b); + return dst; +}; + +/** + * Add vector and scalar, element by element + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} Result array + */ +deMath.addScalar = function(a, b) { + if (!Array.isArray(a)) + throw new Error('First argument must be an array.'); + if (typeof b !== 'number') + throw new Error('Second argument must be a number.'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] + b); + return dst; +}; + +/** + * Add two vectors, element by element + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} Result array + */ +deMath.add = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] + b[i]); + return dst; +}; + +/** + * Subtract two vectors, element by element + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} Result array + */ + +deMath.subtract = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] - b[i]); + return dst; +}; + +/** + * Subtract vector and scalar, element by element + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} Result array + */ +deMath.subScalar = function(a, b) { + if (!Array.isArray(a)) + throw new Error('First argument must be an array.'); + if (typeof b !== 'number') + throw new Error('Second argument must be a number.'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] - b); + return dst; +}; + +/** + * Calculate absolute difference between two vectors + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} abs(diff(a - b)) + */ +deMath.absDiff = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(Math.abs(a[i] - b[i])); + return dst; +}; + +/** + * Calculate absolute value of a vector + * @param {goog.NumberArray} a + * @return {Array} abs(a) + */ +deMath.abs = function(a) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(Math.abs(a[i])); + return dst; +}; + +/** + * Is a <= b (element by element)? + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} Result array of booleans + */ +deMath.lessThanEqual = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i] <= b[i]); + return dst; +}; + +/** + * Is a === b (element by element)? + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {boolean} Result + */ +deMath.equal = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) + return false; + } + return true; +}; + +/** + * Are all values in the array true? + * @param {Array} a + * @return {boolean} + */ +deMath.boolAll = function(a) { + for (var i = 0; i < a.length; i++) + if (a[i] == false) + return false; + return true; +}; + +/** + * deMath.assign(a, b) element by element + * @param {goog.NumberArray} a + * @return {Array} + */ +deMath.assign = function(a) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(a[i]); + return dst; +}; + +/** + * deMath.max(a, b) element by element + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} + */ +deMath.max = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(Math.max(a[i], b[i])); + return dst; +}; + +/** + * deMath.min(a, b) element by element + * @param {goog.NumberArray} a + * @param {goog.NumberArray} b + * @return {Array} + */ +deMath.min = function(a, b) { + if (a.length != b.length) + throw new Error('Arrays must have the same size'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(Math.min(a[i], b[i])); + return dst; +}; + +// Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding. +deMath.rint = function(a) { + var floorVal = Math.floor(a); + var fracVal = a - floorVal; + + if (fracVal != 0.5) + return Math.round(a); // Ordinary case. + + var roundUp = (floorVal % 2) != 0; + + return floorVal + (roundUp ? 1 : 0); +}; + +/** + * wrap the number, so that it fits in the range [minValue, maxValue] + * @param {number} v + * @param {number} minValue + * @param {number} maxValue + * @return {number} + */ +deMath.wrap = function(v, minValue, maxValue) { + var range = maxValue - minValue + 1; + + if (v < minValue) { + v += range * (Math.floor((minValue - v) / range) + 1); + } + return minValue + Math.floor((v - minValue) % range); +}; + +/** + * Round number to int by dropping fractional part + * it is equivalent of GLSL int() constructor + * @param {number} a + * @return {number} + */ +deMath.intCast = function(a) { + var v; + if (a >= 0) + v = Math.floor(a); + else + v = Math.ceil(a); + return deMath.wrap(v, -0x80000000, 0x7FFFFFFF); +}; + +/** + * Round number to uint by dropping fractional part + * it is equivalent of GLSL uint() constructor + * @param {number} a + * @return {number} + */ +deMath.uintCast = function(a) { + var v; + if (a >= 0) + v = Math.floor(a); + else + v = Math.ceil(a); + return deMath.wrap(v, 0, 0xFFFFFFFF); +}; + +/** + * @param {number} a + * @return {number} + */ +deMath.logToFloor = function(a) { + assertMsgOptions(a > 0, 'Value is less or equal than zero', false, true); + return 31 - deMath.clz32(a); +}; + +/** + * Find intersection of two rectangles + * @param {goog.NumberArray} a Array [x, y, width, height] + * @param {goog.NumberArray} b Array [x, y, width, height] + * @return {Array} + */ +deMath.intersect = function(a, b) { + if (a.length != 4) + throw new Error('Array "a" must have length 4 but has length: ' + a.length); + if (b.length != 4) + throw new Error('Array "b" must have length 4 but has length: ' + b.length); + var x0 = Math.max(a[0], b[0]); + var y0 = Math.max(a[1], b[1]); + var x1 = Math.min(a[0] + a[2], b[0] + b[2]); + var y1 = Math.min(a[1] + a[3], b[1] + b[3]); + var w = Math.max(0, x1 - x0); + var h = Math.max(0, y1 - y0); + + return [x0, y0, w, h]; +}; + +/** deMath.deMathHash + * @param {number} a + * @return {number} + */ +deMath.deMathHash = function(a) { + var key = a; + key = (key ^ 61) ^ (key >> 16); + key = key + (key << 3); + key = key ^ (key >> 4); + key = key * 0x27d4eb2d; /* prime/odd constant */ + key = key ^ (key >> 15); + return key; +}; + +/** + * Converts a byte array to a number. Cannot convert numbers larger than 52 bits. + * @param {Uint8Array} array + * @return {number} + */ +deMath.arrayToNumber = function(array) { + DE_ASSERT(array.length <= 6 || (array.length == 6 && array[5] <= 127)); + /** @type {number} */ var result = 0; + + for (var ndx = 0; ndx < array.length; ndx++) { + result += array[ndx] * Math.pow(256, ndx); + } + + return result; +}; + +/** + * Fills a byte array with a number + * @param {Uint8Array} array Output array (already resized) + * @param {number} number + */ +deMath.numberToArray = function(array, number) { + DE_ASSERT(Number.isInteger(number)); + for (var byteNdx = 0; byteNdx < array.length; byteNdx++) { + /** @type {number} */ var acumzndx = !byteNdx ? number : Math.floor(number / Math.pow(256, byteNdx)); + array[byteNdx] = acumzndx & 0xFF; + } +}; + +/** + * Obtains the bit fragment from a number + * @param {number} x + * @param {number} firstNdx + * @param {number} lastNdx + * @return {number} + */ +deMath.getBitRange = function(x, firstNdx, lastNdx) { + DE_ASSERT(lastNdx - firstNdx <= 52); + var shifted = deMath.shiftRight(x, firstNdx); + var bitSize = lastNdx - firstNdx; + var mask; + if (bitSize < 32) + mask = (1 << bitSize) - 1; + else + mask = Math.pow(2, bitSize) - 1; + var masked = deMath.binaryAnd(shifted, mask); + return masked; +}; + +/** + * Obtains the bit fragment from a Uint32Array representing a number. + * (ArrayBuffer representations are used in tcuFloat.) + * + * Cannot return more than 52 bits ((lastNdx - firstNdx) <= 52). + * + * @param {Uint32Array} array + * @param {number} firstNdx + * @param {number} lastNdx + * @return {number} + */ +deMath.getArray32BitRange = function(array, firstNdx, lastNdx) { + DE_ASSERT(0 <= firstNdx && firstNdx < (array.length * 32)); + DE_ASSERT(0 < lastNdx && lastNdx <= (array.length * 32)); + DE_ASSERT((lastNdx - firstNdx) <= 52); + + // Example of how this works for a 64-bit number (Uint32Array of length 2). + // + // * Note that the shift operators in the code << and >>> are pointing in + // the opposite direction of this diagram, since LSB is shown on the left. + // + // [array[0], array[1] ] + // [00000011111111111111111111111111, 11111111111100000000000000000000] + // ^LSB MSB^ ^LSB MSB^ + // + // [00000011111111111111111111111111, 11111111111100000000000000000000] + // \ \ + // firstNdx = 6 (inclusive) lastNdx = 44 (exclusive) + // blockIndexA = 0 blockIndexB = 1 + // + // [00000011111111111111111111111111, 11111111111100000000000000000000] + // \-----\ \-------------------\ + // bitsToBeginningOfBlock = 6 bitsFromEndOfBlock = 20 + // + // -------------blockA------------- -------------blockB------------- + // [00000011111111111111111111111111, 11111111111100000000000000000000] + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ + // blockATruncated blockBTruncated + // \--blockATruncatedLength--\ + // + // 11111111111111111111111111 111111111111 + // ^^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^^ return value (38 bits) + + /** @type {number} */ var blockIndexA = Math.floor(firstNdx / 32); + /** @type {number} */ var bitsToBeginningOfBlock = firstNdx % 32; + /** @type {number} */ var blockIndexB = Math.floor((lastNdx - 1) / 32); + /** @type {number} */ var bitsFromEndOfBlock = 31 - ((lastNdx - 1) % 32); + + /** @type {number} */ var blockB = array[blockIndexB]; + // Chop off the most significant `bitsFromEndOfBlock` bits from blockB. + // Note: Initially this logic used a bitmask instead. But there are subtle + // corner cases in JS that caused results to sometimes come out negative. + // This truncation method is just used to avoid that complexity. + /** @type {number} */ var blockBTruncated = (blockB << bitsFromEndOfBlock) >>> bitsFromEndOfBlock; + + if (blockIndexA == blockIndexB) { + // firstNdx and lastNdx are in the same block. + // Chop off the least significant `bitsToBeginningOfBlock` bits from blockBTruncated. + return blockBTruncated >>> bitsToBeginningOfBlock; + } else { + // firstNdx and lastNdx are in different blocks. + /** @type {number} */ var blockA = array[blockIndexA]; + // Chop off the least significant `bitsToBeginningOfBlock` bits from blockA. + /** @type {number} */ var blockATruncated = blockA >>> bitsToBeginningOfBlock; + /** @type {number} */ var blockATruncatedLength = 32 - bitsToBeginningOfBlock; + + // Concatenate blockATruncated and blockBTruncated. + // Conceptually equivalent to: + // blockATruncated | (blockBTruncated << blockATruncatedLength) + // except that wouldn't work for numbers larger than 32 bits. + return blockATruncated + (blockBTruncated * Math.pow(2, blockATruncatedLength)); + } +}; + +/** + * Split a large signed number into low and high 32bit dwords. + * @param {number} x + * @return {Array} + */ +deMath.split32 = function(x) { + var ret = []; + ret[1] = Math.floor(x / 0x100000000); + ret[0] = x - ret[1] * 0x100000000; + return ret; +}; + +/** + * Split a signed number's low 32bit dwords into low and high 16bit dwords. + * @param {number} x + * @return {Array} + */ +deMath.split16 = function(x) { + var ret = []; + x = x & 0xffffffff; + ret[1] = Math.floor(x / 0x10000); + ret[0] = x - ret[1] * 0x10000; + return ret; +}; + +/** + * Recontruct a number from high and low 32 bit dwords + * @param {Array} x + * @return {number} + */ +deMath.join32 = function(x) { + var v0 = x[0] >= 0 ? x[0] : 0x100000000 + x[0]; + var v1 = x[1]; + var val = v1 * 0x100000000 + v0; + return val; +}; + +//Bit operations with the help of arrays + +/** + * @enum + */ +deMath.BinaryOp = { + AND: 0, + OR: 1, + XOR: 2 +}; + +/** + * Performs a normal (native) binary operation + * @param {number} valueA First operand + * @param {number} valueB Second operand + * @param {deMath.BinaryOp} operation The desired operation to perform + * @return {number} + */ +deMath.doNativeBinaryOp = function(valueA, valueB, operation) { + switch (operation) { + case deMath.BinaryOp.AND: + return valueA & valueB; + case deMath.BinaryOp.OR: + return valueA | valueB; + case deMath.BinaryOp.XOR: + return valueA ^ valueB; + default: + throw new Error('Unknown operation: ' + operation); + } +}; + +/** + * Performs a binary operation between two operands + * with the help of arrays to avoid losing the internal binary representation. + * @param {number} valueA First operand + * @param {number} valueB Second operand + * @param {deMath.BinaryOp} binaryOpParm The desired operation to perform + * @return {number} + */ +deMath.binaryOp = function(valueA, valueB, binaryOpParm) { + //quick path if values fit in signed 32 bit range + if (deMath.deInRange32(valueA, -0x80000000, 0x7FFFFFFF) && deMath.deInRange32(valueB, -0x80000000, 0x7FFFFFFF)) + return deMath.doNativeBinaryOp(valueA, valueB, binaryOpParm); + + var x = deMath.split32(valueA); + var y = deMath.split32(valueB); + var z = []; + for (var i = 0; i < 2; i++) + z[i] = deMath.doNativeBinaryOp(x[i], y[i], binaryOpParm); + var ret = deMath.join32(z); + return ret; +}; + +/** + * @param {number} a + * @param {number} b + * @return {number} + */ +deMath.binaryAnd = function(a, b) { + return deMath.binaryOp(a, b, deMath.BinaryOp.AND); +}; + +/** + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} + */ +deMath.binaryAndVecScalar = function(a, b) { + if (!Array.isArray(a)) + throw new Error('First argument must be an array.'); + if (typeof b !== 'number') + throw new Error('Second argument must be a number.'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(deMath.binaryOp(a[i], b, deMath.BinaryOp.AND)); + return dst; +}; + +/** + * @param {number} a + * @param {number} b + * @return {number} + */ +deMath.binaryOr = function(a, b) { + return deMath.binaryOp(a, b, deMath.BinaryOp.OR); +}; + +/** + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} + */ +deMath.binaryOrVecScalar = function(a, b) { + if (!Array.isArray(a)) + throw new Error('First argument must be an array.'); + if (typeof b !== 'number') + throw new Error('Second argument must be a number.'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(deMath.binaryOp(a[i], b, deMath.BinaryOp.OR)); + return dst; +}; + +/** + * @param {number} a + * @param {number} b + * @return {number} + */ +deMath.binaryXor = function(a, b) { + return deMath.binaryOp(a, b, deMath.BinaryOp.XOR); +}; + +/** + * @param {goog.NumberArray} a + * @param {number} b + * @return {Array} + */ +deMath.binaryXorVecScalar = function(a, b) { + if (!Array.isArray(a)) + throw new Error('First argument must be an array.'); + if (typeof b !== 'number') + throw new Error('Second argument must be a number.'); + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(deMath.binaryOp(a[i], b, deMath.BinaryOp.XOR)); + return dst; +}; + +/** + * Performs a binary NOT operation on an operand + * @param {number} value Operand + * @return {number} + */ +deMath.binaryNot = function(value) { + //quick path if value fits in signed 32 bit range + if (deMath.deInRange32(value, -0x80000000, 0x7FFFFFFF)) + return ~value; + + var x = deMath.split32(value); + x[0] = ~x[0]; + x[1] = ~x[1]; + var ret = deMath.join32(x); + return ret; +}; + +/** + * Shifts the given value 'steps' bits to the left. Replaces << operator + * This function should be used if the expected value will be wider than 32-bits. + * @param {number} value + * @param {number} steps + * @return {number} + */ +deMath.shiftLeft = function(value, steps) { + //quick path + if (steps < 31) { + var v = value * (1 << steps); + if (deMath.deInRange32(v, -0x80000000, 0x7FFFFFFF)) + return v; + } + + if (steps == 0) + return value; + else if (steps < 32) { + var mask = (1 << 32 - steps) - 1; + var x = deMath.split32(value); + var highBits = x[0] & (~mask); + var y = highBits >> (32 - steps); + if (highBits < 0) { + var m = (1 << steps) - 1; + y &= m; + } + var result = []; + result[0] = x[0] << steps; + result[1] = x[1] << steps; + result[1] |= y; + + return deMath.join32(result); + } else { + var x = deMath.split32(value); + var result = []; + result[0] = 0; + result[1] = x[0] << steps - 32; + return deMath.join32(result); + } +}; + +/** + * @param {Array} a + * @param {number} b + */ +deMath.shiftLeftVecScalar = function(a, b) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(deMath.shiftLeft(a[i], b)); + return dst; +}; + +/** + * Shifts the given value 'steps' bits to the right. Replaces >> operator + * This function should be used if the value is wider than 32-bits + * @param {number} value + * @param {number} steps + * @return {number} + */ +deMath.shiftRight = function(value, steps) { + //quick path + if (deMath.deInRange32(value, -0x80000000, 0x7FFFFFFF) && steps < 32) + return value >> steps; + + if (steps == 0) + return value; + else if (steps < 32) { + if (steps == 0) + return value; + var mask = (1 << steps) - 1; + var x = deMath.split32(value); + var lowBits = x[1] & mask; + var result = []; + var m = (1 << 32 - steps) - 1; + result[0] = (x[0] >> steps) & m; + result[1] = x[1] >> steps; + result[0] |= lowBits << 32 - steps; + return deMath.join32(result); + } else { + var x = deMath.split32(value); + var result = []; + result[0] = x[1] >> steps - 32; + result[1] = value < 0 ? -1 : 0; + return deMath.join32(result); + } +}; + +/** + * @param {Array} a + * @param {number} b + */ +deMath.shiftRightVecScalar = function(a, b) { + var dst = []; + for (var i = 0; i < a.length; i++) + dst.push(deMath.shiftRight(a[i], b)); + return dst; +}; + +/** deMath.logicalAndBool over two arrays of booleans + * @param {Array} a + * @param {Array} b + * @return {Array} + */ +deMath.logicalAndBool = function(a, b) { + if (!Array.isArray(a)) + throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a); + if (!Array.isArray(b)) + throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b); + if (a.length != b.length) + throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')'); + + /** @type {Array} */ var result = []; + for (var i = 0; i < a.length; i++) { + if (a[i] & b[i]) + result.push(true); + else + result.push(false); + } + return result; +}; + +/** deMath.logicalOrBool over two arrays of booleans + * @param {Array} a + * @param {Array} b + * @return {Array} + */ +deMath.logicalOrBool = function(a, b) { + if (!Array.isArray(a)) + throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a); + if (!Array.isArray(b)) + throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b); + if (a.length != b.length) + throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')'); + + /** @type {Array} */ var result = []; + for (var i = 0; i < a.length; i++) { + if (a[i] | b[i]) + result.push(true); + else + result.push(false); + } + return result; +}; + +/** deMath.logicalNotBool over an array of booleans + * @param {Array} a + * @return {Array} + */ +deMath.logicalNotBool = function(a) { + if (!Array.isArray(a)) + throw new Error('The passed value is not an array: (' + typeof(a) + ')' + a); + + /** @type {Array} */ var result = []; + for (var i = 0; i < a.length; i++) + result.push(!a[i]); + return result; +}; + +/** deMath.greaterThan over two arrays of booleans + * @param {Array} a + * @param {Array} b + * @return {Array} + */ +deMath.greaterThan = function(a, b) { + if (!Array.isArray(a)) + throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a); + if (!Array.isArray(b)) + throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b); + if (a.length != b.length) + throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')'); + + /** @type {Array} */ var result = []; + for (var i = 0; i < a.length; i++) + result.push(a[i] > b[i]); + return result; +}; + +/** deMath.greaterThan over two arrays of booleans + * @param {Array} a + * @param {Array} b + * @return {Array} + */ +deMath.greaterThanEqual = function(a, b) { + if (!Array.isArray(a)) + throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a); + if (!Array.isArray(b)) + throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b); + if (a.length != b.length) + throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')'); + + /** @type {Array} */ var result = []; + for (var i = 0; i < a.length; i++) + result.push(a[i] >= b[i]); + return result; +}; + +/** + * Array of float to array of int (0, 255) + * @param {Array} a + * @return {Array} + */ + +deMath.toIVec = function(a) { + /** @type {Array} */ var res = []; + for (var i = 0; i < a.length; i++) + res.push(deMath.clamp(Math.floor(a[i] * 255), 0, 255)); + return res; +}; + +/** + * @param {number} a + * @return {number} + */ + deMath.clz32 = function(a) { + /** @type {number} */ var maxValue = 2147483648; // max 32 bit number + /** @type {number} */ var leadingZeros = 0; + while (a < maxValue) { + maxValue = maxValue >>> 1; + leadingZeros++; + } + return leadingZeros; +}; + +/** + * @param {number} a + * @param {number} exponent + * @return {number} + */ +deMath.deLdExp = function(a, exponent) { + return deMath.ldexp(a, exponent); +}; + +/** + * @param {number} a + * @param {number} exponent + * @return {number} + */ +deMath.deFloatLdExp = function(a, exponent) { + return deMath.ldexp(a, exponent); +}; + +/** + * @param {number} value + * @return {Array} + */ +deMath.frexp = (function() { + var data = new DataView(new ArrayBuffer(8)); + + return function(value) { + if (value === 0) return [value, 0]; + data.setFloat64(0, value); + var bits = (data.getUint32(0) >>> 20) & 0x7FF; + if (bits === 0) { + data.setFloat64(0, value * Math.pow(2, 64)); + bits = ((data.getUint32(0) >>> 20) & 0x7FF) - 64; + } + var exponent = bits - 1022, + mantissa = deMath.ldexp(value, -exponent); + return [mantissa, exponent]; + } +})(); + +/** + * @param {number} mantissa + * @param {number} exponent + * @return {number} + */ +deMath.ldexp = function(mantissa, exponent) { + return exponent > 1023 ? // avoid multiplying by infinity + mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023) : + exponent < -1074 ? // avoid multiplying by zero + mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074) : + mantissa * Math.pow(2, exponent); +}; + +/** + * @param {number} a + * @return {number} + */ +deMath.deCbrt = function(a) { + return deMath.deSign(a) * Math.pow(Math.abs(a), 1.0 / 3.0); +}; + +/** + * @param {number} x + * @return {number} + */ +deMath.deSign = function(x) { + return isNaN(x) ? x : ((x > 0.0) - (x < 0.0)); +}; + +deMath.deFractExp = function(x) { + var result = { + significand: x, + exponent: 0 + }; + + if (isFinite(x)) { + var r = deMath.frexp(x); + result.exponent = r[1] - 1; + result.significand = r[0] * 2; + } + return result; +}; + +}); -- cgit v1.2.3