UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

1,435 lines 62.6 kB
import { BuildArray } from "../Misc/arrayTools.js"; import { RegisterClass } from "../Misc/typeStore.js"; import { Epsilon, ToGammaSpace, ToLinearSpace } from "./math.constants.js"; import { Clamp, ToHex, WithinEpsilon } from "./math.scalar.functions.js"; function ColorChannelToLinearSpace(color) { return Math.pow(color, ToLinearSpace); } function ColorChannelToLinearSpaceExact(color) { if (color <= 0.04045) { return 0.0773993808 * color; } return Math.pow(0.947867299 * (color + 0.055), 2.4); } function ColorChannelToGammaSpace(color) { return Math.pow(color, ToGammaSpace); } function ColorChannelToGammaSpaceExact(color) { if (color <= 0.0031308) { return 12.92 * color; } return 1.055 * Math.pow(color, 0.41666) - 0.055; } /** * Class used to hold a RGB color */ export class Color3 { /** * Creates a new Color3 object from red, green, blue values, all between 0 and 1 * @param r defines the red component (between 0 and 1, default is 0) * @param g defines the green component (between 0 and 1, default is 0) * @param b defines the blue component (between 0 and 1, default is 0) */ constructor( /** * [0] Defines the red component (between 0 and 1, default is 0) */ r = 0, /** * [0] Defines the green component (between 0 and 1, default is 0) */ g = 0, /** * [0] Defines the blue component (between 0 and 1, default is 0) */ b = 0) { this.r = r; this.g = g; this.b = b; } /** * Creates a string with the Color3 current values * @returns the string representation of the Color3 object */ toString() { return "{R: " + this.r + " G:" + this.g + " B:" + this.b + "}"; } /** * Returns the string "Color3" * @returns "Color3" */ getClassName() { return "Color3"; } /** * Compute the Color3 hash code * @returns an unique number that can be used to hash Color3 objects */ getHashCode() { let hash = (this.r * 255) | 0; hash = (hash * 397) ^ ((this.g * 255) | 0); hash = (hash * 397) ^ ((this.b * 255) | 0); return hash; } // Operators /** * Stores in the given array from the given starting index the red, green, blue values as successive elements * @param array defines the array where to store the r,g,b components * @param index defines an optional index in the target array to define where to start storing values * @returns the current Color3 object */ toArray(array, index = 0) { array[index] = this.r; array[index + 1] = this.g; array[index + 2] = this.b; return this; } /** * Update the current color with values stored in an array from the starting index of the given array * @param array defines the source array * @param offset defines an offset in the source array * @returns the current Color3 object */ fromArray(array, offset = 0) { Color3.FromArrayToRef(array, offset, this); return this; } /** * Returns a new Color4 object from the current Color3 and the given alpha * @param alpha defines the alpha component on the new Color4 object (default is 1) * @returns a new Color4 object */ toColor4(alpha = 1) { return new Color4(this.r, this.g, this.b, alpha); } /** * Returns a new array populated with 3 numeric elements : red, green and blue values * @returns the new array */ asArray() { return [this.r, this.g, this.b]; } /** * Returns the luminance value * @returns a float value */ toLuminance() { return this.r * 0.3 + this.g * 0.59 + this.b * 0.11; } /** * Multiply each Color3 rgb values by the given Color3 rgb values in a new Color3 object * @param otherColor defines the second operand * @returns the new Color3 object */ multiply(otherColor) { return new Color3(this.r * otherColor.r, this.g * otherColor.g, this.b * otherColor.b); } /** * Multiply the rgb values of the Color3 and the given Color3 and stores the result in the object "result" * @param otherColor defines the second operand * @param result defines the Color3 object where to store the result * @returns the result Color3 */ multiplyToRef(otherColor, result) { result.r = this.r * otherColor.r; result.g = this.g * otherColor.g; result.b = this.b * otherColor.b; return result; } /** * Multiplies the current Color3 coordinates by the given ones * @param otherColor defines the second operand * @returns the current updated Color3 */ multiplyInPlace(otherColor) { this.r *= otherColor.r; this.g *= otherColor.g; this.b *= otherColor.b; return this; } /** * Returns a new Color3 set with the result of the multiplication of the current Color3 coordinates by the given floats * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @returns the new Color3 */ multiplyByFloats(r, g, b) { return new Color3(this.r * r, this.g * g, this.b * b); } /** * @internal * Do not use */ divide(_other) { throw new ReferenceError("Can not divide a color"); } /** * @internal * Do not use */ divideToRef(_other, _result) { throw new ReferenceError("Can not divide a color"); } /** * @internal * Do not use */ divideInPlace(_other) { throw new ReferenceError("Can not divide a color"); } /** * Updates the current Color3 with the minimal coordinate values between its and the given color ones * @param other defines the second operand * @returns the current updated Color3 */ minimizeInPlace(other) { return this.minimizeInPlaceFromFloats(other.r, other.g, other.b); } /** * Updates the current Color3 with the maximal coordinate values between its and the given color ones. * @param other defines the second operand * @returns the current updated Color3 */ maximizeInPlace(other) { return this.maximizeInPlaceFromFloats(other.r, other.g, other.b); } /** * Updates the current Color3 with the minimal coordinate values between its and the given coordinates * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @returns the current updated Color3 */ minimizeInPlaceFromFloats(r, g, b) { this.r = Math.min(r, this.r); this.g = Math.min(g, this.g); this.b = Math.min(b, this.b); return this; } /** * Updates the current Color3 with the maximal coordinate values between its and the given coordinates. * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @returns the current updated Color3 */ maximizeInPlaceFromFloats(r, g, b) { this.r = Math.max(r, this.r); this.g = Math.max(g, this.g); this.b = Math.max(b, this.b); return this; } /** * @internal * Do not use */ floorToRef(_result) { throw new ReferenceError("Can not floor a color"); } /** * @internal * Do not use */ floor() { throw new ReferenceError("Can not floor a color"); } /** * @internal * Do not use */ fractToRef(_result) { throw new ReferenceError("Can not fract a color"); } /** * @internal * Do not use */ fract() { throw new ReferenceError("Can not fract a color"); } /** * Determines equality between Color3 objects * @param otherColor defines the second operand * @returns true if the rgb values are equal to the given ones */ equals(otherColor) { return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b; } /** * Alias for equalsToFloats * @param r red color component * @param g green color component * @param b blue color component * @returns boolean */ equalsFloats(r, g, b) { return this.equalsToFloats(r, g, b); } /** * Determines equality between the current Color3 object and a set of r,b,g values * @param r defines the red component to check * @param g defines the green component to check * @param b defines the blue component to check * @returns true if the rgb values are equal to the given ones */ equalsToFloats(r, g, b) { return this.r === r && this.g === g && this.b === b; } /** * Returns true if the current Color3 and the given color coordinates are distant less than epsilon * @param otherColor defines the second operand * @param epsilon defines the minimal distance to define values as equals * @returns true if both colors are distant less than epsilon */ equalsWithEpsilon(otherColor, epsilon = Epsilon) { return WithinEpsilon(this.r, otherColor.r, epsilon) && WithinEpsilon(this.g, otherColor.g, epsilon) && WithinEpsilon(this.b, otherColor.b, epsilon); } /** * @internal * Do not use */ negate() { throw new ReferenceError("Can not negate a color"); } /** * @internal * Do not use */ negateInPlace() { throw new ReferenceError("Can not negate a color"); } /** * @internal * Do not use */ negateToRef(_result) { throw new ReferenceError("Can not negate a color"); } /** * Creates a new Color3 with the current Color3 values multiplied by scale * @param scale defines the scaling factor to apply * @returns a new Color3 object */ scale(scale) { return new Color3(this.r * scale, this.g * scale, this.b * scale); } /** * Multiplies the Color3 values by the float "scale" * @param scale defines the scaling factor to apply * @returns the current updated Color3 */ scaleInPlace(scale) { this.r *= scale; this.g *= scale; this.b *= scale; return this; } /** * Multiplies the rgb values by scale and stores the result into "result" * @param scale defines the scaling factor * @param result defines the Color3 object where to store the result * @returns the result Color3 */ scaleToRef(scale, result) { result.r = this.r * scale; result.g = this.g * scale; result.b = this.b * scale; return result; } /** * Scale the current Color3 values by a factor and add the result to a given Color3 * @param scale defines the scale factor * @param result defines color to store the result into * @returns the result Color3 */ scaleAndAddToRef(scale, result) { result.r += this.r * scale; result.g += this.g * scale; result.b += this.b * scale; return result; } /** * Clamps the rgb values by the min and max values and stores the result into "result" * @param min defines minimum clamping value (default is 0) * @param max defines maximum clamping value (default is 1) * @param result defines color to store the result into * @returns the result Color3 */ clampToRef(min = 0, max = 1, result) { result.r = Clamp(this.r, min, max); result.g = Clamp(this.g, min, max); result.b = Clamp(this.b, min, max); return result; } /** * Creates a new Color3 set with the added values of the current Color3 and of the given one * @param otherColor defines the second operand * @returns the new Color3 */ add(otherColor) { return new Color3(this.r + otherColor.r, this.g + otherColor.g, this.b + otherColor.b); } /** * Adds the given color to the current Color3 * @param otherColor defines the second operand * @returns the current updated Color3 */ addInPlace(otherColor) { this.r += otherColor.r; this.g += otherColor.g; this.b += otherColor.b; return this; } /** * Adds the given coordinates to the current Color3 * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @returns the current updated Color3 */ addInPlaceFromFloats(r, g, b) { this.r += r; this.g += g; this.b += b; return this; } /** * Stores the result of the addition of the current Color3 and given one rgb values into "result" * @param otherColor defines the second operand * @param result defines Color3 object to store the result into * @returns the unmodified current Color3 */ addToRef(otherColor, result) { result.r = this.r + otherColor.r; result.g = this.g + otherColor.g; result.b = this.b + otherColor.b; return result; } /** * Returns a new Color3 set with the subtracted values of the given one from the current Color3 * @param otherColor defines the second operand * @returns the new Color3 */ subtract(otherColor) { return new Color3(this.r - otherColor.r, this.g - otherColor.g, this.b - otherColor.b); } /** * Stores the result of the subtraction of given one from the current Color3 rgb values into "result" * @param otherColor defines the second operand * @param result defines Color3 object to store the result into * @returns the unmodified current Color3 */ subtractToRef(otherColor, result) { result.r = this.r - otherColor.r; result.g = this.g - otherColor.g; result.b = this.b - otherColor.b; return result; } /** * Subtract the given color from the current Color3 * @param otherColor defines the second operand * @returns the current updated Color3 */ subtractInPlace(otherColor) { this.r -= otherColor.r; this.g -= otherColor.g; this.b -= otherColor.b; return this; } /** * Returns a new Color3 set with the subtraction of the given floats from the current Color3 coordinates * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @returns the resulting Color3 */ subtractFromFloats(r, g, b) { return new Color3(this.r - r, this.g - g, this.b - b); } /** * Subtracts the given floats from the current Color3 coordinates and set the given color "result" with this result * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @param result defines the Color3 object where to store the result * @returns the result */ subtractFromFloatsToRef(r, g, b, result) { result.r = this.r - r; result.g = this.g - g; result.b = this.b - b; return result; } /** * Copy the current object * @returns a new Color3 copied the current one */ clone() { return new Color3(this.r, this.g, this.b); } /** * Copies the rgb values from the source in the current Color3 * @param source defines the source Color3 object * @returns the updated Color3 object */ copyFrom(source) { this.r = source.r; this.g = source.g; this.b = source.b; return this; } /** * Updates the Color3 rgb values from the given floats * @param r defines the red component to read from * @param g defines the green component to read from * @param b defines the blue component to read from * @returns the current Color3 object */ copyFromFloats(r, g, b) { this.r = r; this.g = g; this.b = b; return this; } /** * Updates the Color3 rgb values from the given floats * @param r defines the red component to read from * @param g defines the green component to read from * @param b defines the blue component to read from * @returns the current Color3 object */ set(r, g, b) { return this.copyFromFloats(r, g, b); } /** * Copies the given float to the current Color3 coordinates * @param v defines the r, g and b coordinates of the operand * @returns the current updated Color3 */ setAll(v) { this.r = this.g = this.b = v; return this; } /** * Compute the Color3 hexadecimal code as a string * @returns a string containing the hexadecimal representation of the Color3 object */ toHexString() { const intR = Math.round(this.r * 255); const intG = Math.round(this.g * 255); const intB = Math.round(this.b * 255); return "#" + ToHex(intR) + ToHex(intG) + ToHex(intB); } /** * Updates the Color3 rgb values from the string containing valid hexadecimal values * @param hex defines a string containing valid hexadecimal values * @returns the current Color3 object */ fromHexString(hex) { if (hex.substring(0, 1) !== "#" || hex.length !== 7) { return this; } this.r = parseInt(hex.substring(1, 3), 16) / 255; this.g = parseInt(hex.substring(3, 5), 16) / 255; this.b = parseInt(hex.substring(5, 7), 16) / 255; return this; } /** * Converts current color in rgb space to HSV values * @returns a new color3 representing the HSV values */ toHSV() { return this.toHSVToRef(new Color3()); } /** * Converts current color in rgb space to HSV values * @param result defines the Color3 where to store the HSV values * @returns the updated result */ toHSVToRef(result) { const r = this.r; const g = this.g; const b = this.b; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h = 0; let s = 0; const v = max; const dm = max - min; if (max !== 0) { s = dm / max; } if (max != min) { if (max == r) { h = (g - b) / dm; if (g < b) { h += 6; } } else if (max == g) { h = (b - r) / dm + 2; } else if (max == b) { h = (r - g) / dm + 4; } h *= 60; } result.r = h; result.g = s; result.b = v; return result; } /** * Computes a new Color3 converted from the current one to linear space * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns a new Color3 object */ toLinearSpace(exact = false) { const convertedColor = new Color3(); this.toLinearSpaceToRef(convertedColor, exact); return convertedColor; } /** * Converts the Color3 values to linear space and stores the result in "convertedColor" * @param convertedColor defines the Color3 object where to store the linear space version * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns the unmodified Color3 */ toLinearSpaceToRef(convertedColor, exact = false) { if (exact) { convertedColor.r = ColorChannelToLinearSpaceExact(this.r); convertedColor.g = ColorChannelToLinearSpaceExact(this.g); convertedColor.b = ColorChannelToLinearSpaceExact(this.b); } else { convertedColor.r = ColorChannelToLinearSpace(this.r); convertedColor.g = ColorChannelToLinearSpace(this.g); convertedColor.b = ColorChannelToLinearSpace(this.b); } return this; } /** * Computes a new Color3 converted from the current one to gamma space * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns a new Color3 object */ toGammaSpace(exact = false) { const convertedColor = new Color3(); this.toGammaSpaceToRef(convertedColor, exact); return convertedColor; } /** * Converts the Color3 values to gamma space and stores the result in "convertedColor" * @param convertedColor defines the Color3 object where to store the gamma space version * @param exact defines if the conversion will be done in an exact way which is slower but more accurate (default is false) * @returns the unmodified Color3 */ toGammaSpaceToRef(convertedColor, exact = false) { if (exact) { convertedColor.r = ColorChannelToGammaSpaceExact(this.r); convertedColor.g = ColorChannelToGammaSpaceExact(this.g); convertedColor.b = ColorChannelToGammaSpaceExact(this.b); } else { convertedColor.r = ColorChannelToGammaSpace(this.r); convertedColor.g = ColorChannelToGammaSpace(this.g); convertedColor.b = ColorChannelToGammaSpace(this.b); } return this; } /** * Converts Hue, saturation and value to a Color3 (RGB) * @param hue defines the hue (value between 0 and 360) * @param saturation defines the saturation (value between 0 and 1) * @param value defines the value (value between 0 and 1) * @param result defines the Color3 where to store the RGB values * @returns the updated result */ static HSVtoRGBToRef(hue, saturation, value, result) { const chroma = value * saturation; const h = hue / 60; const x = chroma * (1 - Math.abs((h % 2) - 1)); let r = 0; let g = 0; let b = 0; if (h >= 0 && h <= 1) { r = chroma; g = x; } else if (h >= 1 && h <= 2) { r = x; g = chroma; } else if (h >= 2 && h <= 3) { g = chroma; b = x; } else if (h >= 3 && h <= 4) { g = x; b = chroma; } else if (h >= 4 && h <= 5) { r = x; b = chroma; } else if (h >= 5 && h <= 6) { r = chroma; b = x; } const m = value - chroma; result.r = r + m; result.g = g + m; result.b = b + m; return result; } /** * Converts Hue, saturation and value to a new Color3 (RGB) * @param hue defines the hue (value between 0 and 360) * @param saturation defines the saturation (value between 0 and 1) * @param value defines the value (value between 0 and 1) * @returns a new Color3 object */ static FromHSV(hue, saturation, value) { const result = new Color3(0, 0, 0); Color3.HSVtoRGBToRef(hue, saturation, value, result); return result; } /** * Creates a new Color3 from the string containing valid hexadecimal values * @param hex defines a string containing valid hexadecimal values * @returns a new Color3 object */ static FromHexString(hex) { return new Color3(0, 0, 0).fromHexString(hex); } /** * Creates a new Color3 from the starting index of the given array * @param array defines the source array * @param offset defines an offset in the source array * @returns a new Color3 object */ static FromArray(array, offset = 0) { return new Color3(array[offset], array[offset + 1], array[offset + 2]); } /** * Creates a new Color3 from the starting index element of the given array * @param array defines the source array to read from * @param offset defines the offset in the source array * @param result defines the target Color3 object */ static FromArrayToRef(array, offset = 0, result) { result.r = array[offset]; result.g = array[offset + 1]; result.b = array[offset + 2]; } /** * Creates a new Color3 from integer values (\< 256) * @param r defines the red component to read from (value between 0 and 255) * @param g defines the green component to read from (value between 0 and 255) * @param b defines the blue component to read from (value between 0 and 255) * @returns a new Color3 object */ static FromInts(r, g, b) { return new Color3(r / 255.0, g / 255.0, b / 255.0); } /** * Creates a new Color3 with values linearly interpolated of "amount" between the start Color3 and the end Color3 * @param start defines the start Color3 value * @param end defines the end Color3 value * @param amount defines the gradient value between start and end * @returns a new Color3 object */ static Lerp(start, end, amount) { const result = new Color3(0.0, 0.0, 0.0); Color3.LerpToRef(start, end, amount, result); return result; } /** * Creates a new Color3 with values linearly interpolated of "amount" between the start Color3 and the end Color3 * @param left defines the start value * @param right defines the end value * @param amount defines the gradient factor * @param result defines the Color3 object where to store the result */ static LerpToRef(left, right, amount, result) { result.r = left.r + (right.r - left.r) * amount; result.g = left.g + (right.g - left.g) * amount; result.b = left.b + (right.b - left.b) * amount; } /** * Returns a new Color3 located for "amount" (float) on the Hermite interpolation spline defined by the vectors "value1", "tangent1", "value2", "tangent2" * @param value1 defines the first control point * @param tangent1 defines the first tangent Color3 * @param value2 defines the second control point * @param tangent2 defines the second tangent Color3 * @param amount defines the amount on the interpolation spline (between 0 and 1) * @returns the new Color3 */ static Hermite(value1, tangent1, value2, tangent2, amount) { const squared = amount * amount; const cubed = amount * squared; const part1 = 2.0 * cubed - 3.0 * squared + 1.0; const part2 = -2.0 * cubed + 3.0 * squared; const part3 = cubed - 2.0 * squared + amount; const part4 = cubed - squared; const r = value1.r * part1 + value2.r * part2 + tangent1.r * part3 + tangent2.r * part4; const g = value1.g * part1 + value2.g * part2 + tangent1.g * part3 + tangent2.g * part4; const b = value1.b * part1 + value2.b * part2 + tangent1.b * part3 + tangent2.b * part4; return new Color3(r, g, b); } /** * Returns a new Color3 which is the 1st derivative of the Hermite spline defined by the colors "value1", "value2", "tangent1", "tangent2". * @param value1 defines the first control point * @param tangent1 defines the first tangent * @param value2 defines the second control point * @param tangent2 defines the second tangent * @param time define where the derivative must be done * @returns 1st derivative */ static Hermite1stDerivative(value1, tangent1, value2, tangent2, time) { const result = Color3.Black(); this.Hermite1stDerivativeToRef(value1, tangent1, value2, tangent2, time, result); return result; } /** * Returns a new Color3 which is the 1st derivative of the Hermite spline defined by the colors "value1", "value2", "tangent1", "tangent2". * @param value1 defines the first control point * @param tangent1 defines the first tangent * @param value2 defines the second control point * @param tangent2 defines the second tangent * @param time define where the derivative must be done * @param result define where to store the derivative */ static Hermite1stDerivativeToRef(value1, tangent1, value2, tangent2, time, result) { const t2 = time * time; result.r = (t2 - time) * 6 * value1.r + (3 * t2 - 4 * time + 1) * tangent1.r + (-t2 + time) * 6 * value2.r + (3 * t2 - 2 * time) * tangent2.r; result.g = (t2 - time) * 6 * value1.g + (3 * t2 - 4 * time + 1) * tangent1.g + (-t2 + time) * 6 * value2.g + (3 * t2 - 2 * time) * tangent2.g; result.b = (t2 - time) * 6 * value1.b + (3 * t2 - 4 * time + 1) * tangent1.b + (-t2 + time) * 6 * value2.b + (3 * t2 - 2 * time) * tangent2.b; } /** * Returns a Color3 value containing a red color * @returns a new Color3 object */ static Red() { return new Color3(1, 0, 0); } /** * Returns a Color3 value containing a green color * @returns a new Color3 object */ static Green() { return new Color3(0, 1, 0); } /** * Returns a Color3 value containing a blue color * @returns a new Color3 object */ static Blue() { return new Color3(0, 0, 1); } /** * Returns a Color3 value containing a black color * @returns a new Color3 object */ static Black() { return new Color3(0, 0, 0); } /** * Gets a Color3 value containing a black color that must not be updated */ static get BlackReadOnly() { return Color3._BlackReadOnly; } /** * Returns a Color3 value containing a white color * @returns a new Color3 object */ static White() { return new Color3(1, 1, 1); } /** * Returns a Color3 value containing a purple color * @returns a new Color3 object */ static Purple() { return new Color3(0.5, 0, 0.5); } /** * Returns a Color3 value containing a magenta color * @returns a new Color3 object */ static Magenta() { return new Color3(1, 0, 1); } /** * Returns a Color3 value containing a yellow color * @returns a new Color3 object */ static Yellow() { return new Color3(1, 1, 0); } /** * Returns a Color3 value containing a gray color * @returns a new Color3 object */ static Gray() { return new Color3(0.5, 0.5, 0.5); } /** * Returns a Color3 value containing a teal color * @returns a new Color3 object */ static Teal() { return new Color3(0, 1.0, 1.0); } /** * Returns a Color3 value containing a random color * @returns a new Color3 object */ static Random() { return new Color3(Math.random(), Math.random(), Math.random()); } } /** * If the first color is flagged with integers (as everything is 0,0,0), V8 stores all of the properties as integers internally because it doesn't know any better yet. * If subsequent colors are created with non-integer values, V8 determines that it would be best to represent these properties as doubles instead of integers, * and henceforth it will use floating-point representation for all color instances that it creates. * But the original color instances are unchanged and has a "deprecated map". * If we keep using the color instances from step 1, it will now be a poison pill which will mess up optimizations in any code it touches. */ Color3._V8PerformanceHack = new Color3(0.5, 0.5, 0.5); // Statics Color3._BlackReadOnly = Color3.Black(); Object.defineProperties(Color3.prototype, { dimension: { value: [3] }, rank: { value: 1 }, }); /** * Class used to hold a RBGA color */ export class Color4 { /** * Creates a new Color4 object from red, green, blue values, all between 0 and 1 * @param r defines the red component (between 0 and 1, default is 0) * @param g defines the green component (between 0 and 1, default is 0) * @param b defines the blue component (between 0 and 1, default is 0) * @param a defines the alpha component (between 0 and 1, default is 1) */ constructor( /** * [0] Defines the red component (between 0 and 1, default is 0) */ r = 0, /** * [0] Defines the green component (between 0 and 1, default is 0) */ g = 0, /** * [0] Defines the blue component (between 0 and 1, default is 0) */ b = 0, /** * [1] Defines the alpha component (between 0 and 1, default is 1) */ a = 1) { this.r = r; this.g = g; this.b = b; this.a = a; } // Operators /** * Creates a new array populated with 4 numeric elements : red, green, blue, alpha values * @returns the new array */ asArray() { return [this.r, this.g, this.b, this.a]; } /** * Stores from the starting index in the given array the Color4 successive values * @param array defines the array where to store the r,g,b components * @param index defines an optional index in the target array to define where to start storing values * @returns the current Color4 object */ toArray(array, index = 0) { array[index] = this.r; array[index + 1] = this.g; array[index + 2] = this.b; array[index + 3] = this.a; return this; } /** * Update the current color with values stored in an array from the starting index of the given array * @param array defines the source array * @param offset defines an offset in the source array * @returns the current Color4 object */ fromArray(array, offset = 0) { this.r = array[offset]; this.g = array[offset + 1]; this.b = array[offset + 2]; this.a = array[offset + 3]; return this; } /** * Determines equality between Color4 objects * @param otherColor defines the second operand * @returns true if the rgba values are equal to the given ones */ equals(otherColor) { return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b && this.a === otherColor.a; } /** * Creates a new Color4 set with the added values of the current Color4 and of the given one * @param otherColor defines the second operand * @returns a new Color4 object */ add(otherColor) { return new Color4(this.r + otherColor.r, this.g + otherColor.g, this.b + otherColor.b, this.a + otherColor.a); } /** * Updates the given color "result" with the result of the addition of the current Color4 and the given one. * @param otherColor the color to add * @param result the color to store the result * @returns result input */ addToRef(otherColor, result) { result.r = this.r + otherColor.r; result.g = this.g + otherColor.g; result.b = this.b + otherColor.b; result.a = this.a + otherColor.a; return result; } /** * Adds in place the given Color4 values to the current Color4 object * @param otherColor defines the second operand * @returns the current updated Color4 object */ addInPlace(otherColor) { this.r += otherColor.r; this.g += otherColor.g; this.b += otherColor.b; this.a += otherColor.a; return this; } /** * Adds the given coordinates to the current Color4 * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @param a defines the a coordinate of the operand * @returns the current updated Color4 */ addInPlaceFromFloats(r, g, b, a) { this.r += r; this.g += g; this.b += b; this.a += a; return this; } /** * Creates a new Color4 set with the subtracted values of the given one from the current Color4 * @param otherColor defines the second operand * @returns a new Color4 object */ subtract(otherColor) { return new Color4(this.r - otherColor.r, this.g - otherColor.g, this.b - otherColor.b, this.a - otherColor.a); } /** * Subtracts the given ones from the current Color4 values and stores the results in "result" * @param otherColor defines the second operand * @param result defines the Color4 object where to store the result * @returns the result Color4 object */ subtractToRef(otherColor, result) { result.r = this.r - otherColor.r; result.g = this.g - otherColor.g; result.b = this.b - otherColor.b; result.a = this.a - otherColor.a; return result; } /** * Subtract in place the given color from the current Color4. * @param otherColor the color to subtract * @returns the updated Color4. */ subtractInPlace(otherColor) { this.r -= otherColor.r; this.g -= otherColor.g; this.b -= otherColor.b; this.a -= otherColor.a; return this; } /** * Returns a new Color4 set with the result of the subtraction of the given floats from the current Color4 coordinates. * @param r value to subtract * @param g value to subtract * @param b value to subtract * @param a value to subtract * @returns new color containing the result */ subtractFromFloats(r, g, b, a) { return new Color4(this.r - r, this.g - g, this.b - b, this.a - a); } /** * Sets the given color "result" set with the result of the subtraction of the given floats from the current Color4 coordinates. * @param r value to subtract * @param g value to subtract * @param b value to subtract * @param a value to subtract * @param result the color to store the result in * @returns result input */ subtractFromFloatsToRef(r, g, b, a, result) { result.r = this.r - r; result.g = this.g - g; result.b = this.b - b; result.a = this.a - a; return result; } /** * Creates a new Color4 with the current Color4 values multiplied by scale * @param scale defines the scaling factor to apply * @returns a new Color4 object */ scale(scale) { return new Color4(this.r * scale, this.g * scale, this.b * scale, this.a * scale); } /** * Multiplies the Color4 values by the float "scale" * @param scale defines the scaling factor to apply * @returns the current updated Color4 */ scaleInPlace(scale) { this.r *= scale; this.g *= scale; this.b *= scale; this.a *= scale; return this; } /** * Multiplies the current Color4 values by scale and stores the result in "result" * @param scale defines the scaling factor to apply * @param result defines the Color4 object where to store the result * @returns the result Color4 */ scaleToRef(scale, result) { result.r = this.r * scale; result.g = this.g * scale; result.b = this.b * scale; result.a = this.a * scale; return result; } /** * Scale the current Color4 values by a factor and add the result to a given Color4 * @param scale defines the scale factor * @param result defines the Color4 object where to store the result * @returns the result Color4 */ scaleAndAddToRef(scale, result) { result.r += this.r * scale; result.g += this.g * scale; result.b += this.b * scale; result.a += this.a * scale; return result; } /** * Clamps the rgb values by the min and max values and stores the result into "result" * @param min defines minimum clamping value (default is 0) * @param max defines maximum clamping value (default is 1) * @param result defines color to store the result into. * @returns the result Color4 */ clampToRef(min = 0, max = 1, result) { result.r = Clamp(this.r, min, max); result.g = Clamp(this.g, min, max); result.b = Clamp(this.b, min, max); result.a = Clamp(this.a, min, max); return result; } /** * Multiply an Color4 value by another and return a new Color4 object * @param color defines the Color4 value to multiply by * @returns a new Color4 object */ multiply(color) { return new Color4(this.r * color.r, this.g * color.g, this.b * color.b, this.a * color.a); } /** * Multiply a Color4 value by another and push the result in a reference value * @param color defines the Color4 value to multiply by * @param result defines the Color4 to fill the result in * @returns the result Color4 */ multiplyToRef(color, result) { result.r = this.r * color.r; result.g = this.g * color.g; result.b = this.b * color.b; result.a = this.a * color.a; return result; } /** * Multiplies in place the current Color4 by the given one. * @param otherColor color to multiple with * @returns the updated Color4. */ multiplyInPlace(otherColor) { this.r *= otherColor.r; this.g *= otherColor.g; this.b *= otherColor.b; this.a *= otherColor.a; return this; } /** * Returns a new Color4 set with the multiplication result of the given floats and the current Color4 coordinates. * @param r value multiply with * @param g value multiply with * @param b value multiply with * @param a value multiply with * @returns resulting new color */ multiplyByFloats(r, g, b, a) { return new Color4(this.r * r, this.g * g, this.b * b, this.a * a); } /** * @internal * Do not use */ divide(_other) { throw new ReferenceError("Can not divide a color"); } /** * @internal * Do not use */ divideToRef(_other, _result) { throw new ReferenceError("Can not divide a color"); } /** * @internal * Do not use */ divideInPlace(_other) { throw new ReferenceError("Can not divide a color"); } /** * Updates the Color4 coordinates with the minimum values between its own and the given color ones * @param other defines the second operand * @returns the current updated Color4 */ minimizeInPlace(other) { this.r = Math.min(this.r, other.r); this.g = Math.min(this.g, other.g); this.b = Math.min(this.b, other.b); this.a = Math.min(this.a, other.a); return this; } /** * Updates the Color4 coordinates with the maximum values between its own and the given color ones * @param other defines the second operand * @returns the current updated Color4 */ maximizeInPlace(other) { this.r = Math.max(this.r, other.r); this.g = Math.max(this.g, other.g); this.b = Math.max(this.b, other.b); this.a = Math.max(this.a, other.a); return this; } /** * Updates the current Color4 with the minimal coordinate values between its and the given coordinates * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @param a defines the a coordinate of the operand * @returns the current updated Color4 */ minimizeInPlaceFromFloats(r, g, b, a) { this.r = Math.min(r, this.r); this.g = Math.min(g, this.g); this.b = Math.min(b, this.b); this.a = Math.min(a, this.a); return this; } /** * Updates the current Color4 with the maximal coordinate values between its and the given coordinates. * @param r defines the r coordinate of the operand * @param g defines the g coordinate of the operand * @param b defines the b coordinate of the operand * @param a defines the a coordinate of the operand * @returns the current updated Color4 */ maximizeInPlaceFromFloats(r, g, b, a) { this.r = Math.max(r, this.r); this.g = Math.max(g, this.g); this.b = Math.max(b, this.b); this.a = Math.max(a, this.a); return this; } /** * @internal * Do not use */ floorToRef(_result) { throw new ReferenceError("Can not floor a color"); } /** * @internal * Do not use */ floor() { throw new ReferenceError("Can not floor a color"); } /** * @internal * Do not use */ fractToRef(_result) { throw new ReferenceError("Can not fract a color"); } /** * @internal * Do not use */ fract() { throw new ReferenceError("Can not fract a color"); } /** * @internal * Do not use */ negate() { throw new ReferenceError("Can not negate a color"); } /** * @internal * Do not use */ negateInPlace() { throw new ReferenceError("Can not negate a color"); } /** * @internal * Do not use */ negateToRef(_result) { throw new ReferenceError("Can not negate a color"); } /** * Boolean : True if the current Color4 coordinates are each beneath the distance "epsilon" from the given color ones. * @param otherColor color to compare against * @param epsilon (Default: very small number) * @returns true if they are equal */ equalsWithEpsilon(otherColor, epsilon = Epsilon) { return (WithinEpsilon(this.r, otherColor.r, epsilon) && WithinEpsilon(this.g, otherColor.g, epsilon) && WithinEpsilon(this.b, otherColor.b, epsilon) && WithinEpsilon(this.a, otherColor.a, epsilon)); } /** * Boolean : True if the given floats are strictly equal to the current Color4 coordinates. * @param x x value to compare against * @param y y value to compare against * @param z z value to compare against * @param w w value to compare against * @returns true if equal */ equalsToFloats(x, y, z, w) { return this.r === x && this.g === y && this.b === z && this.a === w; } /** * Creates a string with the Color4 current values * @returns the string representation of the Color4 object */ toString() { return "{R: " + this.r + " G:" + this.g + " B:" + this.b + " A:" + this.a + "}"; } /** * Returns the string "Color4" * @returns "Color4" */ getClassName() { return "Color4"; } /** * Compute the Color4 hash code * @returns an unique number that can be used to hash Color4 objects */ getHashCode() { let hash = (this.r * 255) | 0; hash = (hash * 397) ^ ((this.g * 255) | 0); hash = (hash * 397) ^ ((this.b * 255) | 0); hash = (hash * 397) ^ ((this.a * 255) | 0); return hash; } /** * Creates a new Color4 copied from the current one * @returns a new Color4 object */ clone() { const result = new Color4(); return result.copyFrom(this); } /** * Copies the given Color4 values into the current one * @param source defines the source Color4 object * @returns the current updated Color4 object */ copyFrom(source) { this.r = source.r; this.g = source.g; this.b = source.b; this.a = source.a; return this; } /** * Copies the given float values into the current one * @param r defines the red component to read from * @param g defines the green component to read from * @param b defines the blue component to read from * @param a defines the alpha component to read from * @returns the current updated Color4 object */ copyFromFloats(r, g, b, a) { this.r = r; this.g = g; this.b = b; this.a = a; return this; } /** * Copies the given float values into the current one * @param r defines the red component to read from * @param g defines the green component to read from * @param b defines the blue component to read from * @param a defines the alpha component to read from * @returns the current updated Color4 object */ set(r, g, b, a) { return this.copyFromFloats(r, g, b, a); } /** * Copies the given float to the current Vector4 coordinates * @param v defines the r, g, b, and a coordinates of the operand * @returns the current updated Vector4 */ setAll(v) { this.r = this.g = this.b = this.a = v; return this; } /** * Compute the Color4 hexadecimal code as a string * @param returnAsColor3 defines if the string should only contains RGB values (off by default) * @returns a string containing the hexadecimal representation of the Color4 object */ toHexString(returnAsColor3 = false) { const intR = Math.round(this.r * 255); const intG = Math.round(this.g * 255); const intB = Math.round(this.b * 255); if (returnAsColor3) { return "#" + ToHex(intR) + ToHex(intG) + ToHex(intB); } const intA = Math.round(this.a * 255); return "