From 005e82f5a732f3fc271ddbc7bdf80c01f92bd603 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Fri, 10 Nov 2023 18:14:12 +0800 Subject: [PATCH 1/6] fix: camera error bug --- packages/core/src/Camera.ts | 11 ++++-- packages/core/src/ComponentsManager.ts | 24 ++++++++++++ packages/core/src/DisorderedArray.ts | 4 ++ packages/core/src/Engine.ts | 31 +++++++++------ packages/core/src/Scene.ts | 39 ------------------- .../core/src/input/pointer/PointerManager.ts | 8 ++-- 6 files changed, 59 insertions(+), 58 deletions(-) diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 163c592fd6..28e442e674 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -77,6 +77,9 @@ export class Camera extends Component { _replacementShader: Shader = null; /** @internal */ _replacementSubShaderTag: ShaderTagKey = null; + /** @internal */ + @ignoreClone + _cameraIndex: number = -1; private _priority: number = 0; private _shaderData: ShaderData = new ShaderData(ShaderDataGroup.Camera); @@ -202,8 +205,8 @@ export class Camera extends Component { set priority(value: number) { if (this._priority !== value) { - if (this._entity._isActiveInScene && this.enabled) { - this.scene._cameraNeedSorting = true; + if (this._phasedActiveInScene) { + this.scene._componentsManager._cameraNeedSorting = true; } this._priority = value; } @@ -571,14 +574,14 @@ export class Camera extends Component { * @inheritdoc */ override _onEnableInScene(): void { - this.scene._attachRenderCamera(this); + this.scene._componentsManager.addCamera(this); } /** * @inheritdoc */ override _onDisableInScene(): void { - this.scene._detachRenderCamera(this); + this.scene._componentsManager.removeCamera(this); } /** diff --git a/packages/core/src/ComponentsManager.ts b/packages/core/src/ComponentsManager.ts index e1ecc0799c..3c7f4e3e98 100644 --- a/packages/core/src/ComponentsManager.ts +++ b/packages/core/src/ComponentsManager.ts @@ -9,6 +9,10 @@ import { Animator } from "./animation"; * The manager of the components. */ export class ComponentsManager { + /* @internal */ + _cameraNeedSorting: boolean = false; + /** @internal */ + _activeCameras: DisorderedArray = new DisorderedArray(); /** @internal */ _renderers: DisorderedArray = new DisorderedArray(); @@ -30,6 +34,25 @@ export class ComponentsManager { // Delay dispose active/inActive Pool private _componentsContainerPool: Component[][] = []; + addCamera(camera: Camera) { + camera._cameraIndex = this._activeCameras.length; + this._activeCameras.add(camera); + this._cameraNeedSorting = true; + } + + removeCamera(camera: Camera) { + const replaced = this._activeCameras.deleteByIndex(camera._cameraIndex); + replaced && (replaced._cameraIndex = camera._cameraIndex); + camera._cameraIndex = -1; + } + + sortCameras(): void { + if (this._cameraNeedSorting) { + this._activeCameras.sort((a, b) => a.priority - b.priority); + this._cameraNeedSorting = false; + } + } + addRenderer(renderer: Renderer) { renderer._rendererIndex = this._renderers.length; this._renderers.add(renderer); @@ -233,5 +256,6 @@ export class ComponentsManager { this._onPhysicsUpdateScripts.garbageCollection(); this._onUpdateAnimations.garbageCollection(); this._onUpdateRenderers.garbageCollection(); + this._activeCameras.garbageCollection(); } } diff --git a/packages/core/src/DisorderedArray.ts b/packages/core/src/DisorderedArray.ts index 14792dbb8f..71c4198fe1 100644 --- a/packages/core/src/DisorderedArray.ts +++ b/packages/core/src/DisorderedArray.ts @@ -86,6 +86,10 @@ export class DisorderedArray { this._endLoopAndClear(); } + sort(compareFn: (a: T, b: T) => number): void { + this._elements.sort(compareFn); + } + garbageCollection(): void { this._elements.length = this.length; } diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index b68ac09726..d74c7d1e00 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -1,6 +1,8 @@ import { IPhysics, IPhysicsManager, IShaderLab } from "@galacean/engine-design"; import { Color } from "@galacean/engine-math/src/Color"; +import { SpriteMaskInteraction } from "./2d"; import { Font } from "./2d/text/Font"; +import { Camera } from "./Camera"; import { Canvas } from "./Canvas"; import { EngineSettings } from "./EngineSettings"; import { Entity } from "./Entity"; @@ -25,6 +27,7 @@ import { ParticleBufferUtils } from "./particle/ParticleBufferUtils"; import { PhysicsScene } from "./physics/PhysicsScene"; import { ColliderShape } from "./physics/shape/ColliderShape"; import { IHardwareRenderer } from "./renderingHardwareInterface"; +import { CompareFunction } from "./shader"; import { Shader } from "./shader/Shader"; import { ShaderMacro } from "./shader/ShaderMacro"; import { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; @@ -38,8 +41,6 @@ import { CullMode } from "./shader/enums/CullMode"; import { RenderQueueType } from "./shader/enums/RenderQueueType"; import { RenderState } from "./shader/state/RenderState"; import { Texture2D, Texture2DArray, TextureCube, TextureCubeFace, TextureFormat } from "./texture"; -import { CompareFunction } from "./shader"; -import { SpriteMaskInteraction } from "./2d"; ShaderPool.init(); @@ -336,8 +337,9 @@ export class Engine extends EventDispatcher { for (let i = 0; i < sceneCount; i++) { const scene = scenes[i]; if (!scene.isActive || scene.destroyed) continue; - scene._cameraNeedSorting && scene._sortCameras(); - scene._componentsManager.callScriptOnStart(); + const componentsManager = scene._componentsManager; + componentsManager.sortCameras(); + componentsManager.callScriptOnStart(); } // Update physics and fire `onPhysicsUpdate` @@ -498,11 +500,15 @@ export class Engine extends EventDispatcher { for (let i = 0, n = scenes.length; i < n; i++) { const scene = scenes[i]; if (!scene.isActive || scene.destroyed) continue; - const cameras = scene._activeCameras; - const cameraCount = cameras.length; - if (cameraCount > 0) { - for (let i = 0; i < cameraCount; i++) { - const camera = cameras[i]; + const cameras = scene._componentsManager._activeCameras; + + if (cameras.length === 0) { + Logger.debug("No active camera in scene."); + continue; + } + + cameras.forEach( + (camera: Camera) => { const componentsManager = scene._componentsManager; componentsManager.callCameraOnBeginRender(camera); camera.render(); @@ -512,10 +518,11 @@ export class Engine extends EventDispatcher { if (this._hardwareRenderer._options._forceFlush) { this._hardwareRenderer.flush(); } + }, + (camera: Camera, index: number) => { + camera._cameraIndex = index; } - } else { - Logger.debug("No active camera in scene."); - } + ); } } diff --git a/packages/core/src/Scene.ts b/packages/core/src/Scene.ts index d6f322ce80..1a4644c1d3 100644 --- a/packages/core/src/Scene.ts +++ b/packages/core/src/Scene.ts @@ -1,6 +1,5 @@ import { Color, Vector3, Vector4 } from "@galacean/engine-math"; import { Background } from "./Background"; -import { Camera } from "./Camera"; import { ComponentsManager } from "./ComponentsManager"; import { Engine } from "./Engine"; import { Entity } from "./Entity"; @@ -44,15 +43,11 @@ export class Scene extends EngineObject { /** Max Shadow distance. */ shadowDistance: number = 50; - /* @internal */ - _cameraNeedSorting: boolean = false; /* @internal */ _lightManager: LightManager = new LightManager(); /* @internal */ _componentsManager: ComponentsManager = new ComponentsManager(); /** @internal */ - _activeCameras: Camera[] = []; - /** @internal */ _isActiveInEngine: boolean = false; /** @internal */ _sceneManager: SceneManager; @@ -401,39 +396,6 @@ export class Scene extends EngineObject { return null; } - /** - * @internal - */ - _sortCameras(): void { - this._activeCameras.sort((a, b) => a.priority - b.priority); - this._cameraNeedSorting = false; - } - - /** - * @internal - */ - _attachRenderCamera(camera: Camera): void { - const activeCameras = this._activeCameras; - const index = activeCameras.indexOf(camera); - if (index === -1) { - activeCameras.push(camera); - this._cameraNeedSorting = true; - } else { - Logger.warn("Camera already attached."); - } - } - - /** - * @internal - */ - _detachRenderCamera(camera: Camera): void { - const activeCameras = this._activeCameras; - const index = activeCameras.indexOf(camera); - if (index !== -1) { - activeCameras.splice(index, 1); - } - } - /** * @internal */ @@ -514,7 +476,6 @@ export class Scene extends EngineObject { while (this.rootEntitiesCount > 0) { this._rootEntities[0].destroy(); } - this._activeCameras.length = 0; this.background.destroy(); this._ambientLight && this._ambientLight._removeFromScene(this); this.shaderData._addReferCount(-1); diff --git a/packages/core/src/input/pointer/PointerManager.ts b/packages/core/src/input/pointer/PointerManager.ts index c092f0c47e..f2ff440567 100644 --- a/packages/core/src/input/pointer/PointerManager.ts +++ b/packages/core/src/input/pointer/PointerManager.ts @@ -293,10 +293,12 @@ export class PointerManager implements IInput { if (!scene.isActive || scene.destroyed) { continue; } - const { _activeCameras: cameras } = scene; - for (let j = cameras.length - 1; j >= 0; j--) { + const { _activeCameras: cameraArray } = scene._componentsManager; + const cameras = cameraArray._elements; + + for (let j = cameraArray.length - 1; j >= 0; j--) { const camera = cameras[j]; - if (!camera.enabled || camera.renderTarget) { + if (camera.renderTarget) { continue; } const { x: vpX, y: vpY, z: vpW, w: vpH } = camera.viewport; From 9e6541b71168336afc067b553402dbb3fd3c4ef9 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Fri, 10 Nov 2023 18:51:05 +0800 Subject: [PATCH 2/6] refactor: opt code --- packages/core/src/input/pointer/PointerManager.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/input/pointer/PointerManager.ts b/packages/core/src/input/pointer/PointerManager.ts index f2ff440567..5b55483080 100644 --- a/packages/core/src/input/pointer/PointerManager.ts +++ b/packages/core/src/input/pointer/PointerManager.ts @@ -293,11 +293,11 @@ export class PointerManager implements IInput { if (!scene.isActive || scene.destroyed) { continue; } - const { _activeCameras: cameraArray } = scene._componentsManager; - const cameras = cameraArray._elements; + const { _activeCameras: cameras } = scene._componentsManager; + const elements = cameras._elements; - for (let j = cameraArray.length - 1; j >= 0; j--) { - const camera = cameras[j]; + for (let j = cameras.length - 1; j >= 0; j--) { + const camera = elements[j]; if (camera.renderTarget) { continue; } From 6757c37f61607605f12274424829b23b745db840 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Mon, 13 Nov 2023 11:29:01 +0800 Subject: [PATCH 3/6] fix: `_cameraIndex` bug --- packages/core/src/ComponentsManager.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/core/src/ComponentsManager.ts b/packages/core/src/ComponentsManager.ts index 3c7f4e3e98..5a7c3a6700 100644 --- a/packages/core/src/ComponentsManager.ts +++ b/packages/core/src/ComponentsManager.ts @@ -44,11 +44,20 @@ export class ComponentsManager { const replaced = this._activeCameras.deleteByIndex(camera._cameraIndex); replaced && (replaced._cameraIndex = camera._cameraIndex); camera._cameraIndex = -1; + this._cameraNeedSorting = true; } sortCameras(): void { if (this._cameraNeedSorting) { - this._activeCameras.sort((a, b) => a.priority - b.priority); + this._activeCameras.sort((a, b) => { + const result = a.priority - b.priority; + if (result > 0) { + const temp = a._cameraIndex; + a._cameraIndex = b._cameraIndex; + b._cameraIndex = temp; + } + return result; + }); this._cameraNeedSorting = false; } } From 035356acab4ca249bc373ef349413304f09a852a Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Mon, 13 Nov 2023 11:44:37 +0800 Subject: [PATCH 4/6] refactor: opt code --- packages/core/src/ComponentsManager.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/core/src/ComponentsManager.ts b/packages/core/src/ComponentsManager.ts index 5a7c3a6700..09b0096c21 100644 --- a/packages/core/src/ComponentsManager.ts +++ b/packages/core/src/ComponentsManager.ts @@ -49,15 +49,11 @@ export class ComponentsManager { sortCameras(): void { if (this._cameraNeedSorting) { - this._activeCameras.sort((a, b) => { - const result = a.priority - b.priority; - if (result > 0) { - const temp = a._cameraIndex; - a._cameraIndex = b._cameraIndex; - b._cameraIndex = temp; - } - return result; - }); + const activeCameras = this._activeCameras; + activeCameras.sort((a, b) => a.priority - b.priority); + for (let i = 0, n = activeCameras.length; i < n; i++) { + activeCameras.get(i)._cameraIndex = i; + } this._cameraNeedSorting = false; } } From 96ecdab227d9ecbfb971382bc1ab4ec825727836 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Mon, 13 Nov 2023 12:27:46 +0800 Subject: [PATCH 5/6] refactor: opt code --- packages/core/src/DisorderedArray.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/DisorderedArray.ts b/packages/core/src/DisorderedArray.ts index 71c4198fe1..19d31d201b 100644 --- a/packages/core/src/DisorderedArray.ts +++ b/packages/core/src/DisorderedArray.ts @@ -69,7 +69,7 @@ export class DisorderedArray { forEach(callbackFn: (element: T) => void, swapFn: (element: T, index: number) => void): void { this._startLoop(); const elements = this._elements; - for (let i = 0; i < this.length; i++) { + for (let i = 0, n = this.length; i < n; i++) { const element = elements[i]; element && callbackFn(element); } @@ -79,7 +79,7 @@ export class DisorderedArray { forEachAndClean(callbackFn: (e: T) => void): void { this._startLoop(); const elements = this._elements; - for (let i = 0; i < this.length; i++) { + for (let i = 0, n = this.length; i < n; i++) { const element = elements[i]; element && callbackFn(element); } From 36fee144f1b0eaf428a3b39f69fb513d6f96fd82 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Mon, 13 Nov 2023 13:45:29 +0800 Subject: [PATCH 6/6] refactor: opt code --- packages/core/src/DisorderedArray.ts | 4 +- .../core/src/RenderPipeline/RenderQueue.ts | 106 +-------- packages/core/src/Utils.ts | 222 +++++++++++++----- 3 files changed, 168 insertions(+), 164 deletions(-) diff --git a/packages/core/src/DisorderedArray.ts b/packages/core/src/DisorderedArray.ts index 19d31d201b..75412e1b14 100644 --- a/packages/core/src/DisorderedArray.ts +++ b/packages/core/src/DisorderedArray.ts @@ -1,3 +1,5 @@ +import { Utils } from "./Utils"; + /** * High-performance unordered array, delete uses exchange method to improve performance, internal capacity only increases. */ @@ -87,7 +89,7 @@ export class DisorderedArray { } sort(compareFn: (a: T, b: T) => number): void { - this._elements.sort(compareFn); + Utils._quickSort(this._elements, 0, this.length, compareFn); } garbageCollection(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 29ab6b7e0f..1cb10380f5 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -1,6 +1,7 @@ import { Camera } from "../Camera"; import { Engine } from "../Engine"; import { Layer } from "../Layer"; +import { Utils } from "../Utils"; import { RenderQueueType, Shader } from "../shader"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; import { RenderContext } from "./RenderContext"; @@ -194,7 +195,7 @@ export class RenderQueue { * Sort the elements. */ sort(compareFunc: Function): void { - this._quickSort(this.elements, 0, this.elements.length, compareFunc); + Utils._quickSort(this.elements, 0, this.elements.length, compareFunc); } /** @@ -204,107 +205,4 @@ export class RenderQueue { _initSpriteBatcher(engine: Engine): void { this._spriteBatcher = new SpriteBatcher(engine); } - - /** - * @remarks - * Modified based on v8. - * https://github.com/v8/v8/blob/7.2-lkgr/src/js/array.js - */ - private _quickSort(a: T[], from: number, to: number, compareFunc: Function): void { - while (true) { - // Insertion sort is faster for short arrays. - if (to - from <= 10) { - this._insertionSort(a, from, to, compareFunc); - return; - } - const third_index = (from + to) >> 1; - // Find a pivot as the median of first, last and middle element. - let v0 = a[from]; - let v1 = a[to - 1]; - let v2 = a[third_index]; - const c01 = compareFunc(v0, v1); - if (c01 > 0) { - // v1 < v0, so swap them. - const tmp = v0; - v0 = v1; - v1 = tmp; - } // v0 <= v1. - const c02 = compareFunc(v0, v2); - if (c02 >= 0) { - // v2 <= v0 <= v1. - const tmp = v0; - v0 = v2; - v2 = v1; - v1 = tmp; - } else { - // v0 <= v1 && v0 < v2 - const c12 = compareFunc(v1, v2); - if (c12 > 0) { - // v0 <= v2 < v1 - const tmp = v1; - v1 = v2; - v2 = tmp; - } - } - // v0 <= v1 <= v2 - a[from] = v0; - a[to - 1] = v2; - const pivot = v1; - let low_end = from + 1; // Upper bound of elements lower than pivot. - let high_start = to - 1; // Lower bound of elements greater than pivot. - a[third_index] = a[low_end]; - a[low_end] = pivot; - - // From low_end to i are elements equal to pivot. - // From i to high_start are elements that haven't been compared yet. - partition: for (let i = low_end + 1; i < high_start; i++) { - let element = a[i]; - let order = compareFunc(element, pivot); - if (order < 0) { - a[i] = a[low_end]; - a[low_end] = element; - low_end++; - } else if (order > 0) { - do { - high_start--; - if (high_start == i) break partition; - const top_elem = a[high_start]; - order = compareFunc(top_elem, pivot); - } while (order > 0); - a[i] = a[high_start]; - a[high_start] = element; - if (order < 0) { - element = a[i]; - a[i] = a[low_end]; - a[low_end] = element; - low_end++; - } - } - } - if (to - high_start < low_end - from) { - this._quickSort(a, high_start, to, compareFunc); - to = low_end; - } else { - this._quickSort(a, from, low_end, compareFunc); - from = high_start; - } - } - } - - private _insertionSort(a: T[], from: number, to: number, compareFunc: Function): void { - for (let i = from + 1; i < to; i++) { - let j; - const element = a[i]; - for (j = i - 1; j >= from; j--) { - const tmp = a[j]; - const order = compareFunc(tmp, element); - if (order > 0) { - a[j + 1] = tmp; - } else { - break; - } - } - a[j + 1] = element; - } - } } diff --git a/packages/core/src/Utils.ts b/packages/core/src/Utils.ts index d9d853c870..2c8258f46a 100644 --- a/packages/core/src/Utils.ts +++ b/packages/core/src/Utils.ts @@ -1,65 +1,6 @@ import { Matrix } from "@galacean/engine-math"; export class Utils { - /** - * @internal - */ - static _floatMatrixMultiply(left: Matrix, re: Float32Array, rOffset: number, oe: Float32Array, offset: number): void { - const le = left.elements; - - // prettier-ignore - const l11 = le[0], l12 = le[1], l13 = le[2], l14 = le[3], - l21 = le[4], l22 = le[5], l23 = le[6], l24 = le[7], - l31 = le[8], l32 = le[9], l33 = le[10], l34 = le[11], - l41 = le[12], l42 = le[13], l43 = le[14], l44 = le[15]; - - // prettier-ignore - const r11 = re[rOffset], r12 = re[rOffset + 1], r13 = re[rOffset + 2], r14 = re[rOffset + 3], - r21 = re[rOffset + 4], r22 = re[rOffset + 5], r23 = re[rOffset + 6], r24 = re[rOffset + 7], - r31 = re[rOffset + 8], r32 = re[rOffset + 9], r33 = re[rOffset + 10], r34 = re[rOffset + 11], - r41 = re[rOffset + 12], r42 = re[rOffset + 13], r43 = re[rOffset + 14], r44 = re[rOffset + 15]; - - oe[offset] = l11 * r11 + l21 * r12 + l31 * r13 + l41 * r14; - oe[offset + 1] = l12 * r11 + l22 * r12 + l32 * r13 + l42 * r14; - oe[offset + 2] = l13 * r11 + l23 * r12 + l33 * r13 + l43 * r14; - oe[offset + 3] = l14 * r11 + l24 * r12 + l34 * r13 + l44 * r14; - - oe[offset + 4] = l11 * r21 + l21 * r22 + l31 * r23 + l41 * r24; - oe[offset + 5] = l12 * r21 + l22 * r22 + l32 * r23 + l42 * r24; - oe[offset + 6] = l13 * r21 + l23 * r22 + l33 * r23 + l43 * r24; - oe[offset + 7] = l14 * r21 + l24 * r22 + l34 * r23 + l44 * r24; - - oe[offset + 8] = l11 * r31 + l21 * r32 + l31 * r33 + l41 * r34; - oe[offset + 9] = l12 * r31 + l22 * r32 + l32 * r33 + l42 * r34; - oe[offset + 10] = l13 * r31 + l23 * r32 + l33 * r33 + l43 * r34; - oe[offset + 11] = l14 * r31 + l24 * r32 + l34 * r33 + l44 * r34; - - oe[offset + 12] = l11 * r41 + l21 * r42 + l31 * r43 + l41 * r44; - oe[offset + 13] = l12 * r41 + l22 * r42 + l32 * r43 + l42 * r44; - oe[offset + 14] = l13 * r41 + l23 * r42 + l33 * r43 + l43 * r44; - oe[offset + 15] = l14 * r41 + l24 * r42 + l34 * r43 + l44 * r44; - } - - /** - * @internal - * Simplify lodash get: https://github.com/lodash/lodash/blob/master/get.js. - * @param target - The object to query. - * @param path - The path of the property to get. - * @returns Returns the resolved value. - */ - static _reflectGet(target: Object, path: string) { - const pathArr = this._stringToPath(path); - - let object = target; - let index = 0; - const length = pathArr.length; - - while (object != null && index < length) { - object = object[pathArr[index++]]; - } - return index && index == length ? object : undefined; - } - /** * Fast remove an element from array. * @param array - Array @@ -127,6 +68,152 @@ export class Utils { return baseUrl.substring(0, baseUrl.lastIndexOf("/") + 1) + this._formatRelativePath(relativeUrl); } + /** + * @internal + */ + static _floatMatrixMultiply(left: Matrix, re: Float32Array, rOffset: number, oe: Float32Array, offset: number): void { + const le = left.elements; + + // prettier-ignore + const l11 = le[0], l12 = le[1], l13 = le[2], l14 = le[3], + l21 = le[4], l22 = le[5], l23 = le[6], l24 = le[7], + l31 = le[8], l32 = le[9], l33 = le[10], l34 = le[11], + l41 = le[12], l42 = le[13], l43 = le[14], l44 = le[15]; + + // prettier-ignore + const r11 = re[rOffset], r12 = re[rOffset + 1], r13 = re[rOffset + 2], r14 = re[rOffset + 3], + r21 = re[rOffset + 4], r22 = re[rOffset + 5], r23 = re[rOffset + 6], r24 = re[rOffset + 7], + r31 = re[rOffset + 8], r32 = re[rOffset + 9], r33 = re[rOffset + 10], r34 = re[rOffset + 11], + r41 = re[rOffset + 12], r42 = re[rOffset + 13], r43 = re[rOffset + 14], r44 = re[rOffset + 15]; + + oe[offset] = l11 * r11 + l21 * r12 + l31 * r13 + l41 * r14; + oe[offset + 1] = l12 * r11 + l22 * r12 + l32 * r13 + l42 * r14; + oe[offset + 2] = l13 * r11 + l23 * r12 + l33 * r13 + l43 * r14; + oe[offset + 3] = l14 * r11 + l24 * r12 + l34 * r13 + l44 * r14; + + oe[offset + 4] = l11 * r21 + l21 * r22 + l31 * r23 + l41 * r24; + oe[offset + 5] = l12 * r21 + l22 * r22 + l32 * r23 + l42 * r24; + oe[offset + 6] = l13 * r21 + l23 * r22 + l33 * r23 + l43 * r24; + oe[offset + 7] = l14 * r21 + l24 * r22 + l34 * r23 + l44 * r24; + + oe[offset + 8] = l11 * r31 + l21 * r32 + l31 * r33 + l41 * r34; + oe[offset + 9] = l12 * r31 + l22 * r32 + l32 * r33 + l42 * r34; + oe[offset + 10] = l13 * r31 + l23 * r32 + l33 * r33 + l43 * r34; + oe[offset + 11] = l14 * r31 + l24 * r32 + l34 * r33 + l44 * r34; + + oe[offset + 12] = l11 * r41 + l21 * r42 + l31 * r43 + l41 * r44; + oe[offset + 13] = l12 * r41 + l22 * r42 + l32 * r43 + l42 * r44; + oe[offset + 14] = l13 * r41 + l23 * r42 + l33 * r43 + l43 * r44; + oe[offset + 15] = l14 * r41 + l24 * r42 + l34 * r43 + l44 * r44; + } + + /** + * @internal + * Simplify lodash get: https://github.com/lodash/lodash/blob/master/get.js. + * @param target - The object to query. + * @param path - The path of the property to get. + * @returns Returns the resolved value. + */ + static _reflectGet(target: Object, path: string) { + const pathArr = this._stringToPath(path); + + let object = target; + let index = 0; + const length = pathArr.length; + + while (object != null && index < length) { + object = object[pathArr[index++]]; + } + return index && index == length ? object : undefined; + } + + /** + * @internal + * @remarks + * Modified based on v8. + * https://github.com/v8/v8/blob/7.2-lkgr/src/js/array.js + */ + static _quickSort(a: T[], from: number, to: number, compareFunc: Function): void { + while (true) { + // Insertion sort is faster for short arrays. + if (to - from <= 10) { + this._insertionSort(a, from, to, compareFunc); + return; + } + const third_index = (from + to) >> 1; + // Find a pivot as the median of first, last and middle element. + let v0 = a[from]; + let v1 = a[to - 1]; + let v2 = a[third_index]; + const c01 = compareFunc(v0, v1); + if (c01 > 0) { + // v1 < v0, so swap them. + const tmp = v0; + v0 = v1; + v1 = tmp; + } // v0 <= v1. + const c02 = compareFunc(v0, v2); + if (c02 >= 0) { + // v2 <= v0 <= v1. + const tmp = v0; + v0 = v2; + v2 = v1; + v1 = tmp; + } else { + // v0 <= v1 && v0 < v2 + const c12 = compareFunc(v1, v2); + if (c12 > 0) { + // v0 <= v2 < v1 + const tmp = v1; + v1 = v2; + v2 = tmp; + } + } + // v0 <= v1 <= v2 + a[from] = v0; + a[to - 1] = v2; + const pivot = v1; + let low_end = from + 1; // Upper bound of elements lower than pivot. + let high_start = to - 1; // Lower bound of elements greater than pivot. + a[third_index] = a[low_end]; + a[low_end] = pivot; + + // From low_end to i are elements equal to pivot. + // From i to high_start are elements that haven't been compared yet. + partition: for (let i = low_end + 1; i < high_start; i++) { + let element = a[i]; + let order = compareFunc(element, pivot); + if (order < 0) { + a[i] = a[low_end]; + a[low_end] = element; + low_end++; + } else if (order > 0) { + do { + high_start--; + if (high_start == i) break partition; + const top_elem = a[high_start]; + order = compareFunc(top_elem, pivot); + } while (order > 0); + a[i] = a[high_start]; + a[high_start] = element; + if (order < 0) { + element = a[i]; + a[i] = a[low_end]; + a[low_end] = element; + low_end++; + } + } + } + if (to - high_start < low_end - from) { + this._quickSort(a, high_start, to, compareFunc); + to = low_end; + } else { + this._quickSort(a, from, low_end, compareFunc); + from = high_start; + } + } + } + private static _stringToPath(string): string[] { const result = []; if (string.charCodeAt(0) === charCodeOfDot) { @@ -156,6 +243,23 @@ export class Utils { }, []) .join("/"); } + + private static _insertionSort(a: T[], from: number, to: number, compareFunc: Function): void { + for (let i = from + 1; i < to; i++) { + let j; + const element = a[i]; + for (j = i - 1; j >= from; j--) { + const tmp = a[j]; + const order = compareFunc(tmp, element); + if (order > 0) { + a[j + 1] = tmp; + } else { + break; + } + } + a[j + 1] = element; + } + } } const charCodeOfDot = ".".charCodeAt(0);