From d0e639cd1c2d8a85ab549a6cbc1a62a74c5e6779 Mon Sep 17 00:00:00 2001 From: Hu Song Date: Fri, 6 May 2022 14:57:39 +0800 Subject: [PATCH 01/33] Test: Use Floss and Chai to Replace Jest (#778) test: Use Floss and Chai to Replace Jest --- .gitignore | 1 + .npmrc | 3 + lerna.json | 3 +- package.json | 16 +- packages/controls/tests/OrthoControl.test.ts | 39 -- packages/core/tests/AssetPromise.test.ts | 96 ---- packages/core/tests/Background.test.ts | 72 --- packages/core/tests/BufferMesh.test.ts | 74 --- packages/core/tests/Camera.test.ts | 233 -------- packages/core/tests/Component.test.ts | 170 ------ packages/core/tests/ComponentsManager.test.ts | 98 ---- packages/core/tests/DisorderedArray.test.ts | 44 -- packages/core/tests/Engine.test.ts | 107 ---- packages/core/tests/Entity.test.ts | 326 ----------- packages/core/tests/EventDispatcher.test.ts | 84 --- packages/core/tests/ModelMesh.test.ts | 245 -------- packages/core/tests/Request.test.ts | 92 --- packages/core/tests/ResourceManager.test.ts | 130 ----- packages/core/tests/Scene.test.ts | 44 -- packages/core/tests/SpriteRenderer.test.ts | 56 -- packages/core/tests/TextRenderer.test.ts | 59 -- packages/core/tests/Transform.test.ts | 535 ------------------ .../core/tests/material/BaseMaterial.test.ts | 79 --- .../tests/material/BlinnPhongMaterial.test.ts | 89 --- .../tests/material/PBRBaseMaterial.test.ts | 83 --- .../core/tests/material/PBRMaterial.test.ts | 45 -- .../material/PBRSpecularMaterial.test.ts | 46 -- .../core/tests/material/UnlitMaterial.test.ts | 43 -- .../core/tests/physics/PhysicsManager.test.ts | 46 -- packages/core/tests/script.test.ts | 278 --------- .../core/tests/texture/RenderTarget.test.ts | 120 ---- packages/core/tests/texture/Texture2D.test.ts | 110 ---- .../core/tests/texture/TextureCubeMap.test.ts | 154 ----- packages/loader/tests/JSONLoader.test.ts | 14 - packages/loader/tests/TextLoader.test.ts | 12 - packages/loader/tests/gltf/Util.test.ts | 20 - packages/loader/tests/gltf/parser.test.ts | 74 --- packages/loader/tests/gltf/test.json | 298 ---------- packages/math/tests/BoundingBox.test.ts | 141 ----- packages/math/tests/BoundingFrustum.test.ts | 94 --- packages/math/tests/BoundingSphere.test.ts | 48 -- packages/math/tests/CollisionUtil.test.ts | 139 ----- packages/math/tests/Color.test.ts | 86 --- packages/math/tests/MathUtil.test.ts | 39 -- packages/math/tests/Matrix.test.ts | 489 ---------------- packages/math/tests/Matrix3x3.test.ts | 259 --------- packages/math/tests/Plane.test.ts | 28 - packages/math/tests/Quaternion.test.ts | 249 -------- packages/math/tests/Ray.test.ts | 37 -- packages/math/tests/Rect.test.ts | 31 - .../math/tests/SphericalHarmonics3.test.ts | 146 ----- packages/math/tests/Vector2.test.ts | 206 ------- packages/math/tests/Vector3.test.ts | 264 --------- packages/math/tests/Vector4.test.ts | 214 ------- packages/oasis-engine/tests/test.js | 5 - packages/rhi-webgl/src/GLTexture.ts | 2 +- packages/rhi-webgl/tests/WebGLEngine.test.ts | 10 - packages/stats/tests/Stats-test.js | 8 - rollup.config.js | 1 + tests/index.ts | 18 + tests/package.json | 25 + tests/src/core/Camera.test.ts | 39 ++ tests/src/rhi-webgl/WebGLEngine.test.ts | 12 + tools/gen-changelog.js | 17 - tools/jest/jest.transform.glsl.js | 9 - tools/jest/jest.transform.ts.js | 32 -- tsconfig.tests.json | 17 + 67 files changed, 129 insertions(+), 6574 deletions(-) create mode 100644 .npmrc delete mode 100644 packages/controls/tests/OrthoControl.test.ts delete mode 100644 packages/core/tests/AssetPromise.test.ts delete mode 100644 packages/core/tests/Background.test.ts delete mode 100644 packages/core/tests/BufferMesh.test.ts delete mode 100644 packages/core/tests/Camera.test.ts delete mode 100644 packages/core/tests/Component.test.ts delete mode 100644 packages/core/tests/ComponentsManager.test.ts delete mode 100644 packages/core/tests/DisorderedArray.test.ts delete mode 100644 packages/core/tests/Engine.test.ts delete mode 100644 packages/core/tests/Entity.test.ts delete mode 100644 packages/core/tests/EventDispatcher.test.ts delete mode 100644 packages/core/tests/ModelMesh.test.ts delete mode 100644 packages/core/tests/Request.test.ts delete mode 100644 packages/core/tests/ResourceManager.test.ts delete mode 100644 packages/core/tests/Scene.test.ts delete mode 100644 packages/core/tests/SpriteRenderer.test.ts delete mode 100644 packages/core/tests/TextRenderer.test.ts delete mode 100644 packages/core/tests/Transform.test.ts delete mode 100644 packages/core/tests/material/BaseMaterial.test.ts delete mode 100644 packages/core/tests/material/BlinnPhongMaterial.test.ts delete mode 100644 packages/core/tests/material/PBRBaseMaterial.test.ts delete mode 100644 packages/core/tests/material/PBRMaterial.test.ts delete mode 100644 packages/core/tests/material/PBRSpecularMaterial.test.ts delete mode 100644 packages/core/tests/material/UnlitMaterial.test.ts delete mode 100644 packages/core/tests/physics/PhysicsManager.test.ts delete mode 100644 packages/core/tests/script.test.ts delete mode 100644 packages/core/tests/texture/RenderTarget.test.ts delete mode 100644 packages/core/tests/texture/Texture2D.test.ts delete mode 100644 packages/core/tests/texture/TextureCubeMap.test.ts delete mode 100644 packages/loader/tests/JSONLoader.test.ts delete mode 100644 packages/loader/tests/TextLoader.test.ts delete mode 100644 packages/loader/tests/gltf/Util.test.ts delete mode 100644 packages/loader/tests/gltf/parser.test.ts delete mode 100644 packages/loader/tests/gltf/test.json delete mode 100644 packages/math/tests/BoundingBox.test.ts delete mode 100644 packages/math/tests/BoundingFrustum.test.ts delete mode 100644 packages/math/tests/BoundingSphere.test.ts delete mode 100644 packages/math/tests/CollisionUtil.test.ts delete mode 100644 packages/math/tests/Color.test.ts delete mode 100644 packages/math/tests/MathUtil.test.ts delete mode 100644 packages/math/tests/Matrix.test.ts delete mode 100644 packages/math/tests/Matrix3x3.test.ts delete mode 100644 packages/math/tests/Plane.test.ts delete mode 100644 packages/math/tests/Quaternion.test.ts delete mode 100644 packages/math/tests/Ray.test.ts delete mode 100644 packages/math/tests/Rect.test.ts delete mode 100644 packages/math/tests/SphericalHarmonics3.test.ts delete mode 100644 packages/math/tests/Vector2.test.ts delete mode 100644 packages/math/tests/Vector3.test.ts delete mode 100644 packages/math/tests/Vector4.test.ts delete mode 100644 packages/oasis-engine/tests/test.js delete mode 100644 packages/rhi-webgl/tests/WebGLEngine.test.ts delete mode 100644 packages/stats/tests/Stats-test.js create mode 100644 tests/index.ts create mode 100644 tests/package.json create mode 100644 tests/src/core/Camera.test.ts create mode 100644 tests/src/rhi-webgl/WebGLEngine.test.ts delete mode 100644 tools/gen-changelog.js delete mode 100644 tools/jest/jest.transform.glsl.js delete mode 100644 tools/jest/jest.transform.ts.js create mode 100644 tsconfig.tests.json diff --git a/.gitignore b/.gitignore index 2ca4e43c3d..4ccc0d663c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ tmp /packages/*/node_modules /packages/*/types /packages/*/doc +/tests/node_modules /playground/node_modules types /packages/*/test/fixtures/**/node_modules diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..326e36628a --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +registry=https://registry.npm.taobao.org +chromedriver_cdnurl=https://npmmirror.com/mirrors/chromedriver/ +electron_mirror=http://npm.taobao.org/mirrors/electron/ \ No newline at end of file diff --git a/lerna.json b/lerna.json index 2d69a2d2ba..24383ebabd 100644 --- a/lerna.json +++ b/lerna.json @@ -5,7 +5,8 @@ "hoist": true }, "packages": [ - "packages/*" + "packages/*", + "tests/**" ], "loglevel": "verbose" } diff --git a/package.json b/package.json index c3e2a6d8f9..583d7403c4 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ ], "scripts": { "bootstrap": "npm i && lerna bootstrap", - "test": "jest", - "test-cov": "jest --coverage", + "test": "cross-env TS_NODE_PROJECT=tsconfig.tests.json floss --path tests -r ts-node/register", + "test-debug": "cross-env TS_NODE_PROJECT=tsconfig.tests.json floss --path tests -r ts-node/register --debug", + "test-cov": "cross-env TS_NODE_PROJECT=tsconfig.tests.json nyc --reporter=lcov floss --path tests -r ts-node/register", "ci": "lerna bootstrap && npm run b:module && npm run b:types && npm run test-cov", "lint": "eslint packages/*/src --ext .ts", "watch": "cross-env NODE_ENV=development BUILD_TYPE=MODULE rollup -cw -m inline", @@ -36,27 +37,30 @@ "@rollup/plugin-inject": "^4.0.2", "@rollup/plugin-node-resolve": "^11.0.1", "@rollup/plugin-replace": "^2.3.4", - "@types/jest": "^26.0.20", + "@types/chai": "^4.3.1", + "@types/mocha": "^8.0.0", "@types/offscreencanvas": "^2019.6.4", "@typescript-eslint/eslint-plugin": "^4.12.0", "@typescript-eslint/parser": "^4.12.0", - "babel-jest": "^26.6.3", "babel-loader": "^8.2.2", + "chai": "^4.3.6", "cross-env": "^5.2.0", + "electron": "^13", "eslint": "^7.17.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-prettier": "^3.1.1", + "floss": "^5.0.1", "husky": "^4.3.7", - "jest": "~24", - "jest-electron": "^0.1.11", "lerna": "^3.22.1", "lint-staged": "^10.5.3", + "nyc": "^15.1.0", "prettier": "^2.2.1", "rollup": "^2.36.1", "rollup-plugin-glslify": "^1.2.0", "rollup-plugin-modify": "^3.0.0", "rollup-plugin-serve": "^1.1.0", "rollup-plugin-terser": "^7.0.2", + "ts-node": "^9.1.1", "typescript": "^4.4.3" }, "husky": { diff --git a/packages/controls/tests/OrthoControl.test.ts b/packages/controls/tests/OrthoControl.test.ts deleted file mode 100644 index 01dddcad55..0000000000 --- a/packages/controls/tests/OrthoControl.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Camera, Entity, WebGLEngine } from "oasis-engine"; -import { OrthoControl } from "../src/OrthoControl"; - -const canvasDOM = document.createElement("canvas"); -canvasDOM.width = 1024; -canvasDOM.height = 1024; - -describe(" Ortho Control", () => { - let entity: Entity; - let camera: Camera; - let cameraControl: OrthoControl; - - beforeAll(() => { - const engine = new WebGLEngine(canvasDOM); - entity = engine.sceneManager.activeScene.createRootEntity(); - camera = entity.addComponent(Camera); - cameraControl = entity.addComponent(OrthoControl); - }); - - it("test zoom", () => { - cameraControl.zoomIn(); - cameraControl.onUpdate(0); - expect(camera.orthographicSize).toEqual(8.749999999999998); - cameraControl.zoomOut(); - cameraControl.onUpdate(0); - expect(camera.orthographicSize).toEqual(10.065789473684207); - }); - - it("test pan", () => { - cameraControl.panStart(0, 0); - cameraControl.panMove(2, 0); - cameraControl.onUpdate(0); - cameraControl.panEnd(); - - const pos = entity.transform.position; - expect(pos.x).toEqual(-0.039319490131578934); - expect(pos.y).toEqual(0); - }); -}); diff --git a/packages/core/tests/AssetPromise.test.ts b/packages/core/tests/AssetPromise.test.ts deleted file mode 100644 index 7188b2f7ab..0000000000 --- a/packages/core/tests/AssetPromise.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { AssetPromise, AssetPromiseStatus } from "../src/asset/AssetPromise"; - -describe("Asset Promise Test", function () { - it("test promise all", () => { - const promises = []; - for (let i = 0; i < 10; i++) { - const promise = new AssetPromise((resolve) => { - setTimeout(() => { - resolve(0); - }, 1000); - }); - promises.push(promise); - } - let out = 0.1; - //@ts-ignore - const allPromise = AssetPromise.all(promises).onProgress((p) => { - expect(p).toBeCloseTo(out); - out += 0.1; - }); - return expect( - allPromise.then((res) => { - expect(allPromise.status).toEqual(AssetPromiseStatus.Success); - expect(allPromise.progress).toEqual(1); - return res; - }) - ).resolves.toEqual([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - }); - - it("promise all rejected", () => { - const promises = []; - for (let i = 0; i < 10; i++) { - const promise = new AssetPromise((resolve) => { - setTimeout(() => { - resolve(0); - }, 1000); - }); - promises.push(promise); - } - setTimeout(() => { - promises[0].cancel(); - }, 500); - // @ts-ignore - return expect(AssetPromise.all(promises)).rejects.toEqual("Promise Canceled"); - }); - - it("test promise cancel", () => { - const promise = new AssetPromise((resolve) => { - setTimeout(() => { - resolve(0); - }, 2000); - }); - return expect(promise.cancel()).rejects.toEqual("Promise Canceled"); - }); - - it("test promise cancel resolved", () => { - const promise = new AssetPromise((resolve) => { - resolve(0); - }); - return expect( - promise.then((res) => { - promise.cancel(); - return res; - }) - ).resolves.toEqual(0); - }); - - it("test promise reject", () => { - const promise = new AssetPromise((resolve, reject) => { - reject("test"); - }); - return expect( - promise.catch((e) => { - expect(promise.status).toEqual(AssetPromiseStatus.Failed); - throw e; - }) - ).rejects.toEqual("test"); - }); - - it("test multi promise reject", () => { - const promise = new AssetPromise((resolve, reject) => { - setTimeout(() => { - reject("test"); - }); - }); - promise.catch((e) => { - return e; - }); - const promise1 = new AssetPromise((resolve, reject) => { - setTimeout(() => { - resolve("test 1"); - }, 1000); - }); - - return expect(promise).rejects.toEqual("test"); - }); -}); diff --git a/packages/core/tests/Background.test.ts b/packages/core/tests/Background.test.ts deleted file mode 100644 index 9bcca7c53f..0000000000 --- a/packages/core/tests/Background.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { WebCanvas } from "../../rhi-webgl/src/WebCanvas"; -import { WebGLRenderer } from "../../rhi-webgl/src/WebGLRenderer"; -import { Engine } from "../src/Engine"; -import { BackgroundTextureFillMode } from "../src/enums/BackgroundTextureFillMode"; -import { Texture2D } from "../src/texture/Texture2D"; - -describe("Background Test", function () { - const hardwareRenderer = new WebGLRenderer(); - const canvas = new WebCanvas(document.createElement("canvas")); - canvas.width = 100; - canvas.height = 100; - const engine = new Engine(canvas, hardwareRenderer); - const scene = engine.sceneManager.activeScene; - it("set texture should be success", () => { - const texture = new Texture2D(engine, 50, 100); - scene.background._resizeBackgroundTexture(); - scene.background.texture = texture; - expect(scene.background.texture).toEqual(texture); - scene.background.texture = texture; - expect(scene.background.texture).toEqual(texture); - expect(scene.background.textureFillMode).toEqual(BackgroundTextureFillMode.AspectFitHeight); - scene.background.textureFillMode = BackgroundTextureFillMode.AspectFitHeight; - expect(scene.background.textureFillMode).toEqual(BackgroundTextureFillMode.AspectFitHeight); - }); - it("set texture fill should be success", () => { - scene.background.textureFillMode = BackgroundTextureFillMode.Fill; - const positions = scene.background._mesh.getPositions(); - expect(positions[0].x).toBeCloseTo(-1); - expect(positions[0].y).toBeCloseTo(-1); - - expect(positions[1].x).toBeCloseTo(1); - expect(positions[1].y).toBeCloseTo(-1); - - expect(positions[2].x).toBeCloseTo(-1); - expect(positions[2].y).toBeCloseTo(1); - - expect(positions[3].x).toBeCloseTo(1); - expect(positions[3].y).toBeCloseTo(1); - }); - - it("set texture fill should be success", () => { - scene.background.textureFillMode = BackgroundTextureFillMode.AspectFitHeight; - const positions = scene.background._mesh.getPositions(); - expect(positions[0].x).toBeCloseTo(-0.5); - expect(positions[0].y).toBeCloseTo(-1); - - expect(positions[1].x).toBeCloseTo(0.5); - expect(positions[1].y).toBeCloseTo(-1); - - expect(positions[2].x).toBeCloseTo(-0.5); - expect(positions[2].y).toBeCloseTo(1); - - expect(positions[3].x).toBeCloseTo(0.5); - expect(positions[3].y).toBeCloseTo(1); - }); - - it("set texture fill should be success", () => { - scene.background.textureFillMode = BackgroundTextureFillMode.AspectFitWidth; - const positions = scene.background._mesh.getPositions(); - expect(positions[0].x).toBeCloseTo(-1); - expect(positions[0].y).toBeCloseTo(-2); - - expect(positions[1].x).toBeCloseTo(1); - expect(positions[1].y).toBeCloseTo(-2); - - expect(positions[2].x).toBeCloseTo(-1); - expect(positions[2].y).toBeCloseTo(2); - - expect(positions[3].x).toBeCloseTo(1); - expect(positions[3].y).toBeCloseTo(2); - }); -}); diff --git a/packages/core/tests/BufferMesh.test.ts b/packages/core/tests/BufferMesh.test.ts deleted file mode 100644 index 97a76c7c05..0000000000 --- a/packages/core/tests/BufferMesh.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Engine } from "../src"; -import { WebGLRenderer, WebCanvas } from "../../rhi-webgl"; -import { IndexFormat } from "../src"; -import { BufferMesh } from "../src/mesh/BufferMesh"; -import { - Buffer, - BufferBindFlag, - BufferUsage, - IndexBufferBinding, - VertexElement, - VertexElementFormat, - VertexBufferBinding -} from "../src/graphic"; - -describe("BufferMesh Test", function () { - const hardwareRenderer = new WebGLRenderer(); - const canvas = new WebCanvas(document.createElement("canvas")); - const engine = new Engine(canvas, hardwareRenderer); - it("setVertexElements", () => { - const vertexElements = [ - new VertexElement("a_position", 0, VertexElementFormat.Vector3, 0), - new VertexElement("a_velocity", 12, VertexElementFormat.Vector3, 0), - new VertexElement("a_acceleration", 24, VertexElementFormat.Vector3, 0), - new VertexElement("a_color", 36, VertexElementFormat.Vector4, 0), - new VertexElement("a_lifeAndSize", 52, VertexElementFormat.Vector4, 0), - new VertexElement("a_rotation", 68, VertexElementFormat.Vector2, 0), - new VertexElement("a_uv", 76, VertexElementFormat.Vector3, 0), - new VertexElement("a_normalizedUv", 88, VertexElementFormat.Vector2, 0) - ]; - const bufferMesh = new BufferMesh(engine); - bufferMesh.setVertexElements(vertexElements); - expect(bufferMesh.vertexElements.length).toBe(8); - }); - - it("setVertexBufferBinding", () => { - const bufferMesh1 = new BufferMesh(engine); - const bufferMesh2 = new BufferMesh(engine); - const bufferMesh3 = new BufferMesh(engine); - - const vertexBuffer = new Buffer(engine, BufferBindFlag.VertexBuffer, 600, BufferUsage.Dynamic); - bufferMesh1.setVertexBufferBinding(vertexBuffer, 666); - expect(bufferMesh1.vertexBufferBindings[0].stride).toBe(666); - - const bb = new VertexBufferBinding(vertexBuffer, 666); - bufferMesh2.setVertexBufferBinding(bb); - expect(bufferMesh2.vertexBufferBindings[0].stride).toBe(666); - - bufferMesh3.setVertexBufferBinding(vertexBuffer, 666, 5); - expect(bufferMesh3.vertexBufferBindings[5].stride).toBe(666); - expect(bufferMesh3.vertexBufferBindings.length).toBe(6); - }); - - it("setVertexBufferBindings", () => { - const bufferMesh = new BufferMesh(engine); - const vertexBuffer = new Buffer(engine, BufferBindFlag.VertexBuffer, 600, BufferUsage.Dynamic); - - const vb1 = new VertexBufferBinding(vertexBuffer, 666); - const vb2 = new VertexBufferBinding(vertexBuffer, 555); - bufferMesh.setVertexBufferBindings([vb1, vb2], 2); - expect(bufferMesh.vertexBufferBindings[3].stride).toBe(555); - }); - - it("setIndexBufferBinding", () => { - const bufferMesh1 = new BufferMesh(engine); - const bufferMesh2 = new BufferMesh(engine); - const indexBuffer = new Buffer(engine, BufferBindFlag.IndexBuffer, 120, BufferUsage.Dynamic); - const ib = new IndexBufferBinding(indexBuffer, IndexFormat.UInt16); - bufferMesh1.setIndexBufferBinding(indexBuffer, IndexFormat.UInt16); - bufferMesh2.setIndexBufferBinding(ib); - - expect(bufferMesh1.indexBufferBinding.buffer).toBe(indexBuffer); - expect(bufferMesh2.indexBufferBinding.buffer).toBe(indexBuffer); - }); -}); diff --git a/packages/core/tests/Camera.test.ts b/packages/core/tests/Camera.test.ts deleted file mode 100644 index a4e83a2ad4..0000000000 --- a/packages/core/tests/Camera.test.ts +++ /dev/null @@ -1,233 +0,0 @@ -// @ts-nocheck -import { MathUtil, Matrix, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; -import { WebGLEngine } from "../../rhi-webgl/src"; -import { Camera } from "../src/Camera"; -import { Entity } from "../src/Entity"; - -const canvasDOM = document.createElement("canvas"); -canvasDOM.width = 1024; -canvasDOM.height = 1024; - -describe("camera test", function () { - let node: Entity; - let camera: Camera; - let identityMatrix: Matrix; - beforeAll(() => { - const engine = new WebGLEngine(canvasDOM); - node = engine.sceneManager.activeScene.createRootEntity(); - camera = node.addComponent(Camera); - // camera._onAwake(); - identityMatrix = new Matrix(); - }); - - it("constructor", () => { - expect(camera.aspectRatio).toEqual(1); - expect(camera._renderPipeline).not.toBeUndefined(); - expect(camera.entity.transform.worldPosition).not.toBeUndefined(); - vector4CloseTo(camera.viewport, new Vector4(0, 0, 1, 1)); - expect(camera.fieldOfView).toEqual(45); - expect(camera.isOrthographic).toEqual(false); - }); - - it("camera awake without transform", () => { - // const testNode = node.createChild("testNode"); - // const transform = testNode.getComponent(Transform); - // transform.destroy(); - // expect(() => { - // const camera = testNode.addComponent(Camera); - // }).toThrow(); - // const newTransform = testNode.addComponent(Transform); - // testNode.addComponent(Camera); - // expect(() => { - // newTransform.destroy(); - // }).toThrow(); - }); - - it("perspective calculate", () => { - camera.viewport = new Vector4(0, 0, 1, 1); - camera.fieldOfView = 45; - camera.nearClipPlane = 10; - camera.farClipPlane = 100; - const projectionMatrix = camera.projectionMatrix; - const result = new Matrix(); - Matrix.perspective(MathUtil.degreeToRadian(45), 400 / 400, 10, 100, result); - expect(projectionMatrix).toEqual(result); - }); - - it("custom projection", () => { - camera.projectionMatrix = new Matrix(); - camera.fieldOfView = 60; - expect(camera.projectionMatrix).toEqual(identityMatrix); - }); - - it("reset perspective", () => { - camera.resetProjectionMatrix(); - camera.viewport = new Vector4(0, 0, 1, 1); - camera.fieldOfView = 60; - camera.nearClipPlane = 10; - camera.farClipPlane = 100; - const result = new Matrix(); - Matrix.perspective(MathUtil.degreeToRadian(60), 400 / 400, 10, 100, result); - expect(camera.projectionMatrix).toEqual(result); - }); - - it("orth calculate", () => { - camera.orthographicSize = 5; - camera.isOrthographic = true; - const projectionMatrix = camera.projectionMatrix; - const width = (camera.orthographicSize * 400) / 400; - const height = camera.orthographicSize; - const result = new Matrix(); - Matrix.ortho(-width, width, -height, height, camera.nearClipPlane, camera.farClipPlane, result); - expect(projectionMatrix).toEqual(result); - }); - - it("orth setting", () => { - camera.projectionMatrix = new Matrix(); - expect(camera.projectionMatrix).toEqual(identityMatrix); - }); - - it("do not trigger dirty", () => { - camera.resetProjectionMatrix(); - camera.orthographicSize = 5; - // trigger calculate - camera.projectionMatrix; - //@ts-ignore - camera._orthographicSize = 4; - const width = (camera.orthographicSize * 400) / 400; - const height = camera.orthographicSize; - const result = new Matrix(); - Matrix.ortho(-width, width, -height, height, camera.nearClipPlane, camera.farClipPlane, result); - expect(camera.projectionMatrix).not.toEqual(result); - }); - - it("screen to viewport point", () => { - camera.viewport = new Vector4(0.5, 0.5, 0.5, 0.5); - const out = camera.screenToViewportPoint(new Vector2(512, 512), new Vector2()); - expect(out.x).toBeCloseTo(0); - expect(out.y).toBeCloseTo(0); - }); - - it("viewport to screen point", () => { - camera.viewport = new Vector4(0.5, 0.5, 0.5, 0.5); - const out = camera.viewportToScreenPoint(new Vector2(0.5, 0.5), new Vector2()); - expect(out.x).toBeCloseTo(1024 * 0.75); - expect(out.y).toBeCloseTo(1024 * 0.75); - }); - - it("world to viewport", () => { - camera.projectionMatrix = new Matrix( - 3.0807323455810547, - 0, - 0, - 0, - 0, - 1.7320458889007568, - 0, - 0, - 0, - 0, - -1.001001000404358, - -1, - 0, - 0, - -0.10010010004043579, - 0 - ); - camera.entity.transform.worldMatrix = new Matrix(); - const out = camera.worldToViewportPoint(new Vector3(1, 1, -100), new Vector3()); - vector3CloseTo(out, new Vector3(0.5154036617279053, 0.4913397705554962, 100)); - }); - - it("viewport to world", () => { - camera.projectionMatrix = new Matrix( - 3.0807323455810547, - 0, - 0, - 0, - 0, - 1.7320458889007568, - 0, - 0, - 0, - 0, - -1.001001000404358, - -1, - 0, - 0, - -0.10010010004043579, - 0 - ); - camera.entity.transform.worldMatrix = new Matrix(); - const out = camera.viewportToWorldPoint(new Vector3(0.5154036617279053, 0.4913397705554962, 100), new Vector3()); - arrayCloseTo([1, 1, -100], [out.x, out.y, out.z]); - }); - - it("viewportToRay", () => { - const mat = new Matrix( - -1, - 0, - 0, - 0, - 0, - 0.9593654870986938, - -0.28216633200645447, - 0, - 0, - -0.28216633200645447, - -0.9593654870986938, - 0, - 0, - 5, - 17, - 1 - ); - camera.entity.transform.worldMatrix = mat; - const ray = camera.viewportPointToRay(new Vector2(0.4472140669822693, 0.4436090290546417), new Ray()); - arrayCloseTo( - [ray.origin.x, ray.origin.y, ray.origin.z], - Float32Array.from([0.0017142786925635912, 5.017240249493299, 17.047073454417177]) - ); - arrayCloseTo( - [ray.direction.x, ray.direction.y, ray.direction.z], - Float32Array.from([0.034176195559507606, 0.3437087947548518, 0.9384541821875192]) - ); - }); - - it("test near clip plane and far clip plane", () => { - camera.entity.transform.worldMatrix = new Matrix(); - camera.nearClipPlane = 10; - camera.farClipPlane = 100; - camera.resetProjectionMatrix(); - const nearClipPoint = camera.viewportToWorldPoint(new Vector3(0.5, 0.5, camera.nearClipPlane), new Vector3()); - const farClipPoint = camera.viewportToWorldPoint(new Vector3(0.5, 0.5, camera.farClipPlane), new Vector3()); - expect(nearClipPoint.z).toBeCloseTo(-camera.nearClipPlane); - expect(farClipPoint.z).toBeCloseTo(-camera.farClipPlane); - }); - - it("todo implementation", () => { - camera.enableHDR = true; - expect(camera.enableHDR).toBeFalsy(); - }); -}); - -function arrayCloseTo(arr1: ArrayLike, arr2: ArrayLike) { - const len = arr1.length; - expect(len).toEqual(arr2.length); - for (let i = 0; i < len; i++) { - expect(arr1[i]).toBeCloseTo(arr2[i]); - } -} - -function vector3CloseTo(vec1: Vector3, vec2: Vector3): void { - expect(vec1.x).toBeCloseTo(vec2.x); - expect(vec1.y).toBeCloseTo(vec2.y); - expect(vec1.z).toBeCloseTo(vec2.z); -} - -function vector4CloseTo(vec1: Vector4, vec2: Vector4): void { - expect(vec1.x).toBeCloseTo(vec2.x); - expect(vec1.y).toBeCloseTo(vec2.y); - expect(vec1.z).toBeCloseTo(vec2.z); - expect(vec1.w).toBeCloseTo(vec2.w); -} diff --git a/packages/core/tests/Component.test.ts b/packages/core/tests/Component.test.ts deleted file mode 100644 index dfc99c763f..0000000000 --- a/packages/core/tests/Component.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; -import { Entity, Component, Engine, Scene } from "../src/index"; - -class TestComponent extends Component {} - -describe("Component", () => { - const getContext = jest.fn().mockReturnValue({ - canvas: { width: 1024, height: 1024 }, - getParameter: jest.fn(), - enable: jest.fn(), - disable: jest.fn(), - colorMask: jest.fn(), - depthMask: jest.fn(), - blendFunc: jest.fn(), - cullFace: jest.fn(), - frontFace: jest.fn(), - depthFunc: jest.fn(), - depthRange: jest.fn(), - polygonOffset: jest.fn(), - stencilFunc: jest.fn(), - stencilMask: jest.fn(), - getExtension: jest.fn(), - bindFramebuffer: jest.fn(), - viewport: jest.fn(), - clearColor: jest.fn(), - clear: jest.fn() - }); - - const canvasDOM = document.createElement("canvas"); - canvasDOM.getContext = getContext; - - const engine = new WebGLEngine(document.createElement("canvas")); - const scene = engine.sceneManager.activeScene; - const root = new Entity(engine, "root"); - //@ts-ignore - scene.addRootEntity(root); - engine.run(); - beforeEach(() => { - }); - - describe("enabled", () => { - it("enabled", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - TestComponent.prototype._onEnable = jest.fn(); - const component = entity.addComponent(TestComponent); - expect(component.enabled).toBeTruthy(); - expect(component._onEnable).toHaveBeenCalledTimes(1); - }); - - it("disabled", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - TestComponent.prototype._onDisable = jest.fn(); - const component = entity.addComponent(TestComponent); - component.enabled = false; - expect(component.enabled).toBeFalsy(); - expect(component._onDisable).toHaveBeenCalledTimes(1); - }); - - it("not trigger", () => { - const parent = new Entity(engine, "parent"); - //@ts-ignore - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.isActive = false; - TestComponent.prototype._onEnable = jest.fn(); - TestComponent.prototype._onDisable = jest.fn(); - const component = child.addComponent(TestComponent); - component.enabled = true; - expect(component._onEnable).toHaveBeenCalledTimes(0); - component.enabled = false; - expect(component._onDisable).toHaveBeenCalledTimes(0); - }); - }); - - describe("entity scene", () => { - it("entity", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - const component = entity.addComponent(TestComponent); - expect(component.entity).toBe(entity); - }); - - it("scene", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - const component = entity.addComponent(TestComponent); - expect(component.scene).toBe(scene); - }); - }); - - describe("destroy", () => { - it("normal", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - TestComponent.prototype._onDisable = jest.fn(); - TestComponent.prototype._onDestroy = jest.fn(); - const component = entity.addComponent(TestComponent); - component.destroy(); - expect(component._onDisable).toHaveBeenCalledTimes(1); - expect(component._onDestroy).toHaveBeenCalledTimes(1); - }); - }); - - describe("awake", () => { - it("normal", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - TestComponent.prototype._onAwake = jest.fn(); - const component = entity.addComponent(TestComponent); - expect(component._onAwake).toHaveBeenCalledTimes(1); - }); - - it("entity changeActive", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - entity.isActive = false; - TestComponent.prototype._onAwake = jest.fn(); - const component = entity.addComponent(TestComponent); - expect(component._onAwake).toHaveBeenCalledTimes(0); - entity.isActive = true; - expect(component._onAwake).toHaveBeenCalledTimes(1); - entity.isActive = false; - entity.isActive = true; - expect(component._onAwake).toHaveBeenCalledTimes(1); - }); - }); - - describe("active", () => { - it("onEnable", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - TestComponent.prototype._onEnable = jest.fn(); - const component = entity.addComponent(TestComponent); - expect(component._onEnable).toHaveBeenCalledTimes(1); - }); - - it("onDisable", () => { - const entity = new Entity(engine, "entity"); - //@ts-ignore - entity.parent = scene.getRootEntity(); - TestComponent.prototype._onDisable = jest.fn(); - const component = entity.addComponent(TestComponent); - entity.isActive = false; - expect(component._onDisable).toHaveBeenCalledTimes(1); - }); - - it("inActiveHierarchy", () => { - const parent = new Entity(engine, "parent"); - //@ts-ignore - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - TestComponent.prototype._onDisable = jest.fn(); - const component = child.addComponent(TestComponent); - parent.isActive = false; - expect(component._onDisable).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/packages/core/tests/ComponentsManager.test.ts b/packages/core/tests/ComponentsManager.test.ts deleted file mode 100644 index 8c86b80292..0000000000 --- a/packages/core/tests/ComponentsManager.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -// @ts-nocheck -import { WebGLEngine } from "../../rhi-webgl/src"; -import { Camera } from "../src/Camera"; -import { Engine, Entity, Renderer, Script } from "../src/index"; -import { RenderContext } from "../src/RenderPipeline/RenderContext"; -const canvasDOM = document.createElement("canvas"); - -describe("ComponentsManager", () => { - let engine: WebGLEngine = new WebGLEngine(canvasDOM); - let scene; - let camera: Camera; - let rootNode: Entity; - beforeEach(() => { - scene = engine.sceneManager.activeScene; - rootNode = engine.sceneManager.activeScene.createRootEntity(); - camera = rootNode.addComponent(Camera); - engine.sceneManager.activeScene = scene; - }); - - describe("Component", () => { - class TestComponent extends Script { - onUpdate() {} - } - it("onUpdate", () => { - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TestComponent.prototype.onUpdate = jest.fn(); - const component = entity.addComponent(TestComponent); - engine.update(); - engine.update(); - expect(component.onUpdate).toHaveBeenCalledTimes(2); - }); - // TODO 这条没过有问题 - // it("inActive", () => { - // const entity = new Entity(engine, "entity"); - // entity.parent = scene.getRootEntity(); - // TestComponent.prototype.onUpdate = jest.fn(); - // const component = entity.addComponent(TestComponent); - // entity.isActive = false; - // engine.update(); - // engine.update(); - // expect(component.onUpdate).toHaveBeenCalledTimes(0); - // }); - }); - - describe("Renderer", () => { - it("onUpdate", () => { - class TestComponent extends Renderer { - update() {} - _render() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TestComponent.prototype.update = jest.fn(); - const component = entity.addComponent(TestComponent); - engine._componentsManager.callScriptOnStart(); - engine._componentsManager.callRendererOnUpdate(16.7); - engine._componentsManager.callScriptOnStart(); - engine._componentsManager.callRendererOnUpdate(16.7); - expect(component.update).toHaveBeenCalledTimes(2); - }); - - it("render", () => { - class TestComponent extends Renderer { - update() {} - _render() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TestComponent.prototype._render = jest.fn(); - const component = entity.addComponent(TestComponent); - engine._renderContext._camera = camera; - engine._componentsManager.callScriptOnStart(); - engine._componentsManager.callRender(engine._renderContext); - engine._componentsManager.callScriptOnStart(); - engine._componentsManager.callRender(engine._renderContext); - expect(component._render).toHaveBeenCalledTimes(2); - }); - - it("inActive", () => { - class TestComponent extends Renderer { - update() {} - _render() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TestComponent.prototype.update = jest.fn(); - TestComponent.prototype._render = jest.fn(); - const component = entity.addComponent(TestComponent); - entity.isActive = false; - engine._componentsManager.callRendererOnUpdate(16.7); - engine._renderContext._camera = camera; - engine._componentsManager.callRender(engine._renderContext); - expect(component.update).toHaveBeenCalledTimes(0); - expect(component._render).toHaveBeenCalledTimes(0); - }); - }); -}); diff --git a/packages/core/tests/DisorderedArray.test.ts b/packages/core/tests/DisorderedArray.test.ts deleted file mode 100644 index 8275d8cb19..0000000000 --- a/packages/core/tests/DisorderedArray.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { DisorderedArray } from "../src/DisorderedArray"; - -describe("DisorderedArray", () => { - it("add", () => { - const array = new DisorderedArray(); - array.add("test1"); - array.add("test2"); - expect(array.length).toEqual(2); - }); - - it("add&delete", () => { - const array = new DisorderedArray(); - array.add("test1"); - array.delete("test1"); - array.add("test2"); - expect(array.length).toEqual(1); - }); - - it("delete", () => { - const array = new DisorderedArray(); - array.add("test1"); - array.add("test2"); - array.delete("test1"); - expect(array.length).toEqual(1); - }); - - it("deleteByIndex", () => { - const array = new DisorderedArray(); - array.add("test1"); - array.add("test2"); - array.deleteByIndex(0); - expect(array.length).toEqual(1); - }); - - it("garbageCollection", () => { - const array = new DisorderedArray(); - array.add("test1"); - array.add("test2"); - array.deleteByIndex(0); - expect(array._elements.length).toEqual(2); - array.garbageCollection(); - expect(array._elements.length).toEqual(1); - }); -}); diff --git a/packages/core/tests/Engine.test.ts b/packages/core/tests/Engine.test.ts deleted file mode 100644 index 6b12ba81ed..0000000000 --- a/packages/core/tests/Engine.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { WebCanvas, WebGLEngine, WebGLRenderer } from "../../rhi-webgl/src"; -import { Engine } from "../src"; - -describe("Engine test", () => { - describe("test - create and destroy engine ", () => { - it("use Engine", () => { - const canvas = new WebCanvas(document.createElement("canvas")); - const rhi = new WebGLRenderer(); - const engine = new Engine(canvas, rhi); - - expect(engine.canvas).toBe(canvas); - expect(engine._hardwareRenderer).toBe(rhi); - }); - - it("Use WebGLEngine", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - - expect(engine._hardwareRenderer).toBeInstanceOf(WebGLRenderer); - }); - - it("Use offscreen canvas", () => { - const canvas = new WebCanvas(new OffscreenCanvas(1024, 1024)); - const rhi = new WebGLRenderer(); - const engine = new Engine(canvas, rhi); - - expect(engine.canvas).toBe(canvas); - expect(engine._hardwareRenderer).toBeInstanceOf(WebGLRenderer); - expect(canvas.width).toBe(1024); - expect(canvas.height).toBe(1024); - }); - - it("Destroy engine", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - - engine.destroy(); - expect(engine.sceneManager).toBeNull(); - expect(engine.isPaused).toBeTruthy(); - }); - }); - - describe("test - sceneManager", () => { - it("Default scene", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - - expect(engine.sceneManager.activeScene).not.toBeNull(); - }); - it("Destroy scene", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const scene = engine.sceneManager.activeScene; - scene.destroy(); - - expect(engine.sceneManager.activeScene).toBeNull(); - }); - }); - - describe("test - tick/vSync", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const mockTick = (engine.update = jest.fn()); - - it("Open vsync - pause/resume", () => { - mockTick.mockReset(); - engine.run(); - - setTimeout(() => { - expect(mockTick).toBeCalled(); - engine.pause(); - mockTick.mockReset(); - setTimeout(() => { - expect(mockTick).not.toBeCalled(); - expect(engine.isPaused).toBeTruthy(); - mockTick.mockReset(); - engine.resume(); - setTimeout(() => { - expect(mockTick).toBeCalled(); - expect(engine.isPaused).toBeFalsy(); - }, 100); - }, 100); - }, 100); - }); - - it("Close vsync", () => { - mockTick.mockReset(); - engine.vSyncCount = 0; - engine.targetFrameRate = 50; // 1000 / 50 = 20 ms - setTimeout(() => { - // run at least 4 times in 50 fps, - expect(engine.vSyncCount).toBe(0); - expect(engine.targetFrameRate).toBe(50); - expect(mockTick).not.toBeCalledTimes(0); - expect(mockTick).not.toBeCalledTimes(1); - expect(mockTick).not.toBeCalledTimes(2); - expect(mockTick).not.toBeCalledTimes(3); - - mockTick.mockReset(); - engine.targetFrameRate = 10; // 1000 / 10 = 100 ms - - setTimeout(() => { - // run at most 1 time in 10 fps - expect(engine.vSyncCount).toBe(0); - expect(engine.targetFrameRate).toBe(10); - expect(mockTick).not.toBeCalledTimes(2); - expect(mockTick).not.toBeCalledTimes(3); - }, 100); - }, 100); - }); - }); -}); diff --git a/packages/core/tests/Entity.test.ts b/packages/core/tests/Entity.test.ts deleted file mode 100644 index 6f0a13a816..0000000000 --- a/packages/core/tests/Entity.test.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; -import { Component } from "../src/Component"; -import { Entity } from "../src/Entity"; -class TestComponent extends Component {} - -describe("Entity", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const scene = engine.sceneManager.activeScene; - engine.run(); - beforeEach(() => { - scene.createRootEntity("root"); - }); - - describe("scene.findByPath", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - - expect(scene.findEntityByPath("root/parent")).toBe(parent); - - expect(scene.findEntityByPath("root/parent/child")).toBe(child); - }); - it("not found", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - - expect(scene.findEntityByPath("child")).toEqual(null); - - expect(scene.findEntityByPath("parent/test")).toEqual(null); - }); - }); - - describe("isActive", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.isActive = false; - child.isActive = true; - expect(parent.isActive).toBeFalsy(); - expect(child.isActive).toBeTruthy(); - }); - }); - - describe("isActiveInHierarchy", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.isActive = true; - child.isActive = true; - expect(parent.isActiveInHierarchy).toBeTruthy(); - expect(child.isActiveInHierarchy).toBeTruthy(); - }); - - it("child false", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.isActive = true; - child.isActive = false; - expect(parent.isActiveInHierarchy).toBeTruthy(); - expect(child.isActiveInHierarchy).toBeFalsy(); - }); - - it("parent false", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.isActive = false; - child.isActive = true; - expect(parent.isActiveInHierarchy).toBeFalsy(); - expect(child.isActiveInHierarchy).toBeFalsy(); - }); - }); - - describe("parent", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - child.parent = parent; - expect(child.parent).toBe(parent); - }); - - it("null", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - child.parent = null; - expect(child.parent).toBe(null); - }); - - it("change", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const parent2 = new Entity(engine, "parent"); - - parent2.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - child.parent = parent2; - expect(child.parent).toBe(parent2); - }); - }); - - describe("childCount", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - expect(parent.childCount).toEqual(1); - }); - - it("null", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - child.parent = null; - expect(parent.childCount).toEqual(0); - }); - - it("change", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const parent2 = new Entity(engine, "parent"); - - parent2.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - child.parent = parent2; - expect(parent2.childCount).toEqual(1); - expect(parent.childCount).toEqual(0); - }); - }); - - describe("scene", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - expect(parent.scene).toBe(scene); - expect(child.scene).toBe(scene); - }); - - it("change parent", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - expect(parent.scene).toBe(scene); - expect(child.scene).toBe(scene); - }); - }); - - describe("scene", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - expect(child.scene).toBe(scene); - }); - - it("change parent", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - expect(parent.scene).toBe(scene); - expect(child.scene).toBe(scene); - }); - }); - - describe("component", () => { - it("addComponent getComponent", () => { - const entity = new Entity(engine, "entity"); - - entity.parent = scene.getRootEntity(); - const component = entity.addComponent(TestComponent); - expect(entity.getComponent(TestComponent)).toBe(component); - }); - - it("addComponent getComponents", () => { - const entity = new Entity(engine, "entity"); - - entity.parent = scene.getRootEntity(); - const component = entity.addComponent(TestComponent); - const res = []; - entity.getComponents(TestComponent, res); - expect(res[0]).toBe(component); - }); - }); - - describe("child", () => { - it("addChild", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.addChild(child); - expect(child.parent).toBe(parent); - expect(child.scene).toBe(scene); - }); - - it("removeChild", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.removeChild(child); - expect(child.parent).toEqual(null); - expect(child.scene).toEqual(null); - }); - - it("getChild", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - const theChild = parent.getChild(0); - expect(theChild).toBe(child); - }); - - it("getChild", () => { - const parent = new Entity(engine, "parent"); - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - const theChild = parent.getChild(0); - expect(theChild).toBe(child); - }); - - it("findByName", () => { - const parent = new Entity(engine, "parent"); - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - const child2 = new Entity(engine, "child2"); - child2.parent = parent; - expect(parent.findByName("child")).toBe(child); - expect(parent.findByName("child2")).toBe(child2); - }); - - it("findByPath", () => { - const parent = new Entity(engine, "parent"); - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - const child2 = new Entity(engine, "child2"); - child2.parent = parent; - expect(parent.findByPath("/child")).toBe(child); - expect(parent.findByPath("child2")).toBe(child2); - }); - - it("clearChildren", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - const child2 = new Entity(engine, "child2"); - child2.parent = parent; - parent.clearChildren(); - expect(parent.childCount).toEqual(0); - }); - }); - - describe("clone", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - const cloneParent = parent.clone(); - expect(cloneParent.childCount).toEqual(parent.childCount); - expect(cloneParent.findByName("child").name).toEqual(child.name); - expect(cloneParent.findByName("child")).toBe(cloneParent.getChild(0)); - }); - }); - - describe("destroy", () => { - it("normal", () => { - const parent = new Entity(engine, "parent"); - - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - child.destroy(); - expect(parent.childCount).toEqual(0); - }); - }); -}); diff --git a/packages/core/tests/EventDispatcher.test.ts b/packages/core/tests/EventDispatcher.test.ts deleted file mode 100644 index 00cf028340..0000000000 --- a/packages/core/tests/EventDispatcher.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { EventDispatcher } from "../src/base"; - -function getEventNames(e: EventDispatcher) { - // @ts-ignore - if (e._evtCount === 0) return []; - // @ts-ignore - return Object.keys(e._evts); -} - -function getListenerCount(e: EventDispatcher) {} - -describe("EventDispatcher Test", function () { - it("create EventDispatcher", () => { - const eventDispatcher = new EventDispatcher(null); - expect(eventDispatcher.instanceId).not.toBeNull(); - }); - - it("test addEventListener", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.on("test", () => {}); - expect(eventDispatcher.hasEvent("test")).toBeTruthy(); - eventDispatcher.removeEventListener("test"); - expect(eventDispatcher.hasEvent("test")).toBeFalsy(); - }); - - it("test once", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.once("test", () => {}); - expect(eventDispatcher.hasEvent("test")).toBeTruthy(); - eventDispatcher.dispatch("test"); - expect(eventDispatcher.hasEvent("test")).toBeFalsy(); - }); - - it("test callback", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.on("test", (param) => { - expect(param).toEqual("test"); - }); - eventDispatcher.dispatch("test", "test"); - }); - - it("test multi callback", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.on("test", (param) => { - expect(param).toEqual("test"); - }); - eventDispatcher.on("test", (param) => { - expect(param).toEqual("test"); - }); - eventDispatcher.dispatch("test", "test"); - }); - - it("listenerCount", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.on("test", (param) => { - expect(param).toEqual("test"); - }); - expect(eventDispatcher.listenerCount("test") === 1).toBeTruthy(); - }); - - it("listenerCount eventNames", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.on("test", (param) => { - expect(param).toEqual("test"); - }); - expect(eventDispatcher.listenerCount("test") === 1).toBeTruthy(); - expect(eventDispatcher.eventNames()).toEqual(["test"]); - }); - - it("remove all event Listener", () => { - const eventDispatcher = new EventDispatcher(null); - eventDispatcher.on("test1", (param) => { - expect(param).toEqual("test"); - }); - - eventDispatcher.on("test2", (param) => { - expect(param).toEqual("test"); - }); - - expect(eventDispatcher.eventNames()).toEqual(["test1", "test2"]); - eventDispatcher.removeAllEventListeners(); - expect(eventDispatcher.eventNames()).toEqual([]); - }); -}); diff --git a/packages/core/tests/ModelMesh.test.ts b/packages/core/tests/ModelMesh.test.ts deleted file mode 100644 index c40bd28210..0000000000 --- a/packages/core/tests/ModelMesh.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { Vector2, Vector3, Vector4, Color } from "@oasis-engine/math"; -import { WebGLEngine } from "../../rhi-webgl/src"; -import { BlendShape, IndexFormat } from "../src"; -import { ModelMesh } from "../src/mesh/ModelMesh"; - -describe("ModelMesh Test", function () { - const engine = new WebGLEngine(document.createElement("canvas")); - // @ts-ignore - const modelMesh = new ModelMesh(engine); - const positions = [new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0)]; - const positionsX = [new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 1, 0), new Vector3()]; - const colors = [new Color(), new Color(), new Color()]; - const normals = [new Vector3(), new Vector3(), new Vector3()]; - const uvs = [new Vector2(), new Vector2(), new Vector2()]; - const tangents = [new Vector4(), new Vector4(), new Vector4()]; - const weights = [new Vector4(), new Vector4(), new Vector4()]; - const joints = [new Vector4(), new Vector4(), new Vector4()]; - const indices = new Uint8Array([0, 1, 2]); - const indices16 = new Uint16Array([0, 1, 2]); - const indices32 = new Uint32Array([0, 1, 2]); - const deltaPositions = [new Vector3(1, 1, 1), new Vector3(2, 2, 2), new Vector3(3, 3, 3)]; - const deltaNormals = [new Vector3(1, 1, 1), new Vector3(2, 2, 2), new Vector3(3, 3, 3)]; - const deltaTangents = [new Vector3(1, 1, 1), new Vector3(2, 2, 2), new Vector3(3, 3, 3)]; - - const falsyColors = [new Color()]; - const falsyNormals = [new Vector3()]; - const falsyUV = [new Vector2()]; - const falsyTangents = [new Vector4()]; - const falsyWeights = [new Vector4()]; - const falsyJoints = [new Vector4()]; - it("init", () => { - expect(modelMesh.accessible).toBeTruthy(); - }); - - it("set position data", () => { - modelMesh.setPositions(positionsX); - expect(modelMesh.vertexCount).toBe(4); - modelMesh.setPositions(positions); - expect(modelMesh.vertexCount).toBe(3); - }); - - it("set indices data", () => { - modelMesh.setIndices(indices); - // @ts-ignore - expect(modelMesh._indicesFormat).toBe(IndexFormat.UInt8); - modelMesh.setIndices(indices16); - // @ts-ignore - expect(modelMesh._indicesFormat).toBe(IndexFormat.UInt16); - modelMesh.setIndices(indices32); - // @ts-ignore - expect(modelMesh._indicesFormat).toBe(IndexFormat.UInt32); - }); - - it("set blendShape data", () => { - const blendShape = new BlendShape("BlendShape"); - blendShape.addFrame(1.0, deltaPositions, deltaNormals, deltaTangents); - modelMesh.addBlendShape(blendShape); - - const frame0 = modelMesh.blendShapes[0].frames[0]; - expect(frame0.weight).toBe(1.0); - expect(frame0.deltaPositions.length).toBe(3); - expect(frame0.deltaNormals.length).toBe(3); - expect(frame0.deltaTangents.length).toBe(3); - }); - - it("set data correct", () => { - modelMesh.setIndices(indices); - modelMesh.setColors(colors); - modelMesh.setNormals(normals); - modelMesh.setTangents(tangents); - modelMesh.setBoneWeights(weights); - modelMesh.setBoneIndices(joints); - modelMesh.setUVs(uvs); - modelMesh.setUVs(uvs, 1); - modelMesh.setUVs(uvs, 2); - modelMesh.setUVs(uvs, 3); - modelMesh.setUVs(uvs, 4); - modelMesh.setUVs(uvs, 5); - modelMesh.setUVs(uvs, 6); - modelMesh.setUVs(uvs, 7); - - expect(modelMesh.getIndices()).toBe(indices); - expect(modelMesh.getColors()).toBe(colors); - expect(modelMesh.getNormals()).toBe(normals); - expect(modelMesh.getTangents()).toBe(tangents); - expect(modelMesh.getBoneWeights()).toBe(weights); - expect(modelMesh.getBoneIndices()).toBe(joints); - expect(modelMesh.getUVs()).toBe(uvs); - expect(modelMesh.getUVs(1)).toBe(uvs); - expect(modelMesh.getUVs(2)).toBe(uvs); - expect(modelMesh.getUVs(3)).toBe(uvs); - expect(modelMesh.getUVs(4)).toBe(uvs); - expect(modelMesh.getUVs(5)).toBe(uvs); - expect(modelMesh.getUVs(6)).toBe(uvs); - expect(modelMesh.getUVs(7)).toBe(uvs); - - expect(modelMesh._vertexElements.length).toBe(0); - - const frame0 = modelMesh.blendShapes[0].frames[0]; - expect(frame0.deltaPositions).toBe(deltaPositions); - expect(frame0.deltaNormals).toBe(deltaNormals); - expect(frame0.deltaTangents).toBe(deltaTangents); - }); - - it("set data not same size", () => { - expect(() => { - modelMesh.setColors(falsyColors); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setNormals(falsyNormals); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setTangents(falsyTangents); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setBoneWeights(falsyWeights); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setBoneIndices(falsyJoints); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - expect(() => { - modelMesh.setUVs(falsyUV); - }).toThrow("The array provided needs to be the same size as vertex count."); - }); - - it("upload data with no longer used", () => { - modelMesh.uploadData(false); - - expect(modelMesh.getIndices()).toBe(indices); - expect(modelMesh.getColors()).toBe(colors); - expect(modelMesh.getNormals()).toBe(normals); - expect(modelMesh.getTangents()).toBe(tangents); - expect(modelMesh.getBoneWeights()).toBe(weights); - expect(modelMesh.getBoneIndices()).toBe(joints); - expect(modelMesh.getUVs()).toBe(uvs); - expect(modelMesh.getUVs(1)).toBe(uvs); - expect(modelMesh.getUVs(2)).toBe(uvs); - expect(modelMesh.getUVs(3)).toBe(uvs); - expect(modelMesh.getUVs(4)).toBe(uvs); - expect(modelMesh.getUVs(5)).toBe(uvs); - expect(modelMesh.getUVs(6)).toBe(uvs); - expect(modelMesh.getUVs(7)).toBe(uvs); - - const frame0 = modelMesh.blendShapes[0].frames[0]; - expect(frame0.deltaPositions).toBe(deltaPositions); - expect(frame0.deltaNormals).toBe(deltaNormals); - expect(frame0.deltaTangents).toBe(deltaTangents); - - modelMesh.setPositions(positionsX); - modelMesh.clearBlendShapes(); - expect(modelMesh.blendShapes.length).toBe(0); - - expect(modelMesh.vertexCount).toBe(4); - // @ts-ignore - const vertices = modelMesh._verticesFloat32; - modelMesh.uploadData(false); - // @ts-ignore - expect(vertices).not.toBe(modelMesh._verticesFloat32); - modelMesh.setIndices(null); - //@ts-ignore - expect(modelMesh._indices).toBeNull(); - modelMesh.uploadData(false); - const moreIndices = new Uint8Array([1, 2, 3]); - modelMesh.setIndices(moreIndices); - modelMesh.uploadData(false); - - modelMesh.setIndices(null); - modelMesh.setPositions(positions); - }); - it("upload data with no longer used", () => { - modelMesh.uploadData(true); - expect(() => { - modelMesh.setIndices(indices); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setPositions(positions); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setColors(colors); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setNormals(normals); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setTangents(tangents); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setBoneWeights(weights); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setBoneIndices(joints); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setUVs(uvs); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.setUVs(uvs); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getPositions(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getColors(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getNormals(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getTangents(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getBoneWeights(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getBoneIndices(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.getUVs(); - }).toThrow("Not allowed to access data while accessible is false."); - expect(() => { - modelMesh.blendShapes; - }).toThrow("Not allowed to access data while accessible is false."); - }); -}); diff --git a/packages/core/tests/Request.test.ts b/packages/core/tests/Request.test.ts deleted file mode 100644 index d24f90e49c..0000000000 --- a/packages/core/tests/Request.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { MultiExecutor, request } from "../src/asset/request"; - -describe("MultiExecute", () => { - it("multiple execute function", () => { - return expect( - new Promise((resolve) => { - let i = 0; - const multiExec = new MultiExecutor( - () => { - i++; - return Promise.resolve(); - }, - 5, - 100 - ); - multiExec.start(() => { - resolve(i); - }); - }) - ).resolves.toEqual(5); - }); - - it("multiple execute function stop", () => { - return expect( - new Promise((resolve) => { - let i = 0; - const multiExec = new MultiExecutor( - () => { - i++; - if (i > 2) { - resolve(i); - multiExec.stop(); - } - return Promise.resolve(); - }, - 5, - 100 - ); - multiExec.start(() => { - resolve(i); - }); - }) - ).resolves.toEqual(3); - }); -}); - -describe("request", () => { - // it("request image", () => { - // const pp = request( - // "https://gw.alipayobjects.com/mdn/rms_af43d2/afts/img/A*02jzTq1WcikAAAAAAAAAAABkARQnAQ", - // { - // type: "image", - // timeout: 10, - // retryCount: 1 - // } - // ).then((res) => { - // return { width: res.width, height: res.height }; - // }); - // return expect(pp).rejects.toEqual(new Error("request https://gw.alipayobjects.com/mdn/rms_af43d2/afts/img/A*02jzTq1WcikAAAAAAAAAAABkARQnAQ timeout")); - // }); - // - // it("request bin", () => { - // let lastP = 0; - // const promise = request( - // "https://gw.alipayobjects.com/os/OasisHub/b73b0309-3227-4b24-849a-8ec010fc7f7f/48000126/0.8387082619152928.bin" - // ) - // .onProgress((p) => { - // expect(p).toBeGreaterThan(lastP); - // lastP = p; - // }) - // .then((res) => { - // return "success"; - // }) - // .catch((e) => { - // return "failed"; - // }); - // - // return expect(promise).resolves.toEqual("success"); - // }); - // - // it("request timeout", () => { - // const url = - // "https://gw.alipayobjects.com/os/OasisHub/b73b0309-3227-4b24-849a-8ec010fc7f7f/48000126/0.8387082619152928.bin"; - // const promise = request(url, { - // timeout: 10, - // retryCount: 1 - // }).catch((e) => { - // return e; - // }); - // return expect(promise).resolves.toEqual(new Error(`request timeout from: ${url}`)); - // }); -}); diff --git a/packages/core/tests/ResourceManager.test.ts b/packages/core/tests/ResourceManager.test.ts deleted file mode 100644 index 05429df884..0000000000 --- a/packages/core/tests/ResourceManager.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { WebGLEngine } from "../../rhi-webgl/src"; -import { Engine } from "../src"; -import { AssetPromise } from "../src/asset/AssetPromise"; -import { AssetType } from "../src/asset/AssetType"; -import { Loader } from "../src/asset/Loader"; -import { LoadItem } from "../src/asset/LoadItem"; -import { RefObject } from "../src/asset/RefObject"; -import { resourceLoader, ResourceManager } from "../src/asset/ResourceManager"; - -@resourceLoader(AssetType.Text, ["txt"], false) -class TestLoader extends Loader { - load(item: LoadItem): AssetPromise { - return new AssetPromise((resolve) => { - setTimeout(() => { - resolve("test"); - }, 1000); - }); - } -} - -class TestRefObject extends RefObject { - constructor(engine: Engine) { - super(engine); - } - onDestroy() {} -} - -@resourceLoader(AssetType.JSON, ["json"]) -class TestJsonLoader extends Loader { - load(item: LoadItem, resourceManager: ResourceManager): AssetPromise { - return new AssetPromise((resolve) => { - setTimeout(() => { - resolve(new TestRefObject(resourceManager.engine)); - }, 300); - }); - } -} - -describe("test resource manager", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - engine._resourceManager = new ResourceManager(engine); - describe("Add Loader Test", function () { - it("load custom loader url", () => { - return expect(engine.resourceManager.load("xx.txt")).resolves.toEqual("test"); - }); - it("load custom loader object", () => { - return expect(engine.resourceManager.load({ url: "xx.txt" })).resolves.toEqual("test"); - }); - it("load custom loader specify type", () => { - return expect(engine.resourceManager.load({ url: "xx", type: AssetType.Text })).resolves.toEqual("test"); - }); - it("load url loader type undefined", () => { - return expect(() => { - engine.resourceManager.load({ url: "xx" }); - }).toThrow(); - }); - it(`load all test`, () => { - return expect(engine.resourceManager.load(["xx.txt", "xx.txt"])).resolves.toEqual(["test", "test"]); - }); - }); - - const jsonEngine = new WebGLEngine(document.createElement("canvas")); - jsonEngine._resourceManager = new ResourceManager(engine); - it("test delete object", () => { - const path = "xaa.json"; - const promiseAA = jsonEngine.resourceManager.load(path); - return expect( - promiseAA.then((obj) => { - expect(jsonEngine.resourceManager.getAssetPath(obj.instanceId)).toEqual(path); - jsonEngine.resourceManager._deleteAsset(obj); - expect(jsonEngine.resourceManager.getAssetPath(obj.instanceId)).toBeUndefined(); - return {}; - }) - ).resolves.toEqual({}); - }); - - it("test promise cache", () => { - const promise = jsonEngine.resourceManager.load("xba.json"); - const promise1 = jsonEngine.resourceManager.load("xba.json"); - expect(promise === promise1).toBeTruthy(); - }); - - it("test asset cache", () => { - const promise = jsonEngine.resourceManager - .load("xca.json") - .then(() => { - return jsonEngine.resourceManager.load("xca.json"); - }) - .then(() => { - return {}; - }); - expect(promise).resolves.toEqual({}); - }); - - // it("test reference gc", () => { - // const engine = new Engine(null, { init: () => {}, canIUse: jest.fn() }); - // return expect( - // engine.resourceManager.load("xca.json").then((res) => { - // res._addRefCount(1); - // engine.resourceManager.gc(); - // expect(res.destroyed).toBeFalsy(); - // res._addRefCount(-1); - // engine.resourceManager.gc(); - // return res.destroyed; - // }) - // ).resolves.toBeTruthy(); - // }); - - // error 需要在最后抛出 - it("test all cancel", () => { - const promise = engine.resourceManager.load({ url: "xna.txt" }); - promise.catch((e) => e); - engine.resourceManager.cancelNotLoaded(); - return expect(promise).rejects.toEqual("Promise Canceled"); - }); - - it("test specify cancel", () => { - const promise = engine.resourceManager.load(["xaa.txt", "xab.txt"]); - promise.catch((e) => e); - engine.resourceManager.cancelNotLoaded("xaa.txt"); - return expect(promise).rejects.toEqual("Promise Canceled"); - }); - - it("test specify cancel array", () => { - const promise = engine.resourceManager.load(["xca.txt", "xcb.txt", "xcc.txt"]); - promise.catch((e) => e); - engine.resourceManager.cancelNotLoaded(["xca.txt", "xcb.txt"]); - return expect(promise).rejects.toEqual("Promise Canceled"); - }); -}); diff --git a/packages/core/tests/Scene.test.ts b/packages/core/tests/Scene.test.ts deleted file mode 100644 index 48647a385a..0000000000 --- a/packages/core/tests/Scene.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; -import { Entity } from "../src/index"; - -describe("Scene test", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const scene = engine.sceneManager.activeScene; - engine.run(); - - describe("test - root entity", () => { - const entity = new Entity(engine); - - it("No root entity by default", () => { - expect(scene.rootEntitiesCount).toBe(0); - expect(scene.engine).not.toBe(null); - }); - - it("Add root entity", () => { - scene.addRootEntity(entity); - expect(scene.rootEntitiesCount).toBe(1); - expect(scene.getRootEntity()).toBe(entity); - }); - - it("Remove root entity", () => { - expect(scene.rootEntitiesCount).toBe(1); - scene.removeRootEntity(entity); - expect(scene.rootEntitiesCount).toBe(0); - expect(scene.getRootEntity()).not.toBeDefined(); - - scene.addRootEntity(entity); - }); - }); - - it("test - destory", () => { - // before - expect(scene.destroyed).toBeFalsy(); - expect(scene.rootEntitiesCount).not.toBe(0); - - // after - scene.destroy(); - expect(scene.destroy).toBeTruthy(); - expect(scene.rootEntitiesCount).toBe(0); - expect(scene.engine.sceneManager.activeScene).not.toBe(scene); - }); -}); diff --git a/packages/core/tests/SpriteRenderer.test.ts b/packages/core/tests/SpriteRenderer.test.ts deleted file mode 100644 index 7a13d7e02e..0000000000 --- a/packages/core/tests/SpriteRenderer.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -// @ts-nocheck -import { Color } from "@oasis-engine/math"; -import { Entity, Sprite, SpriteRenderer, Texture2D } from "../src/index"; -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; - -describe("SpriteRenderer", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - const scene = engine.sceneManager.activeScene; - - engine.run(); - - beforeEach(() => { - scene.createRootEntity("root"); - }); - - it("Constructor", () => { - const rootEntity = scene.getRootEntity(); - const spriteRenderer = rootEntity.addComponent(SpriteRenderer); - const defaultColor = new Color(1, 1, 1, 1); - - expect(spriteRenderer instanceof SpriteRenderer).toEqual(true); - expect(spriteRenderer.sprite).toEqual(null); - expect(Color.equals(spriteRenderer.color, defaultColor)).toEqual(true); - expect(spriteRenderer.flipX).toEqual(false); - expect(spriteRenderer.flipY).toEqual(false); - }); - - it("get set sprite", () => { - const rootEntity = scene.getRootEntity(); - const spriteRenderer = rootEntity.addComponent(SpriteRenderer); - const texture = new Texture2D(engine, 100, 100); - const sprite = new Sprite(engine, texture); - spriteRenderer.sprite = sprite; - - expect(spriteRenderer.sprite).toBe(sprite); - }); - - it("get set color", () => { - const rootEntity = scene.getRootEntity(); - const spriteRenderer = rootEntity.addComponent(SpriteRenderer); - spriteRenderer.color.setValue(1, 0, 0, 1); - - expect(Color.equals(spriteRenderer.color, new Color(1, 0, 0, 1))).toEqual(true); - }); - - it("get set flip", () => { - const rootEntity = scene.getRootEntity(); - const spriteRenderer = rootEntity.addComponent(SpriteRenderer); - spriteRenderer.flipX = true; - spriteRenderer.flipY = true; - - expect(spriteRenderer.flipY).toEqual(true); - expect(spriteRenderer.flipY).toEqual(true); - }); -}); diff --git a/packages/core/tests/TextRenderer.test.ts b/packages/core/tests/TextRenderer.test.ts deleted file mode 100644 index e6f1e9ffc3..0000000000 --- a/packages/core/tests/TextRenderer.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -// @ts-nocheck -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; -import { TextRenderer } from "../src/index"; - -describe("TextRenderer", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - const scene = engine.sceneManager.activeScene; - - engine.run(); - - beforeEach(() => { - scene.createRootEntity("root"); - }); - - it("Constructor", () => { - const rootEntity = scene.getRootEntity(); - const textRenderer = rootEntity.addComponent(TextRenderer); - - expect(textRenderer instanceof TextRenderer).toEqual(true); - expect(textRenderer.text == "").toEqual(true); - expect(textRenderer.fontSize).toEqual(24); - expect(textRenderer.lineSpacing).toEqual(0); - expect(textRenderer.enableWrapping).toEqual(false); - }); - - it("set text", () => { - const rootEntity = scene.getRootEntity(); - const textEntity = rootEntity.createChild("text"); - const textRenderer = textEntity.addComponent(TextRenderer); - textRenderer.text = "hello world"; - expect(textRenderer.text).toEqual("hello world"); - }); - - it("set fontSize", () => { - const rootEntity = scene.getRootEntity(); - const textEntity = rootEntity.createChild("text"); - const textRenderer = textEntity.addComponent(TextRenderer); - textRenderer.fontSize = 30; - expect(textRenderer.fontSize).toEqual(30); - }); - - it("set lineSpacing", () => { - const rootEntity = scene.getRootEntity(); - const textEntity = rootEntity.createChild("text"); - const textRenderer = textEntity.addComponent(TextRenderer); - textRenderer.lineSpacing = 1; - expect(textRenderer.lineSpacing).toEqual(1); - }); - - it("set enableWrapping", () => { - const rootEntity = scene.getRootEntity(); - const textEntity = rootEntity.createChild("text"); - const textRenderer = textEntity.addComponent(TextRenderer); - textRenderer.enableWrapping = true; - expect(textRenderer.enableWrapping).toEqual(true); - }); -}); - diff --git a/packages/core/tests/Transform.test.ts b/packages/core/tests/Transform.test.ts deleted file mode 100644 index 0da026fb22..0000000000 --- a/packages/core/tests/Transform.test.ts +++ /dev/null @@ -1,535 +0,0 @@ -import { Matrix, Quaternion, Vector3 } from "@oasis-engine/math"; -import { Entity } from "../src/index"; - -describe("Transform", () => { - describe("no parent", () => { - it("constructor", () => { - const node = new Entity(null); - const transform = node.transform; - vector3CloseTo(transform.position, new Vector3()); - vector3CloseTo(transform.rotation, new Vector3()); - quaternionCloseTo(transform.rotationQuaternion, new Quaternion()); - expect(transform.worldMatrix).toEqual(new Matrix()); - vector3CloseTo(transform.worldPosition, new Vector3()); - vector3CloseTo(transform.worldRotation, new Vector3()); - }); - - it("set position", () => { - const node = new Entity(null); - const transform = node.transform; - transform.position = new Vector3(10, 20, 30); - vector3CloseTo(transform.position, new Vector3(10, 20, 30)); - vector3CloseTo(transform.worldPosition, new Vector3(10, 20, 30)); - arrayCloseTo(transform.localMatrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1]); - arrayCloseTo(transform.worldMatrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1]); - }); - - it("set rotation", () => { - const node = new Entity(null); - const transform = node.transform; - transform.rotation = new Vector3(10, 20, 30); - vector3CloseTo(transform.worldRotation, new Vector3(10, 20, 30)); - quaternionCloseTo( - transform.rotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - quaternionCloseTo( - transform.worldRotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - arrayCloseTo( - transform.localMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - arrayCloseTo( - transform.worldMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - }); - - it("set quat", () => { - const node = new Entity(null); - const transform = node.transform; - transform.rotationQuaternion = new Quaternion( - 0.12767944069578063, - 0.14487812541736914, - 0.2392983377447303, - 0.9515485246437885 - ); - vector3CloseTo(transform.rotation, new Vector3(10, 20, 30)); - vector3CloseTo(transform.worldRotation, new Vector3(10, 20, 30)); - quaternionCloseTo( - transform.worldRotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - arrayCloseTo( - transform.localMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - arrayCloseTo( - transform.worldMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - }); - - it("set scale", () => { - const node = new Entity(null); - const transform = node.transform; - transform.scale = new Vector3(1, 2, 3); - vector3CloseTo(transform.lossyWorldScale, new Vector3(1, 2, 3)); - arrayCloseTo(transform.localMatrix.elements, [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1]); - arrayCloseTo(transform.worldMatrix.elements, [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1]); - }); - - it("set world position", () => { - const node = new Entity(null); - node.transform.worldPosition = new Vector3(10, 20, 30); - vector3CloseTo(node.transform.position, new Vector3(10, 20, 30)); - arrayCloseTo(node.transform.localMatrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1]); - arrayCloseTo(node.transform.worldMatrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1]); - }); - - it("set world rotation", () => { - const node = new Entity(null); - const transform = node.transform; - transform.worldRotation = new Vector3(10, 20, 30); - vector3CloseTo(transform.rotation, new Vector3(10, 20, 30)); - quaternionCloseTo( - transform.rotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - quaternionCloseTo( - transform.worldRotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - arrayCloseTo( - transform.localMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - arrayCloseTo( - transform.worldMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - }); - - it("set world quat", () => { - const node = new Entity(null); - const transform = node.transform; - transform.worldRotationQuaternion = new Quaternion( - 0.12767944069578063, - 0.14487812541736914, - 0.2392983377447303, - 0.9515485246437885 - ); - vector3CloseTo(transform.rotation, new Vector3(10, 20, 30)); - quaternionCloseTo( - transform.rotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - vector3CloseTo(transform.worldRotation, new Vector3(10, 20, 30)); - arrayCloseTo( - transform.localMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - arrayCloseTo( - transform.worldMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 0, 0, 0, 1 - ] - ); - }); - - it("set local matrix", () => { - const node = new Entity(null); - const transform = node.transform; - transform.localMatrix = new Matrix( - 0.8434932827949524, - 0.49240386486053467, - -0.21461017429828644, - 0, - -0.4184120297431946, - 0.8528685569763184, - 0.31232455372810364, - 0, - 0.33682408928871155, - -0.1736481785774231, - 0.9254165887832642, - 0, - 10, - 20, - 30, - 1 - ); - vector3CloseTo(transform.position, new Vector3(10, 20, 30)); - vector3CloseTo(transform.worldPosition, new Vector3(10, 20, 30)); - vector3CloseTo(transform.rotation, new Vector3(10, 20, 30)); - vector3CloseTo(transform.worldRotation, new Vector3(10, 20, 30)); - quaternionCloseTo( - transform.rotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - quaternionCloseTo( - transform.worldRotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - arrayCloseTo( - transform.worldMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 10, 20, 30, 1 - ] - ); - }); - - it("set world matrix", () => { - const node = new Entity(null); - const transform = node.transform; - transform.worldMatrix = new Matrix( - 0.8434932827949524, - 0.49240386486053467, - -0.21461017429828644, - 0, - -0.4184120297431946, - 0.8528685569763184, - 0.31232455372810364, - 0, - 0.33682408928871155, - -0.1736481785774231, - 0.9254165887832642, - 0, - 10, - 20, - 30, - 1 - ); - vector3CloseTo(transform.position, new Vector3(10, 20, 30)); - vector3CloseTo(transform.worldPosition, new Vector3(10, 20, 30)); - vector3CloseTo(transform.rotation, new Vector3(10, 20, 30)); - vector3CloseTo(transform.worldRotation, new Vector3(10, 20, 30)); - quaternionCloseTo( - transform.rotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - quaternionCloseTo( - transform.worldRotationQuaternion, - new Quaternion(0.12767944069578063, 0.14487812541736914, 0.2392983377447303, 0.9515485246437885) - ); - arrayCloseTo( - transform.localMatrix.elements, - [ - 0.8434932827949524, 0.49240386486053467, -0.21461017429828644, 0, -0.4184120297431946, 0.8528685569763184, - 0.31232455372810364, 0, 0.33682408928871155, -0.1736481785774231, 0.9254165887832642, 0, 10, 20, 30, 1 - ] - ); - }); - - it("get up, right, forward", () => { - const node = new Entity(null); - const up = new Vector3(); - const right = new Vector3(); - const forward = new Vector3(); - node.transform.getWorldUp(up); - node.transform.getWorldRight(right); - node.transform.getWorldForward(forward); - vector3CloseTo(up, new Vector3(0, 1, 0)); - vector3CloseTo(right, new Vector3(1, 0, 0)); - vector3CloseTo(forward, new Vector3(0, 0, -1)); - }); - }); - - describe("with parent", () => { - it("set parent position, child position", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.position = new Vector3(10, 20, 30); - child.transform.position = new Vector3(10, 20, 30); - vector3CloseTo(child.transform.worldPosition, new Vector3(20, 40, 60)); - }); - - it("set parent rotation, child rotation", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.rotation = new Vector3(90, 0, 0); - child.transform.rotation = new Vector3(90, 0, 0); - vector3CloseTo(child.transform.worldRotation, new Vector3(0, 180, 180)); - }); - - it("set parent rotation, child position", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.rotation = new Vector3(90, 0, 0); - child.transform.position = new Vector3(0, 0, 10); - vector3CloseTo(child.transform.worldPosition, new Vector3(0, -10, 0)); - vector3CloseTo(child.transform.worldRotation, new Vector3(90, 0, 0)); - }); - - it("set parent scale, child position", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.scale = new Vector3(2, 2, 2); - child.transform.position = new Vector3(0, 0, 10); - vector3CloseTo(child.transform.worldPosition, new Vector3(0, 0, 20)); - }); - - it("set parent position, rotation, scale, child lossy world scale", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.scale = new Vector3(2, 2, 2); - child.transform.rotation = new Vector3(60, 60, 60); - vector3CloseTo(child.transform.lossyWorldScale, new Vector3(2, 2, 2)); - }); - - it("set parent local matrix, child position", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - child.transform.position = new Vector3(0, 0, 10); - parent.transform.localMatrix = new Matrix( - 0.8434932827949524, - 0.49240386486053467, - -0.21461017429828644, - 0, - -0.4184120297431946, - 0.8528685569763184, - 0.31232455372810364, - 0, - 0.33682408928871155, - -0.1736481785774231, - 0.9254165887832642, - 0, - 10, - 20, - 30, - 1 - ); - vector3CloseTo( - child.transform.worldPosition, - new Vector3(13.368241310119629, 18.263517379760742, 39.25416564941406) - ); - vector3CloseTo(child.transform.worldRotation, new Vector3(10, 20, 30)); - vector3CloseTo(child.transform.lossyWorldScale, new Vector3(1, 1, 1)); - }); - - it("set parent world matrix, child position", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - child.transform.position = new Vector3(0, 0, 10); - parent.transform.worldMatrix = new Matrix( - 0.8434932827949524, - 0.49240386486053467, - -0.21461017429828644, - 0, - -0.4184120297431946, - 0.8528685569763184, - 0.31232455372810364, - 0, - 0.33682408928871155, - -0.1736481785774231, - 0.9254165887832642, - 0, - 10, - 20, - 30, - 1 - ); - vector3CloseTo( - child.transform.worldPosition, - new Vector3(13.368241310119629, 18.263517379760742, 39.25416564941406) - ); - vector3CloseTo(child.transform.worldRotation, new Vector3(10, 20, 30)); - vector3CloseTo(child.transform.lossyWorldScale, new Vector3(1, 1, 1)); - }); - - it("set parent position, child world position", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.position = new Vector3(10, 0, 0); - child.transform.worldPosition = new Vector3(20, 10, 0); - vector3CloseTo(child.transform.position, new Vector3(10, 10, 0)); - }); - - it("set parent position, child world rotation", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.position = new Vector3(10, 0, 0); - child.transform.worldRotation = new Vector3(0, 90, 0); - vector3CloseTo(child.transform.rotation, new Vector3(0, 90, 0)); - }); - - it("set parent rotation, child world rotation", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.rotation = new Vector3(0, 90, 0); - child.transform.worldRotation = new Vector3(0, 100, 0); - vector3CloseTo(child.transform.rotation, new Vector3(0, 10, 0)); - }); - - it("set parent rotation, child world quat", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.rotation = new Vector3(10, 20, 30); - child.transform.worldRotationQuaternion = new Quaternion( - 0.12767944069578063, - 0.14487812541736914, - 0.2392983377447303, - 0.9515485246437885 - ); - vector3CloseTo(child.transform.rotation, new Vector3()); - }); - - it("set parent local matrix, child world matrix", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.localMatrix = new Matrix( - 0.813797652721405, - 0.46984630823135376, - -0.3420201241970062, - 0, - -0.8819392323493958, - 1.765128254890442, - 0.3263518214225769, - 0, - 1.1355668306350708, - 0.05408494547009468, - 2.776249647140503, - 0, - 10, - 20, - 30, - 1 - ); - child.transform.worldMatrix = new Matrix( - 0.813797652721405, - 0.46984630823135376, - -0.3420201241970062, - 0, - -0.8819392323493958, - 1.765128254890442, - 0.3263518214225769, - 0, - 1.1355668306350708, - 0.05408494547009468, - 2.776249647140503, - 0, - 10, - 20, - 30, - 1 - ); - vector3CloseTo(child.transform.position, new Vector3()); - vector3CloseTo(child.transform.rotation, new Vector3()); - vector3CloseTo(child.transform.scale, new Vector3(1, 1, 1)); - }); - }); - - describe("func", () => { - it("translate", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.translate(new Vector3(10, 20, 30), false); - child.transform.translate(new Vector3(10, 20, 30), true); - vector3CloseTo(child.transform.position, new Vector3(10, 20, 30)); - child.transform.translate(new Vector3(10, 20, 30), false); - vector3CloseTo(child.transform.position, new Vector3(0, 0, 0)); - }); - it("rotate", () => { - const parent = new Entity(null, "parent"); - const child = new Entity(null, "child"); - parent.addChild(child); - parent.transform.rotate(new Vector3(0, 0, 180), false); - child.transform.rotate(new Vector3(0, 0, 45), true); - vector3CloseTo(child.transform.rotation, new Vector3(0, 0, 45)); - child.transform.rotate(new Vector3(0, 0, 45), false); - vector3CloseTo(child.transform.worldRotation, new Vector3(0, 0, -90)); - }); - it("rotateByAxis", () => { - const parent = new Entity(null,"parent"); - const child = new Entity(null,"child"); - parent.addChild(child); - child.transform.position = new Vector3(10, 0, 0); - parent.transform.rotateByAxis(new Vector3(0, 0, 1), 90, true); - vector3CloseTo(child.transform.worldPosition, new Vector3(0, 10, 0)); - child.transform.rotateByAxis(new Vector3(0, 0, 1), 180, false); - vector3CloseTo(child.transform.worldPosition, new Vector3(0, 10, 0)); - }); - it("lookAt", () => { - const node = new Entity(null); - node.transform.position = new Vector3(0, 0, 1); - node.transform.lookAt(new Vector3(), new Vector3(0, 1, 0)); - vector3CloseTo(node.transform.worldRotation, new Vector3(0, 0, 0)); - }); - }); -}); - -function arrayCloseTo(arr1, arr2) { - if (isFloat32Array(arr1)) { - expect(arr1.length).toEqual(arr2.length); - for (let i = 0; i < arr1.length; i++) { - const m1 = arr1[i]; - const m2 = arr2[i]; - expect(m1).toBeCloseTo(m2); - } - } else { - const keys1 = Object.keys(arr1); - const keys2 = Object.keys(arr2); - expect(keys1.length).toEqual(keys2.length); - for (let i = 0; i < keys1.length; i++) { - const key = keys1[i]; - const m1 = arr1[key]; - const m2 = arr2[key]; - expect(m1).toBeCloseTo(m2); - } - } -} - -function vector3CloseTo(vec1, vec2) { - expect(vec1.x).toBeCloseTo(vec2.x); - expect(vec1.y).toBeCloseTo(vec2.y); - expect(vec1.z).toBeCloseTo(vec2.z); -} - -function quaternionCloseTo(qua1, qua2) { - expect(qua1.x).toBeCloseTo(qua2.x); - expect(qua1.y).toBeCloseTo(qua2.y); - expect(qua1.z).toBeCloseTo(qua2.z); - expect(qua1.w).toBeCloseTo(qua2.w); -} - -function isFloat32Array(arr) { - if (Object.prototype.toString.call(arr) === "[object Float32Array]") return true; - return false; -} diff --git a/packages/core/tests/material/BaseMaterial.test.ts b/packages/core/tests/material/BaseMaterial.test.ts deleted file mode 100644 index 5d60ff2978..0000000000 --- a/packages/core/tests/material/BaseMaterial.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -// @ts-nocheck -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { BaseMaterial, BlendMode, RenderFace } from "../../src/material"; -import { CullMode, Shader } from "../../src/shader"; - -describe("BaseMaterial", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - - class TestMaterial extends BaseMaterial { - constructor(engine) { - super(engine, Shader.find("blinn-phong")); - } - - clone(): TestMaterial { - const dest = new TestMaterial(this._engine); - this.cloneTo(dest); - return dest; - } - } - - it("base 参数测试", () => { - const material = new TestMaterial(engine); - - expect(material.alphaCutoff).toBe(0); - expect(material.isTransparent).toBe(false); - expect(material.blendMode).toBe(BlendMode.Normal); - expect(material.renderFace).toBe(RenderFace.Front); - - material.alphaCutoff = 0.5; - material.isTransparent = true; - material.blendMode = BlendMode.Additive; - material.renderFace = RenderFace.Double; - - expect(material.alphaCutoff).toBe(0.5); - expect(material.isTransparent).toBe(true); - expect(material.blendMode).toBe(BlendMode.Additive); - expect(material.renderFace).toBe(RenderFace.Double); - }); - - it("renderFace", () => { - const material = new TestMaterial(engine); - - material.renderFace = RenderFace.Front; - expect(material.renderState.rasterState.cullMode).toBe(CullMode.Back); - material.renderFace = RenderFace.Back; - expect(material.renderState.rasterState.cullMode).toBe(CullMode.Front); - material.renderFace = RenderFace.Double; - expect(material.renderState.rasterState.cullMode).toBe(CullMode.Off); - }); - - it("isTransparent", () => { - const material = new TestMaterial(engine); - - expect(material.renderState.blendState.targetBlendState.enabled).toBeFalsy(); - expect(material.renderState.depthState.writeEnabled).toBeTruthy(); - - material.isTransparent = true; - - expect(material.renderState.blendState.targetBlendState.enabled).toBeTruthy(); - expect(material.renderState.depthState.writeEnabled).toBeFalsy(); - }); - - it("clone", () => { - const material = new TestMaterial(engine); - - material.alphaCutoff = 0.5; - material.isTransparent = true; - material.blendMode = BlendMode.Additive; - material.renderFace = RenderFace.Double; - - const clone = material.clone(); - - expect(clone.alphaCutoff).toBe(0.5); - expect(clone.isTransparent).toBe(true); - expect(clone.blendMode).toBe(BlendMode.Additive); - expect(clone.renderFace).toBe(RenderFace.Double); - }); -}); diff --git a/packages/core/tests/material/BlinnPhongMaterial.test.ts b/packages/core/tests/material/BlinnPhongMaterial.test.ts deleted file mode 100644 index 767f6adcd3..0000000000 --- a/packages/core/tests/material/BlinnPhongMaterial.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -// @ts-nocheck -import { Color, Vector4 } from "@oasis-engine/math"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { BlinnPhongMaterial } from "../../src/material"; -import { Texture2D } from "../../src/texture"; - -describe("BlinnPhongMaterial", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - - it("参数测试", () => { - const material = new BlinnPhongMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - expect(material.baseColor).toEqual(new Color(1, 1, 1, 1)); - expect(material.specularColor).toEqual(new Color(1, 1, 1, 1)); - expect(material.emissiveColor).toEqual(new Color(0, 0, 0, 1)); - expect(material.baseTexture).toBeUndefined(); - expect(material.specularTexture).toBeUndefined(); - expect(material.emissiveTexture).toBeUndefined(); - expect(material.normalTexture).toBeUndefined(); - expect(material.normalIntensity).toBe(1); - expect(material.shininess).toBe(16); - expect(material.tilingOffset).toEqual(new Vector4(1, 1, 0, 0)); - - material.baseColor.setValue(1, 0, 0, 1); - material.specularColor.setValue(1, 0, 0, 1); - material.emissiveColor.setValue(1, 0, 0, 1); - material.baseTexture = texture; - material.specularTexture = texture; - material.emissiveTexture = texture; - material.normalTexture = texture; - material.normalIntensity = 2; - material.shininess = 32; - material.tilingOffset.setValue(1, 1, 1, 1); - - expect(material.baseColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.specularColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.emissiveColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.baseTexture).toBe(texture); - expect(material.specularTexture).toBe(texture); - expect(material.emissiveTexture).toBe(texture); - expect(material.normalTexture).toBe(texture); - expect(material.normalIntensity).toBe(2); - expect(material.shininess).toBe(32); - expect(material.tilingOffset).toEqual(new Vector4(1, 1, 1, 1)); - - material.baseTexture = null; - material.specularTexture = null; - material.emissiveTexture = null; - material.normalTexture = null; - material.shininess = 0; - - expect(material.baseTexture).toBeNull(); - expect(material.specularTexture).toBeNull(); - expect(material.emissiveTexture).toBeNull(); - expect(material.normalTexture).toBeNull(); - expect(material.shininess).toBe(1e-4); - }); - - it("clone", () => { - const material = new BlinnPhongMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - material.baseColor = new Color(1, 0, 0, 1); - material.specularColor = new Color(1, 0, 0, 1); - material.emissiveColor = new Color(1, 0, 0, 1); - material.baseTexture = texture; - material.specularTexture = texture; - material.emissiveTexture = texture; - material.normalTexture = texture; - material.normalIntensity = 2; - material.shininess = 32; - material.tilingOffset = new Vector4(1, 1, 1, 1); - - const clone = material.clone(); - - expect(clone.baseColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.specularColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.emissiveColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.baseTexture).toBe(material.baseTexture); - expect(clone.specularTexture).toBe(material.specularTexture); - expect(clone.emissiveTexture).toBe(material.emissiveTexture); - expect(clone.normalTexture).toBe(material.normalTexture); - expect(clone.normalIntensity).toBe(2); - expect(clone.shininess).toBe(32); - expect(clone.tilingOffset).toEqual(new Vector4(1, 1, 1, 1)); - }); -}); diff --git a/packages/core/tests/material/PBRBaseMaterial.test.ts b/packages/core/tests/material/PBRBaseMaterial.test.ts deleted file mode 100644 index 80c90dfcea..0000000000 --- a/packages/core/tests/material/PBRBaseMaterial.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -// @ts-nocheck -import { Color, Vector4 } from "@oasis-engine/math"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { PBRMaterial } from "../../src/material"; -import { Texture2D } from "../../src/texture"; - -describe("PBRBaseMaterial", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - - it("pbr base 参数测试", () => { - const material = new PBRMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - expect(material.baseColor).toEqual(new Color(1, 1, 1, 1)); - expect(material.emissiveColor).toEqual(new Color(0, 0, 0, 1)); - expect(material.tilingOffset).toEqual(new Vector4(1, 1, 0, 0)); - expect(material.normalTextureIntensity).toBe(1); - expect(material.occlusionTextureIntensity).toBe(1); - - expect(material.baseTexture).toBeUndefined(); - expect(material.emissiveTexture).toBeUndefined(); - expect(material.normalTexture).toBeUndefined(); - expect(material.occlusionTexture).toBeUndefined(); - - material.baseColor.setValue(1, 0, 0, 1); - material.emissiveColor.setValue(1, 0, 0, 1); - material.tilingOffset.setValue(1, 1, 1, 1); - material.normalTextureIntensity = 2; - material.occlusionTextureIntensity = 2; - material.baseTexture = texture; - material.emissiveTexture = texture; - material.normalTexture = texture; - material.occlusionTexture = texture; - - expect(material.baseColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.emissiveColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.tilingOffset).toEqual(new Vector4(1, 1, 1, 1)); - expect(material.normalTextureIntensity).toBe(2); - expect(material.occlusionTextureIntensity).toBe(2); - expect(material.baseTexture).toBe(texture); - expect(material.emissiveTexture).toBe(texture); - expect(material.normalTexture).toBe(texture); - expect(material.occlusionTexture).toBe(texture); - - material.baseTexture = null; - material.emissiveTexture = null; - material.normalTexture = null; - material.occlusionTexture = null; - - expect(material.baseTexture).toBeNull(); - expect(material.emissiveTexture).toBeNull(); - expect(material.normalTexture).toBeNull(); - expect(material.occlusionTexture).toBeNull(); - }); - - it("clone", () => { - const material = new PBRMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - material.baseColor = new Color(1, 0, 0, 1); - material.emissiveColor = new Color(1, 0, 0, 1); - material.tilingOffset = new Vector4(1, 1, 1, 1); - material.normalTextureIntensity = 2; - material.occlusionTextureIntensity = 2; - material.baseTexture = texture; - material.emissiveTexture = texture; - material.normalTexture = texture; - material.occlusionTexture = texture; - - const clone = material.clone(); - - expect(clone.baseColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.emissiveColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.tilingOffset).toEqual(new Vector4(1, 1, 1, 1)); - expect(clone.normalTextureIntensity).toBe(2); - expect(clone.occlusionTextureIntensity).toBe(2); - expect(clone.baseTexture).toBe(material.baseTexture); - expect(clone.emissiveTexture).toBe(material.emissiveTexture); - expect(clone.normalTexture).toBe(material.normalTexture); - expect(clone.occlusionTexture).toBe(material.occlusionTexture); - }); -}); diff --git a/packages/core/tests/material/PBRMaterial.test.ts b/packages/core/tests/material/PBRMaterial.test.ts deleted file mode 100644 index 1db3492f21..0000000000 --- a/packages/core/tests/material/PBRMaterial.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -// @ts-nocheck -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { PBRMaterial } from "../../src/material"; -import { Texture2D } from "../../src/texture"; - -describe("PBRMaterial", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - - it("pbr 参数测试", () => { - const material = new PBRMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - expect(material.metallic).toBe(1); - expect(material.roughness).toBe(1); - expect(material.roughnessMetallicTexture).toBeUndefined(); - - material.metallic = 2; - material.roughness = 2; - material.roughnessMetallicTexture = texture; - - expect(material.metallic).toBe(2); - expect(material.roughness).toBe(2); - expect(material.roughnessMetallicTexture).toBe(texture); - - material.roughnessMetallicTexture = null; - - expect(material.roughnessMetallicTexture).toBeNull(); - }); - - it("clone", () => { - const material = new PBRMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - material.metallic = 2; - material.roughness = 2; - material.roughnessMetallicTexture = texture; - - const clone = material.clone(); - - expect(clone.metallic).toBe(2); - expect(clone.roughness).toBe(2); - expect(clone.roughnessMetallicTexture).toBe(material.roughnessMetallicTexture); - }); -}); diff --git a/packages/core/tests/material/PBRSpecularMaterial.test.ts b/packages/core/tests/material/PBRSpecularMaterial.test.ts deleted file mode 100644 index 9d82bacf10..0000000000 --- a/packages/core/tests/material/PBRSpecularMaterial.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -// @ts-nocheck -import { Color } from "@oasis-engine/math"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { PBRSpecularMaterial } from "../../src/material"; -import { Texture2D } from "../../src/texture"; - -describe("PBRSpecularMaterial", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - - it("pbr specular 参数测试", () => { - const material = new PBRSpecularMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - expect(material.specularColor).toEqual(new Color(1, 1, 1, 1)); - expect(material.glossiness).toBe(1); - expect(material.specularGlossinessTexture).toBeUndefined(); - - material.specularColor.setValue(1, 0, 0, 1); - material.glossiness = 2; - material.specularGlossinessTexture = texture; - - expect(material.specularColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.glossiness).toBe(2); - expect(material.specularGlossinessTexture).toBe(texture); - - material.specularGlossinessTexture = null; - - expect(material.specularGlossinessTexture).toBeNull(); - }); - - it("clone", () => { - const material = new PBRSpecularMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - material.specularColor = new Color(1, 0, 0, 1); - material.glossiness = 2; - material.specularGlossinessTexture = texture; - - const clone = material.clone(); - - expect(clone.specularColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.glossiness).toBe(2); - expect(clone.specularGlossinessTexture).toBe(material.specularGlossinessTexture); - }); -}); diff --git a/packages/core/tests/material/UnlitMaterial.test.ts b/packages/core/tests/material/UnlitMaterial.test.ts deleted file mode 100644 index f53faaa0ff..0000000000 --- a/packages/core/tests/material/UnlitMaterial.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -// @ts-nocheck -import { Color, Vector4 } from "@oasis-engine/math"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { UnlitMaterial } from "../../src/material"; -import { Texture2D } from "../../src/texture"; - -describe("UnlitMaterial", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - - it("参数测试", () => { - const material = new UnlitMaterial(engine); - const texture = new Texture2D(engine, 1024, 1024); - - expect(material.baseColor).toEqual(new Color(1, 1, 1, 1)); - expect(material.tilingOffset).toEqual(new Vector4(1, 1, 0, 0)); - expect(material.baseTexture).toBeUndefined(); - - material.baseColor.setValue(1, 0, 0, 1); - material.tilingOffset.setValue(1, 1, 1, 1); - material.baseTexture = texture; - - expect(material.baseColor).toEqual(new Color(1, 0, 0, 1)); - expect(material.tilingOffset).toEqual(new Vector4(1, 1, 1, 1)); - expect(material.baseTexture).toBe(texture); - - material.baseTexture = null; - expect(material.baseTexture).toBeNull(); - }); - - it("clone", () => { - const material = new UnlitMaterial(engine); - - material.baseColor = new Color(1, 0, 0, 1); - material.tilingOffset = new Vector4(1, 1, 1, 1); - material.baseTexture = new Texture2D(engine, 1024, 1024); - - const clone = material.clone(); - expect(clone.baseColor).toEqual(new Color(1, 0, 0, 1)); - expect(clone.tilingOffset).toEqual(new Vector4(1, 1, 1, 1)); - expect(clone.baseTexture).toBe(material.baseTexture); - }); -}); diff --git a/packages/core/tests/physics/PhysicsManager.test.ts b/packages/core/tests/physics/PhysicsManager.test.ts deleted file mode 100644 index d3ae65ba84..0000000000 --- a/packages/core/tests/physics/PhysicsManager.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -// @ts-nocheck -import { LitePhysics } from "@oasis-engine/physics-lite"; -import { WebGLEngine } from "@oasis-engine/rhi-webgl"; -import { Ray, Vector3 } from "@oasis-engine/math"; -import { BoxColliderShape, Layer, StaticCollider } from "@oasis-engine/core"; - -const canvasDOM = document.createElement("canvas"); -canvasDOM.width = 1024; -canvasDOM.height = 1024; - -describe("physics manager test", () => { - it("constructor", () => { - const engine = new WebGLEngine(canvasDOM); - engine.physicsManager.initialize(LitePhysics); - - expect(engine.physicsManager.gravity.y).toEqual(-9.81); - expect(engine.physicsManager.maxSumTimeStep).toEqual(1 / 3); - expect(engine.physicsManager.fixedTimeStep).toEqual(1 / 60); - }); - - it("raycast", () => { - const engine = new WebGLEngine(canvasDOM); - engine.physicsManager.initialize(LitePhysics); - - const scene = engine.sceneManager.activeScene; - const rootEntity = scene.createRootEntity("root"); - - const collider = rootEntity.addComponent(StaticCollider); - const box = new BoxColliderShape(); - collider.addShape(box); - let ray = new Ray(new Vector3(3, 3, 3), new Vector3(0, 1, 0)); - expect(engine.physicsManager.raycast(ray)).toEqual(false); - expect(engine.physicsManager.raycast(ray, Number.MAX_VALUE)).toEqual(false); - expect(engine.physicsManager.raycast(ray, Number.MAX_VALUE, Layer.Everything)).toEqual(false); - - ray = new Ray(new Vector3(3, 3, 3), new Vector3(-1, -1, -1)); - expect(engine.physicsManager.raycast(ray)).toEqual(true); - expect(engine.physicsManager.raycast(ray, Number.MAX_VALUE)).toEqual(true); - expect(engine.physicsManager.raycast(ray, Number.MAX_VALUE, Layer.Everything)).toEqual(true); - - collider.removeShape(box); - expect(engine.physicsManager.raycast(ray)).toEqual(false); - expect(engine.physicsManager.raycast(ray, Number.MAX_VALUE)).toEqual(false); - expect(engine.physicsManager.raycast(ray, Number.MAX_VALUE, Layer.Everything)).toEqual(false); - }); -}); diff --git a/packages/core/tests/script.test.ts b/packages/core/tests/script.test.ts deleted file mode 100644 index 3486480cbb..0000000000 --- a/packages/core/tests/script.test.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; -import { Component, Entity, Script } from "../src/index"; - -describe("Script", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const scene = engine.sceneManager.activeScene; - engine.run(); - - beforeEach(() => { - scene.createRootEntity("root"); - }); - - describe("enabled", () => { - it("enabled", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onEnable = jest.fn(); - const component = entity.addComponent(TheScript); - expect(component.enabled).toBeTruthy(); - expect(component.onEnable).toHaveBeenCalledTimes(1); - }); - - it("disabled", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onDisable = jest.fn(); - const component = entity.addComponent(TheScript); - component.enabled = false; - expect(component.enabled).toBeFalsy(); - expect(component.onDisable).toHaveBeenCalledTimes(1); - }); - - it("not trigger", () => { - class TheScript extends Script {} - const parent = new Entity(engine, "parent"); - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - parent.isActive = false; - TheScript.prototype.onEnable = jest.fn(); - TheScript.prototype.onDisable = jest.fn(); - const component = child.addComponent(TheScript); - component.enabled = true; - expect(component.onEnable).toHaveBeenCalledTimes(0); - component.enabled = false; - expect(component.onDisable).toHaveBeenCalledTimes(0); - }); - }); - - describe("destroy", () => { - it("onDisable", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onDisable = jest.fn(); - const component = entity.addComponent(TheScript); - component.destroy(); - expect(component.onDisable).toHaveBeenCalledTimes(1); - }); - - it("_onDestroy", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype._onDestroy = jest.fn(); - const component = entity.addComponent(TheScript); - component.destroy(); - expect(component._onDestroy).toHaveBeenCalledTimes(1); - }); - }); - - describe("awake", () => { - it("normal", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onAwake = jest.fn(); - const component = entity.addComponent(TheScript); - expect(component.onAwake).toHaveBeenCalledTimes(1); - }); - - it("entity changeActive", () => { - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - entity.isActive = false; - Script.prototype.onAwake = jest.fn(); - const component = entity.addComponent(Script); - expect(component.onAwake).toHaveBeenCalledTimes(0); - entity.isActive = true; - expect(component.onAwake).toHaveBeenCalledTimes(1); - entity.isActive = false; - entity.isActive = true; - expect(component.onAwake).toHaveBeenCalledTimes(1); - }); - }); - - describe("active", () => { - it("onEnable", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype._onEnable = jest.fn(); - const component = entity.addComponent(TheScript); - expect(component._onEnable).toHaveBeenCalledTimes(1); - }); - - it("onDisable", () => { - class TheScript extends Script {} - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype._onDisable = jest.fn(); - const component = entity.addComponent(TheScript); - entity.isActive = false; - expect(component._onDisable).toHaveBeenCalledTimes(1); - }); - - it("inActiveHierarchy", () => { - class TheScript extends Script {} - const parent = new Entity(engine, "parent"); - parent.parent = scene.getRootEntity(); - const child = new Entity(engine, "child"); - child.parent = parent; - TheScript.prototype._onDisable = jest.fn(); - const component = child.addComponent(TheScript); - parent.isActive = false; - expect(component._onDisable).toHaveBeenCalledTimes(1); - }); - }); - - describe("onStart", () => { - it("normal", () => { - class TheScript extends Script { - onStart() {} - } - TheScript.prototype.onStart = jest.fn(); - const root = scene.getRootEntity(); - const component = root.addComponent(TheScript); - engine.update(); - expect(component.onStart).toHaveBeenCalledTimes(1); - }); - - it("once", () => { - class TheScript extends Script { - onStart() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onStart = jest.fn(); - const component = entity.addComponent(TheScript); - engine.update(); - engine.update(); - expect(component.onStart).toHaveBeenCalledTimes(1); - }); - - it("inActive", () => { - class TheScript extends Script { - onStart() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onStart = jest.fn(); - const component = entity.addComponent(TheScript); - entity.isActive = false; - engine.update(); - expect(component.onStart).toHaveBeenCalledTimes(0); - }); - }); - - describe("onUpdate", () => { - it("normal", () => { - class TheScript extends Script { - onUpdate() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onUpdate = jest.fn(); - const component = entity.addComponent(TheScript); - engine.update(); - engine.update(); - expect(component.onUpdate).toHaveBeenCalledTimes(2); - }); - - it("inActive", () => { - class TheScript extends Script { - onUpdate() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onUpdate = jest.fn(); - const component = entity.addComponent(TheScript); - entity.isActive = false; - engine.update(); - engine.update(); - expect(component.onUpdate).toHaveBeenCalledTimes(0); - }); - }); - - describe("onLateUpdate", () => { - it("normal", () => { - class TheScript extends Script { - onLateUpdate() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onLateUpdate = jest.fn(); - const component = entity.addComponent(TheScript); - engine.update(); - engine.update(); - expect(component.onLateUpdate).toHaveBeenCalledTimes(2); - }); - - it("inActive", () => { - class TheScript extends Script { - onLateUpdate() {} - } - const entity = new Entity(engine, "entity"); - entity.parent = scene.getRootEntity(); - TheScript.prototype.onLateUpdate = jest.fn(); - const component = entity.addComponent(TheScript); - entity.isActive = false; - engine.update(); - engine.update(); - expect(component.onLateUpdate).toHaveBeenCalledTimes(0); - }); - }); - - describe("onBeginRender", () => { - it("normal", () => { - class TestCamera extends Component {} - class TheScript extends Script { - onBeginRender() {} - } - TheScript.prototype.onBeginRender = jest.fn(); - const root = scene.getRootEntity(); - const component = root.addComponent(TheScript); - const camera = root.addComponent(TestCamera); - //@ts-ignore - engine._componentsManager.callCameraOnBeginRender(camera); - //@ts-ignore - engine._componentsManager.callCameraOnBeginRender(camera); - expect(component.onBeginRender).toHaveBeenCalledTimes(2); - }); - }); - - describe("onEndRender", () => { - it("normal", () => { - class TestCamera extends Component {} - class TheScript extends Script { - onEndRender() {} - } - TheScript.prototype.onEndRender = jest.fn(); - const root = scene.getRootEntity(); - const component = root.addComponent(TheScript); - const camera = root.addComponent(TestCamera); - //@ts-ignore - engine._componentsManager.callCameraOnEndRender(camera); - //@ts-ignore - engine._componentsManager.callCameraOnEndRender(camera); - expect(component.onEndRender).toHaveBeenCalledTimes(2); - }); - }); - - describe("onDestroy", () => { - it("normal", () => { - class TheScript extends Script { - onDestroy() {} - } - TheScript.prototype.onDestroy = jest.fn(); - const root = scene.getRootEntity(); - const component = root.addComponent(TheScript); - component.destroy(); - engine._componentsManager.handlingInvalidScripts(); - expect(component.onDestroy).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/packages/core/tests/texture/RenderTarget.test.ts b/packages/core/tests/texture/RenderTarget.test.ts deleted file mode 100644 index 6091ae9491..0000000000 --- a/packages/core/tests/texture/RenderTarget.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -// @ts-nocheck -// @todo: jest `_depth instanceof RenderDepthTexture` in `GLRenderTarget.ts` always return `false`, so test with depthTexture in renderTarget is ignored. - -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import { RenderBufferDepthFormat, RenderTarget, Texture2D } from "../../src/texture"; - -describe("RenderTarget", () => { - const width = 1024; - const height = 1024; - - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - const rhi = engine._hardwareRenderer; - const isWebGL2 = rhi.isWebGL2; - const maxAntiAliasing = rhi.capability._maxAntiAliasing; - - beforeEach(() => { - rhi._isWebGL2 = isWebGL2; - rhi.capability._maxAntiAliasing = maxAntiAliasing; - }); - - describe("创建渲染目标", () => { - const renderColorTexture = new Texture2D(engine, width, height); - const renderColorTexture2 = new Texture2D(engine, width, height); - const renderDepthTexture = new Texture2D(engine, width, height); - - it("创建渲染目标-通过颜色纹理和深度格式", () => { - const renderTarget = new RenderTarget(engine, width, height, renderColorTexture); - - expect(renderTarget.colorTextureCount).toBe(1); - expect(renderTarget.getColorTexture(0)).toBe(renderColorTexture); - expect(renderTarget.depthTexture).toBeUndefined(); - }); - - it("创建渲染目标-通过颜色纹理和深度纹理", () => { - // const renderTarget = new RenderTarget(engine, width, height, renderColorTexture, renderDepthTexture); - // expect(renderTarget.colorTextureCount).toBe(1); - // expect(renderTarget.getColorTexture(0)).toBe(renderColorTexture); - // expect(renderTarget.depthTexture).toBe(renderDepthTexture); - }); - - it("创建渲染目标-只生成深度纹理", () => { - // const renderTarget = new RenderTarget(engine, width, height, null, renderDepthTexture); - // expect(renderTarget.colorTextureCount).toBe(0); - // expect(renderTarget.getColorTexture(0)).toBeUndefined(); - // expect(renderTarget.depthTexture).toBe(renderDepthTexture); - }); - - it("创建渲染目标-通过颜色纹理数组和深度格式", () => { - const renderTarget = new RenderTarget(engine, width, height, [renderColorTexture, renderColorTexture2]); - - expect(renderTarget.colorTextureCount).toBe(2); - expect(renderTarget.getColorTexture(0)).toBe(renderColorTexture); - expect(renderTarget.getColorTexture(1)).toBe(renderColorTexture2); - expect(renderTarget.depthTexture).toBeUndefined(); - }); - - it("创建渲染目标-通过颜色纹理数组和深度纹理", () => { - // const renderTarget = new RenderTarget( - // engine, - // width, - // height, - // [renderColorTexture, renderColorTexture2], - // renderDepthTexture - // ); - // expect(renderTarget.colorTextureCount).toBe(2); - // expect(renderTarget.getColorTexture(0)).toBe(renderColorTexture); - // expect(renderTarget.getColorTexture(1)).toBe(renderColorTexture2); - // expect(renderTarget.depthTexture).toBe(renderDepthTexture); - }); - - it("创建失败-不支持高精度深度缓冲", () => { - expect(() => { - rhi.canIUse.mockReturnValueOnce(false); - new RenderTarget(engine, width, height, renderColorTexture, RenderBufferDepthFormat.Depth32); - }).toThrow(); - }); - - it("创建失败-不支持高精度深度模版缓冲", () => { - expect(() => { - rhi.canIUse.mockReturnValueOnce(false); - new RenderTarget(engine, width, height, renderColorTexture, RenderBufferDepthFormat.Depth32Stencil8); - }).toThrow(); - }); - - it("创建失败-不支持MRT", () => { - expect(() => { - rhi.canIUse.mockReturnValueOnce(false); - new RenderTarget(engine, width, height, [renderColorTexture, renderColorTexture2]); - }).toThrow(); - }); - - // it("创建失败-不支持MRT+Cube+[,MSAA]", () => { - // expect(() => { - // const cubeRenderColorTexture = new TextureCube(engine, width); - // new RenderTarget(engine, width, height, [renderColorTexture, cubeRenderColorTexture]); - // }).toThrow(); - // }); - - it("创建降级-MSAA自动降级", () => { - rhi.capability._maxAntiAliasing = 1; - - const renderTarget = new RenderTarget(engine, width, height, renderColorTexture, undefined, 2); - - expect(renderTarget.antiAliasing).toBe(1); - }); - - it("销毁", () => { - const renderTarget = new RenderTarget(engine, width, height, renderColorTexture); - - expect(renderTarget.colorTextureCount).toBe(1); - expect(renderTarget.getColorTexture()).toBe(renderColorTexture); - - renderTarget.destroy(); - - expect(renderTarget.colorTextureCount).toBe(0); - expect(renderTarget.getColorTexture()).toBeUndefined(); - }); - }); -}); diff --git a/packages/core/tests/texture/Texture2D.test.ts b/packages/core/tests/texture/Texture2D.test.ts deleted file mode 100644 index a65bcd87a7..0000000000 --- a/packages/core/tests/texture/Texture2D.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -// @ts-nocheck -import { Texture2D, TextureFormat } from "../../src/texture"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; - -describe("Texture2D", () => { - const width = 1024; - const height = 1024; - - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - const rhi = engine._hardwareRenderer; - const isWebGL2 = rhi.isWebGL2; - - beforeEach(() => { - rhi._isWebGL2 = isWebGL2; - }); - - describe("格式测试", () => { - it("不支持浮点纹理", () => { - expect(() => { - rhi.canIUse.mockReturnValueOnce(false); - new Texture2D(engine, width, height, TextureFormat.R32G32B32A32); - }).toThrow(); - }); - it("引擎不支持的格式", () => { - expect(() => { - new Texture2D(engine, width, height, 1234567); - }).toThrow(); - }); - }); - - describe("mipmap", () => { - it("webgl2 支持非2次幂开启 mipmap ", () => { - rhi._isWebGL2 = true; - - const texture1 = new Texture2D(engine, 100, 100); - const texture2 = new Texture2D(engine, 100, 100, undefined, true); - - expect(texture1.mipmapCount).not.toBe(1); - expect(texture2.mipmapCount).not.toBe(1); - }); - it("关闭 mipmap 成功", () => { - const texture = new Texture2D(engine, width, height, undefined, false); - - expect(texture.mipmapCount).toBe(1); - }); - it("webgl1 开启 mipmap 失败自动降级 - 非2次幂图片", () => { - rhi._isWebGL2 = false; - - const texture1 = new Texture2D(engine, 100, 100); - const texture2 = new Texture2D(engine, 100, 100, undefined, true); - - expect(texture1.mipmapCount).toBe(1); - expect(texture2.mipmapCount).toBe(1); - }); - }); - - describe("设置颜色缓冲", () => { - const texture = new Texture2D(engine, width, height); - const buffer = new Uint8Array(width * height * 4); - - it("默认匹配大小", () => { - expect(() => { - texture.setPixelBuffer(buffer); - }).not.toThrow(); - }); - it("设置 mip 数据", () => { - expect(() => { - texture.setPixelBuffer(buffer, 1); - }).not.toThrow(); - }); - it("手动设置偏移和宽高", () => { - expect(() => { - texture.setPixelBuffer(buffer, 1, 0, 0, width, height); - }).not.toThrow(); - }); - it("浮点纹理写入数据", () => { - expect(() => { - const texture = new Texture2D(engine, width, height, TextureFormat.R32G32B32A32); - const buffer = new Float32Array(4); - - texture.setPixelBuffer(buffer); - texture.setPixelBuffer(buffer, 1, 0, 0, 1, 1); - }).not.toThrow(); - }); - }); - - describe("读取颜色缓冲", () => { - it("异常-无法读取压缩纹理", () => { - expect(() => { - const texture = new Texture2D(engine, width, height, TextureFormat.ETC2_RGBA8); - const buffer = new Uint8Array(4); - - texture.getPixelBuffer(0, 0, 1, 1, buffer); - }).toThrow(); - }); - it("读取成功", () => { - const texture = new Texture2D(engine, width, height); - const buffer = new Uint8Array(4); - - texture.setPixelBuffer(new Uint8Array([1, 2, 3, 4]), 0, 5, 0, 1, 1); - texture.getPixelBuffer(5, 0, 1, 1, buffer); - - expect(buffer[0]).toBe(1); - expect(buffer[1]).toBe(2); - expect(buffer[2]).toBe(3); - expect(buffer[3]).toBe(4); - }); - }); -}); diff --git a/packages/core/tests/texture/TextureCubeMap.test.ts b/packages/core/tests/texture/TextureCubeMap.test.ts deleted file mode 100644 index bf325bce0e..0000000000 --- a/packages/core/tests/texture/TextureCubeMap.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -// @ts-nocheck -import { TextureCubeFace, TextureCube, TextureFormat } from "../../src/texture"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; - -describe("TextureCube", () => { - const width = 1024; - const height = 1024; - const size = 1024; - - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - const rhi = engine._hardwareRenderer; - const isWebGL2 = rhi.isWebGL2; - - beforeEach(() => { - rhi._isWebGL2 = isWebGL2; - }); - - describe("格式测试", () => { - it("不支持浮点纹理", () => { - expect(() => { - rhi.canIUse.mockReturnValueOnce(false); - new TextureCube(engine, size, TextureFormat.R32G32B32A32); - }).toThrow(); - }); - it("引擎不支持的格式", () => { - expect(() => { - new TextureCube(engine, size, 1234567); - }).toThrow(); - }); - }); - - describe("mipmap", () => { - it("webgl2 支持非2次幂开启 mipmap ", () => { - rhi._isWebGL2 = true; - - const texture1 = new TextureCube(engine, 100); - const texture2 = new TextureCube(engine, 100, undefined, true); - - expect(texture1.mipmapCount).not.toBe(1); - expect(texture2.mipmapCount).not.toBe(1); - }); - it("关闭 mipmap 成功", () => { - const texture = new TextureCube(engine, size, undefined, false); - - expect(texture.mipmapCount).toBe(1); - }); - it("webgl1 开启 mipmap 失败自动降级 - 非2次幂图片", () => { - rhi._isWebGL2 = false; - - const texture1 = new TextureCube(engine, 100); - const texture2 = new TextureCube(engine, 100, undefined, true); - - expect(texture1.mipmapCount).toBe(1); - expect(texture2.mipmapCount).toBe(1); - }); - }); - - // todo: dom test - - describe("设置颜色缓冲", () => { - const texture = new TextureCube(engine, size); - const buffer = new Uint8Array(width * height * 4); - - it("默认匹配大小", () => { - expect(() => { - texture.setPixelBuffer(TextureCubeFace.PositiveX, buffer); - }).not.toThrow(); - }); - it("设置 mip 数据", () => { - expect(() => { - texture.setPixelBuffer(TextureCubeFace.PositiveX, buffer, 0); - }).not.toThrow(); - }); - it("手动设置偏移和宽高", () => { - expect(() => { - texture.setPixelBuffer(TextureCubeFace.PositiveX, buffer, 0, 0, 0, width, height); - }).not.toThrow(); - }); - it("设置cube的不同面", () => { - expect(() => { - texture.setPixelBuffer(TextureCubeFace.PositiveX, buffer, 0, 0, 0, width, height); - texture.setPixelBuffer(TextureCubeFace.NegativeX, buffer, 0, 0, 0, width, height); - texture.setPixelBuffer(TextureCubeFace.PositiveY, buffer, 0, 0, 0, width, height); - texture.setPixelBuffer(TextureCubeFace.NegativeY, buffer, 0, 0, 0, width, height); - texture.setPixelBuffer(TextureCubeFace.PositiveZ, buffer, 0, 0, 0, width, height); - texture.setPixelBuffer(TextureCubeFace.NegativeZ, buffer, 0, 0, 0, width, height); - }).not.toThrow(); - }); - - it("浮点纹理写入数据", () => { - expect(() => { - const texture = new TextureCube(engine, size, TextureFormat.R32G32B32A32); - const buffer = new Float32Array(4); - - texture.setPixelBuffer(TextureCubeFace.PositiveX, buffer); - texture.setPixelBuffer(TextureCubeFace.PositiveX, buffer, 1, 0, 0, 1, 1); - }).not.toThrow(); - }); - }); - - describe("读取颜色缓冲", () => { - it("异常-无法读取压缩纹理", () => { - expect(() => { - const texture = new TextureCube(engine, size, TextureFormat.ETC2_RGBA8); - const buffer = new Uint8Array(4); - - texture.getPixelBuffer(TextureCubeFace.PositiveX, 0, 0, 1, 1, buffer); - }).toThrow(); - }); - it("读取成功", () => { - const texture = new TextureCube(engine, size); - const buffer = new Uint8Array(4); - - texture.setPixelBuffer(TextureCubeFace.PositiveX, new Uint8Array([1, 1, 1, 1]), 0, 0, 0, 1, 1); - texture.setPixelBuffer(TextureCubeFace.NegativeX, new Uint8Array([2, 2, 2, 2]), 0, 0, 0, 1, 1); - texture.setPixelBuffer(TextureCubeFace.PositiveY, new Uint8Array([3, 3, 3, 3]), 0, 0, 0, 1, 1); - texture.setPixelBuffer(TextureCubeFace.NegativeY, new Uint8Array([4, 4, 4, 4]), 0, 0, 0, 1, 1); - texture.setPixelBuffer(TextureCubeFace.PositiveZ, new Uint8Array([5, 5, 5, 5]), 0, 0, 0, 1, 1); - texture.setPixelBuffer(TextureCubeFace.NegativeZ, new Uint8Array([6, 6, 6, 6]), 0, 0, 0, 1, 1); - - texture.getPixelBuffer(TextureCubeFace.PositiveX, 0, 0, 1, 1, buffer); - expect(buffer[0]).toBe(1); - expect(buffer[1]).toBe(1); - expect(buffer[2]).toBe(1); - expect(buffer[3]).toBe(1); - texture.getPixelBuffer(TextureCubeFace.NegativeX, 0, 0, 1, 1, buffer); - expect(buffer[0]).toBe(2); - expect(buffer[1]).toBe(2); - expect(buffer[2]).toBe(2); - expect(buffer[3]).toBe(2); - texture.getPixelBuffer(TextureCubeFace.PositiveY, 0, 0, 1, 1, buffer); - expect(buffer[0]).toBe(3); - expect(buffer[1]).toBe(3); - expect(buffer[2]).toBe(3); - expect(buffer[3]).toBe(3); - texture.getPixelBuffer(TextureCubeFace.NegativeY, 0, 0, 1, 1, buffer); - expect(buffer[0]).toBe(4); - expect(buffer[1]).toBe(4); - expect(buffer[2]).toBe(4); - expect(buffer[3]).toBe(4); - texture.getPixelBuffer(TextureCubeFace.PositiveZ, 0, 0, 1, 1, buffer); - expect(buffer[0]).toBe(5); - expect(buffer[1]).toBe(5); - expect(buffer[2]).toBe(5); - expect(buffer[3]).toBe(5); - texture.getPixelBuffer(TextureCubeFace.NegativeZ, 0, 0, 1, 1, buffer); - expect(buffer[0]).toBe(6); - expect(buffer[1]).toBe(6); - expect(buffer[2]).toBe(6); - expect(buffer[3]).toBe(6); - }); - }); -}); diff --git a/packages/loader/tests/JSONLoader.test.ts b/packages/loader/tests/JSONLoader.test.ts deleted file mode 100644 index 6223d6b7c3..0000000000 --- a/packages/loader/tests/JSONLoader.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import "../src/JSONLoader"; -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; - -describe("text loader test", () => { - it("text loader test", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const promise = engine.resourceManager.load( - "https://gw.alipayobjects.com/os/bmw-prod/73cba7a4-221b-4e32-8db6-c87968cf7ce0.json" - ); - return expect(promise).resolves.toEqual({ - info: "test request" - }); - }); -}); diff --git a/packages/loader/tests/TextLoader.test.ts b/packages/loader/tests/TextLoader.test.ts deleted file mode 100644 index 96138c6664..0000000000 --- a/packages/loader/tests/TextLoader.test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { WebGLEngine } from "../../rhi-webgl/src/WebGLEngine"; -import "../src/TextLoader"; - -describe("text loader test", () => { - it("text loader test", () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const promise = engine.resourceManager.load( - "https://gw.alipayobjects.com/os/bmw-prod/d64cb568-bf86-41f0-8c9e-d1be9424bd98.txt" - ); - return expect(promise).resolves.toEqual("test request"); - }); -}); diff --git a/packages/loader/tests/gltf/Util.test.ts b/packages/loader/tests/gltf/Util.test.ts deleted file mode 100644 index ae8cd14964..0000000000 --- a/packages/loader/tests/gltf/Util.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { GLTFUtil } from "../../src/gltf/GLTFUtil"; -describe("utils test", () => { - it("test base64", () => { - const base64 = "data:image/png;base64,iVBORw0"; - expect(GLTFUtil.parseRelativeUrl("any", base64)).toEqual(base64); - }); - - it("test http and https", () => { - const http = "http://123.com"; - const https = "https://123.com"; - expect(GLTFUtil.parseRelativeUrl("any", http)).toEqual(http); - expect(GLTFUtil.parseRelativeUrl("any", https)).toEqual(https); - }); - - it("test relative", () => { - const gltf = "/static/model/DamangedHelmet/DamagedHelmet.gltf"; - const bin = "DamagedHelmet.bin"; - expect(GLTFUtil.parseRelativeUrl(gltf, bin)).toEqual("/static/model/DamangedHelmet/DamagedHelmet.bin"); - }); -}); diff --git a/packages/loader/tests/gltf/parser.test.ts b/packages/loader/tests/gltf/parser.test.ts deleted file mode 100644 index 812a069850..0000000000 --- a/packages/loader/tests/gltf/parser.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Color } from "@oasis-engine/math"; -import { PBRMaterial } from "../../../core/src/material/PBRMaterial"; -import { PBRSpecularMaterial } from "../../../core/src/material/PBRSpecularMaterial"; -import { WebGLEngine } from "../../../rhi-webgl/src/WebGLEngine"; -import "../../src/gltf/extensions/KHR_materials_pbrSpecularGlossiness"; -import { GLTFParser } from "../../src/gltf/GLTFParser"; -import { GLTFResource } from "../../src/gltf/GLTFResource"; -import { AnimationParser } from "../../src/gltf/parser/AnimationParser"; -import { EntityParser } from "../../src/gltf/parser/EntityParser"; -import { MaterialParser } from "../../src/gltf/parser/MaterialParser"; -import { MeshParser } from "../../src/gltf/parser/MeshParser"; -import { SceneParser } from "../../src/gltf/parser/SceneParser"; -import { SkinParser } from "../../src/gltf/parser/SkinParser"; -import { Validator } from "../../src/gltf/parser/Validator"; -import "../../src/GLTFLoader"; -import gltfJson from "./test.json"; - -describe("AnimationClipLoader Test", () => { - it("parser", async () => { - const engine = new WebGLEngine(document.createElement("canvas")); - const resource = new GLTFResource(engine); - resource.gltf = gltfJson as any; - resource.buffers = [new ArrayBuffer(100)]; - resource.textures = []; - - // @ts-ignore - const parser = new GLTFParser([ - Validator, - MaterialParser, - MeshParser, - EntityParser, - SkinParser, - AnimationParser, - SceneParser - ]); - - await parser.parse(resource); - - // entites - expect(resource.entities.length).toEqual(1); - - // materials - const { materials } = resource; - expect(materials.length).toEqual(2); - // @ts-ignore - const material = materials[0]; - expect(material.name).toEqual("AnimatedCube"); - expect(typeof material.baseTexture === "undefined").toEqual(true); - expect(Color.equals(material.baseColor, new Color(1, 0, 0, 1))).toEqual(true); - expect(material.isTransparent).toEqual(true); - expect(material.renderFace).toEqual(2); - // @ts-ignore - const specularMaterial = materials[1]; - expect(specularMaterial.name).toEqual("2256_Avocado_d"); - expect(typeof specularMaterial.baseTexture !== "undefined").toEqual(false); - expect(Color.equals(specularMaterial.baseColor, new Color(1, 1, 1, 1))).toEqual(true); - expect(specularMaterial.isTransparent).toEqual(false); - expect(specularMaterial.renderFace).toEqual(0); - - // meshes - const modleMesh = resource.meshes[0][0]; - expect(modleMesh.name === "AnimatedCube").toEqual(true); - - // skin - expect(resource.skins === undefined).toEqual(true); - - // animation - const { animations } = resource; - expect(animations.length === 1).toEqual(true); - const animation = animations[0]; - expect(animation.name === "animation_AnimatedCube").toEqual(true); - expect(animation.curveBindings.length).toEqual(1); - }); -}); diff --git a/packages/loader/tests/gltf/test.json b/packages/loader/tests/gltf/test.json deleted file mode 100644 index 08bb00814e..0000000000 --- a/packages/loader/tests/gltf/test.json +++ /dev/null @@ -1,298 +0,0 @@ -{ - "accessors": [ - { - "bufferView": 0, - "byteOffset": 0, - "componentType": 5126, - "count": 3, - "max": [ - 2 - ], - "min": [ - 0 - ], - "type": "SCALAR" - }, - { - "bufferView": 1, - "byteOffset": 0, - "componentType": 5126, - "count": 3, - "max": [ - 0, - 1, - 0, - 1 - ], - "min": [ - 0, - -8.742278e-8, - 0, - -1 - ], - "type": "VEC4" - }, - { - "bufferView": 2, - "byteOffset": 0, - "componentType": 5123, - "count": 36, - "max": [ - 35 - ], - "min": [ - 0 - ], - "type": "SCALAR" - }, - { - "bufferView": 3, - "byteOffset": 0, - "componentType": 5126, - "count": 36, - "max": [ - 1, - 1, - 1.000001 - ], - "min": [ - -1, - -1, - -1 - ], - "type": "VEC3" - }, - { - "bufferView": 4, - "byteOffset": 0, - "componentType": 5126, - "count": 36, - "max": [ - 1, - 1, - 1 - ], - "min": [ - -1, - -1, - -1 - ], - "type": "VEC3" - }, - { - "bufferView": 5, - "byteOffset": 0, - "componentType": 5126, - "count": 36, - "max": [ - 1, - 0, - 0, - 1 - ], - "min": [ - 0, - 0, - -1, - -1 - ], - "type": "VEC4" - }, - { - "bufferView": 6, - "byteOffset": 0, - "componentType": 5126, - "count": 36, - "max": [ - 1, - 1 - ], - "min": [ - -1, - -1 - ], - "type": "VEC2" - } - ], - "extensionsUsed":[ - "KHR_materials_pbrSpecularGlossiness" - ], - "animations": [ - { - "channels": [ - { - "sampler": 0, - "target": { - "node": 0, - "path": "rotation" - } - } - ], - "name": "animation_AnimatedCube", - "samplers": [ - { - "input": 0, - "interpolation": "LINEAR", - "output": 1 - } - ] - } - ], - "asset": { - "generator": "VKTS glTF 2.0 exporter", - "version": "2.0" - }, - "bufferViews": [ - { - "buffer": 0, - "byteLength": 12, - "byteOffset": 0 - }, - { - "buffer": 0, - "byteLength": 48, - "byteOffset": 12 - }, - { - "buffer": 0, - "byteLength": 72, - "byteOffset": 60, - "target": 34963 - }, - { - "buffer": 0, - "byteLength": 432, - "byteOffset": 132, - "target": 34962 - }, - { - "buffer": 0, - "byteLength": 432, - "byteOffset": 564, - "target": 34962 - }, - { - "buffer": 0, - "byteLength": 576, - "byteOffset": 996, - "target": 34962 - }, - { - "buffer": 0, - "byteLength": 288, - "byteOffset": 1572, - "target": 34962 - } - ], - "buffers": [ - { - "byteLength": 1860, - "uri": "https://gw.alipayobjects.com/os/OasisHub/309000013/6807/AnimatedCube.bin" - } - ], - "images": [ - { - "bufferView": 0 - }, - { - "bufferView": 0 - }, - { - "bufferView": 0 - }, - { - "bufferView": 0 - }, - { - "bufferView": 0 - }, - { - "bufferView": 0 - } - ], - "materials": [ - { - "name": "AnimatedCube", - "pbrMetallicRoughness": { - "baseColorTexture": { - "index": 0 - }, - "baseColorFactor": [1, 0, 0, 1], - "metallicRoughnessTexture": { - "index": 1 - } - }, - "alphaMode": "BLEND", - "doubleSided": true - }, - { - "name": "2256_Avocado_d", - "pbrMetallicRoughness": { - "metallicRoughnessTexture": { - "index": 1 - } - }, - "extensions":{ - "KHR_materials_pbrSpecularGlossiness":{ - "diffuseTexture":{ - "index":3 - }, - "specularGlossinessTexture":{ - "index":4 - } - } - } - } - ], - "meshes": [ - { - "name": "AnimatedCube", - "primitives": [ - { - "attributes": { - "NORMAL": 4, - "POSITION": 3, - "TANGENT": 5, - "TEXCOORD_0": 6 - }, - "indices": 2, - "material": 0, - "mode": 4 - } - ] - } - ], - "nodes": [ - { - "mesh": 0, - "name": "AnimatedCube", - "rotation": [ - 0, - -1, - 0, - 0 - ] - } - ], - "samplers": [ - {} - ], - "scene": 0, - "scenes": [ - { - "nodes": [ - 0 - ] - } - ], - "textures": [ - { - "sampler": 0, - "source": 0 - }, - { - "sampler": 0, - "source": 1 - } - ] -} \ No newline at end of file diff --git a/packages/math/tests/BoundingBox.test.ts b/packages/math/tests/BoundingBox.test.ts deleted file mode 100644 index 6d04baac2e..0000000000 --- a/packages/math/tests/BoundingBox.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { BoundingBox } from "../src/BoundingBox"; -import { BoundingSphere } from "../src/BoundingSphere"; -import { Matrix } from "../src/Matrix"; -import { Vector3 } from "../src/Vector3"; - -describe("BoundingBox test", () => { - it("Constructor", () => { - const box1 = new BoundingBox(); - const box2 = new BoundingBox(); - const box3 = new BoundingBox(); - - // Create a same box by different param. - BoundingBox.fromCenterAndExtent(new Vector3(0, 0, 0), new Vector3(1, 1, 1), box1); - - const points = [ - new Vector3(0, 0, 0), - new Vector3(-1, 0, 0), - new Vector3(1, 0, 0), - new Vector3(0, 1, 0), - new Vector3(0, 1, 1), - new Vector3(1, 0, 1), - new Vector3(0, 0.5, 0.5), - new Vector3(0, -0.5, 0.5), - new Vector3(0, -1, 0.5), - new Vector3(0, 0, -1) - ]; - BoundingBox.fromPoints(points, box2); - - const sphere = new BoundingSphere(new Vector3(0, 0, 0), 1); - BoundingBox.fromSphere(sphere, box3); - - const { min: min1, max: max1 } = box1; - const { min: min2, max: max2 } = box2; - const { min: min3, max: max3 } = box3; - - expect(Vector3.equals(min1, min2)).toEqual(true); - expect(Vector3.equals(max1, max2)).toEqual(true); - expect(Vector3.equals(min1, min3)).toEqual(true); - expect(Vector3.equals(max1, max3)).toEqual(true); - expect(Vector3.equals(min2, min3)).toEqual(true); - expect(Vector3.equals(max2, max3)).toEqual(true); - }); - - it("transform", () => { - const box = new BoundingBox(new Vector3(-1, -1, -1), new Vector3(1, 1, 1)); - const matrix = new Matrix(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 1, 0.5, -1, 1); - const newBox = new BoundingBox(); - BoundingBox.transform(box, matrix, newBox); - box.transform(matrix); - - const newMin = new Vector3(-1, -1.5, -3); - const newMax = new Vector3(3, 2.5, 1); - expect(Vector3.equals(newBox.min, newMin)).toEqual(true); - expect(Vector3.equals(newBox.max, newMax)).toEqual(true); - expect(Vector3.equals(box.min, newMin)).toEqual(true); - expect(Vector3.equals(box.max, newMax)).toEqual(true); - }); - - it("merge", () => { - const box1 = new BoundingBox(new Vector3(-1, -1, -1), new Vector3(2, 2, 2)); - const box2 = new BoundingBox(new Vector3(-2, -0.5, -2), new Vector3(3, 0, 3)); - const box = new BoundingBox(); - - BoundingBox.merge(box1, box2, box); - expect(Vector3.equals(new Vector3(-2, -1, -2), box.min)).toEqual(true); - expect(Vector3.equals(new Vector3(3, 2, 3), box.max)).toEqual(true); - }); - - it("getCenter", () => { - const box = new BoundingBox(new Vector3(-1, -1, -1), new Vector3(3, 3, 3)); - const center = new Vector3(); - - box.getCenter(center); - expect(Vector3.equals(new Vector3(1, 1, 1), center)).toEqual(true); - }); - - it("getExtent", () => { - const box = new BoundingBox(new Vector3(-1, -1, -1), new Vector3(3, 3, 3)); - const extent = new Vector3(); - - box.getExtent(extent); - expect(Vector3.equals(new Vector3(2, 2, 2), extent)).toEqual(true); - }); - - it("getCorners", () => { - const min = new Vector3(-1, -1, -1); - const max = new Vector3(3, 3, 3); - const { x: minX, y: minY, z: minZ } = min; - const { x: maxX, y: maxY, z: maxZ } = max; - const expectedCorners = [ - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3() - ]; - expectedCorners[0].setValue(minX, maxY, maxZ); - expectedCorners[1].setValue(maxX, maxY, maxZ); - expectedCorners[2].setValue(maxX, minY, maxZ); - expectedCorners[3].setValue(minX, minY, maxZ); - expectedCorners[4].setValue(minX, maxY, minZ); - expectedCorners[5].setValue(maxX, maxY, minZ); - expectedCorners[6].setValue(maxX, minY, minZ); - expectedCorners[7].setValue(minX, minY, minZ); - - const box = new BoundingBox(min, max); - const corners = [ - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3() - ]; - - box.getCorners(corners); - for (let i = 0; i < 8; ++i) { - expect(Vector3.equals(corners[i], expectedCorners[i])).toEqual(true); - } - }); - - it("clone", () => { - const a = new BoundingBox(new Vector3(0, 0, 0), new Vector3(1, 1, 1)); - const b = a.clone(); - expect(Vector3.equals(a.min, b.min)).toEqual(true); - expect(Vector3.equals(a.max, b.max)).toEqual(true); - }); - - it("cloneTo", () => { - const a = new BoundingBox(new Vector3(0, 0, 0), new Vector3(1, 1, 1)); - const out = new BoundingBox(); - a.cloneTo(out); - expect(Vector3.equals(a.min, out.min)).toEqual(true); - expect(Vector3.equals(a.max, out.max)).toEqual(true); - }); -}); diff --git a/packages/math/tests/BoundingFrustum.test.ts b/packages/math/tests/BoundingFrustum.test.ts deleted file mode 100644 index 3c2b8842b8..0000000000 --- a/packages/math/tests/BoundingFrustum.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { BoundingBox } from "../src/BoundingBox"; -import { BoundingFrustum } from "../src/BoundingFrustum"; -import { BoundingSphere } from "../src/BoundingSphere"; -import { Matrix } from "../src/Matrix"; -import { Vector3 } from "../src/Vector3"; - -describe("BoundingFrustum test", () => { - const viewMatrix = new Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -20, 1); - const projectionMatrix = new Matrix( - 0.03954802080988884, - 0, - 0, - 0, - 0, - 0.10000000149011612, - 0, - 0, - 0, - 0, - -0.0200200192630291, - 0, - -0, - -0, - -1.0020020008087158, - 1 - ); - const vpMatrix = new Matrix(); - Matrix.multiply(projectionMatrix, viewMatrix, vpMatrix); - const frustum = new BoundingFrustum(vpMatrix); - - it("intersectsBox", () => { - const box1 = new BoundingBox(new Vector3(-2, -2, -2), new Vector3(2, 2, 2)); - const flag1 = frustum.intersectsBox(box1); - expect(flag1).toEqual(true); - - const box2 = new BoundingBox(new Vector3(-32, -2, -2), new Vector3(-28, 2, 2)); - const flag2 = frustum.intersectsBox(box2); - expect(flag2).toEqual(false); - }); - - it("intersectsSphere", () => { - const box1 = new BoundingBox(new Vector3(-2, -2, -2), new Vector3(2, 2, 2)); - const sphere1 = new BoundingSphere(); - BoundingSphere.fromBox(box1, sphere1); - const flag1 = frustum.intersectsSphere(sphere1); - expect(flag1).toEqual(true); - - const box2 = new BoundingBox(new Vector3(-32, -2, -2), new Vector3(-28, 2, 2)); - const sphere2 = new BoundingSphere(); - BoundingSphere.fromBox(box2, sphere2); - const flag2 = frustum.intersectsSphere(sphere2); - expect(flag2).toEqual(false); - }); - - it("clone", () => { - const a = new BoundingFrustum(projectionMatrix); - const b = a.clone(); - - for (let i = 0; i < 6; ++i) { - const aPlane = a.getPlane(i); - const bPlane = b.getPlane(i); - - expect(aPlane.distance).toEqual(bPlane.distance); - expect(Vector3.equals(aPlane.normal, bPlane.normal)).toEqual(true); - } - }); - - it("cloneTo", () => { - const a = new BoundingFrustum(projectionMatrix); - const out = new BoundingFrustum(); - a.cloneTo(out); - - for (let i = 0; i < 6; ++i) { - const aPlane = a.getPlane(i); - const outPlane = out.getPlane(i); - - expect(aPlane.distance).toEqual(outPlane.distance); - expect(Vector3.equals(aPlane.normal, outPlane.normal)).toEqual(true); - } - }); - - it("calculateFromMatrix", () => { - const a = new BoundingFrustum(); - a.calculateFromMatrix(vpMatrix); - - for (let i = 0; i < 6; ++i) { - const aPlane = a.getPlane(i); - const bPlane = frustum.getPlane(i); - - expect(aPlane.distance).toEqual(bPlane.distance); - expect(Vector3.equals(aPlane.normal, bPlane.normal)).toEqual(true); - } - }); -}); diff --git a/packages/math/tests/BoundingSphere.test.ts b/packages/math/tests/BoundingSphere.test.ts deleted file mode 100644 index 7d99e69683..0000000000 --- a/packages/math/tests/BoundingSphere.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { BoundingBox } from "../src/BoundingBox"; -import { BoundingSphere } from "../src/BoundingSphere"; -import { Vector3 } from "../src/Vector3"; - -describe("BoundingSphere", () => { - it("Constructor", () => { - const sphere1 = new BoundingSphere(); - const sphere2 = new BoundingSphere(); - - // Create a same sphere by different param. - const points = [ - new Vector3(0, 0, 0), - new Vector3(-1, 0, 0), - new Vector3(0, 0, 0), - new Vector3(0, 1, 0), - new Vector3(1, 1, 1), - new Vector3(0, 0, 1), - new Vector3(-1, -0.5, -0.5), - new Vector3(0, -0.5, -0.5), - new Vector3(1, 0, -1), - new Vector3(0, -1, 0) - ]; - BoundingSphere.fromPoints(points, sphere1); - - const box = new BoundingBox(new Vector3(-1, -1, -1), new Vector3(1, 1, 1)); - BoundingSphere.fromBox(box, sphere2); - - const { center: center1, radius: radius1 } = sphere1; - const { center: center2, radius: radius2 } = sphere2; - expect(Vector3.equals(center1, center2)).toEqual(true); - expect(radius1).toEqual(radius2); - }); - - it("clone", () => { - const a = new BoundingSphere(new Vector3(0, 0, 0), 3); - const b = a.clone(); - expect(Vector3.equals(a.center, b.center)).toEqual(true); - expect(a.radius).toEqual(b.radius); - }); - - it("cloneTo", () => { - const a = new BoundingSphere(new Vector3(0, 0, 0), 3); - const out = new BoundingSphere(); - a.cloneTo(out); - expect(Vector3.equals(a.center, out.center)).toEqual(true); - expect(a.radius).toEqual(out.radius); - }); -}); diff --git a/packages/math/tests/CollisionUtil.test.ts b/packages/math/tests/CollisionUtil.test.ts deleted file mode 100644 index 78993c948d..0000000000 --- a/packages/math/tests/CollisionUtil.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { PlaneIntersectionType } from "../src/enums/PlaneIntersectionType"; -import { ContainmentType } from "../src/enums/ContainmentType"; -import { CollisionUtil } from "../src/CollisionUtil"; -import { Plane } from "../src/Plane"; -import { Vector3 } from "../src/Vector3"; -import { BoundingBox } from "../src/BoundingBox"; -import { BoundingSphere } from "../src/BoundingSphere"; -import { Ray } from "../src/Ray"; -import { Matrix } from "../src/Matrix"; -import { BoundingFrustum } from "../src/BoundingFrustum"; - -describe("CollisionUtil", () => { - const plane = new Plane(new Vector3(0, 1, 0), -5); - const viewMatrix = new Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -20, 1); - const projectionMatrix = new Matrix(0.03954802080988884, 0, 0, 0, 0, 0.10000000149011612, 0, 0, 0, 0, -0.0200200192630291, 0, -0, -0, -1.0020020008087158, 1); - const vpMatrix = new Matrix(); - Matrix.multiply(projectionMatrix, viewMatrix, vpMatrix); - const frustum = new BoundingFrustum(vpMatrix); - - it("distancePlaneAndPoint", () => { - const point = new Vector3(0, 10, 0); - - const distance = CollisionUtil.distancePlaneAndPoint(plane, point); - expect(distance).toEqual(5); - }); - - it("intersectsPlaneAndPoint", () => { - const point1 = new Vector3(0, 10, 0); - const point2 = new Vector3(2, 5, -9); - const point3 = new Vector3(0, 3, 0); - - const intersection1 = CollisionUtil.intersectsPlaneAndPoint(plane, point1); - const intersection2 = CollisionUtil.intersectsPlaneAndPoint(plane, point2); - const intersection3 = CollisionUtil.intersectsPlaneAndPoint(plane, point3); - expect(intersection1).toEqual(PlaneIntersectionType.Front); - expect(intersection2).toEqual(PlaneIntersectionType.Intersecting); - expect(intersection3).toEqual(PlaneIntersectionType.Back); - }); - - it("intersectsPlaneAndBox", () => { - const box1 = new BoundingBox(new Vector3(-1, 6, -2), new Vector3(1, 10, 3)); - const box2 = new BoundingBox(new Vector3(-1, 5, -2), new Vector3(1, 10, 3)); - const box3 = new BoundingBox(new Vector3(-1, 4, -2), new Vector3(1, 5, 3)); - const box4 = new BoundingBox(new Vector3(-1, -5, -2), new Vector3(1, 4.9, 3)); - - const intersection1 = CollisionUtil.intersectsPlaneAndBox(plane, box1); - const intersection2 = CollisionUtil.intersectsPlaneAndBox(plane, box2); - const intersection3 = CollisionUtil.intersectsPlaneAndBox(plane, box3); - const intersection4 = CollisionUtil.intersectsPlaneAndBox(plane, box4); - expect(intersection1).toEqual(PlaneIntersectionType.Front); - expect(intersection2).toEqual(PlaneIntersectionType.Intersecting); - expect(intersection3).toEqual(PlaneIntersectionType.Intersecting); - expect(intersection4).toEqual(PlaneIntersectionType.Back); - }); - - it("intersectsPlaneAndSphere", () => { - const sphere1 = new BoundingSphere(new Vector3(0, 8, 0), 2); - const sphere2 = new BoundingSphere(new Vector3(0, 8, 0), 3); - const sphere3 = new BoundingSphere(new Vector3(0, 3, 0), 2); - const sphere4 = new BoundingSphere(new Vector3(0, 0, 0), 2); - - const intersection1 = CollisionUtil.intersectsPlaneAndSphere(plane, sphere1); - const intersection2 = CollisionUtil.intersectsPlaneAndSphere(plane, sphere2); - const intersection3 = CollisionUtil.intersectsPlaneAndSphere(plane, sphere3); - const intersection4 = CollisionUtil.intersectsPlaneAndSphere(plane, sphere4); - expect(intersection1).toEqual(PlaneIntersectionType.Front); - expect(intersection2).toEqual(PlaneIntersectionType.Intersecting); - expect(intersection3).toEqual(PlaneIntersectionType.Intersecting); - expect(intersection4).toEqual(PlaneIntersectionType.Back); - }); - - it("intersectsRayAndPlane", () => { - const ray1 = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const ray2 = new Ray(new Vector3(0, 0, 0), new Vector3(0, -1, 0)); - - const distance1 = CollisionUtil.intersectsRayAndPlane(ray1, plane); - const distance2 = CollisionUtil.intersectsRayAndPlane(ray2, plane); - expect(distance1).toEqual(5); - expect(distance2).toEqual(-1); - }); - - it("intersectsRayAndBox", () => { - const ray = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const box1 = new BoundingBox(new Vector3(-1, 3, -1), new Vector3(2, 8, 3)); - const box2 = new BoundingBox(new Vector3(1, 1, 1), new Vector3(2, 2, 2)); - - const distance1 = CollisionUtil.intersectsRayAndBox(ray, box1); - const distance2 = CollisionUtil.intersectsRayAndBox(ray, box2); - expect(distance1).toEqual(3); - expect(distance2).toEqual(-1); - }); - - it("intersectsRayAndSphere", () => { - const ray = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const sphere1 = new BoundingSphere(new Vector3(0, 4, 0), 3); - const sphere2 = new BoundingSphere(new Vector3(0, -5, 0), 4); - - const distance1 = CollisionUtil.intersectsRayAndSphere(ray, sphere1); - const distance2 = CollisionUtil.intersectsRayAndSphere(ray, sphere2); - expect(distance1).toEqual(1); - expect(distance2).toEqual(-1); - }); - - it("intersectsFrustumAndBox", () => { - const box1 = new BoundingBox(new Vector3(-2, -2, -2), new Vector3(2, 2, 2)); - const flag1 = frustum.intersectsBox(box1); - expect(flag1).toEqual(true); - - const box2 = new BoundingBox(new Vector3(-32, -2, -2), new Vector3(-28, 2, 2)); - const flag2 = frustum.intersectsBox(box2); - expect(flag2).toEqual(false); - }); - - it("frustumContainsBox", () => { - const box1 = new BoundingBox(new Vector3(-2, -2, -2), new Vector3(2, 2, 2)); - const box2 = new BoundingBox(new Vector3(-32, -2, -2), new Vector3(-28, 2, 2)); - const box3 = new BoundingBox(new Vector3(-35, -2, -2), new Vector3(-18, 2, 2)); - - const expected1 = CollisionUtil.frustumContainsBox(frustum, box1); - const expected2 = CollisionUtil.frustumContainsBox(frustum, box2); - const expected3 = CollisionUtil.frustumContainsBox(frustum, box3); - expect(expected1).toEqual(ContainmentType.Contains); - expect(expected2).toEqual(ContainmentType.Disjoint); - expect(expected3).toEqual(ContainmentType.Intersects); - }); - - it("frustumContainsSphere", () => { - const sphere1 = new BoundingSphere(new Vector3(0, 0, 0), 2); - const sphere2 = new BoundingSphere(new Vector3(-32, -2, -2), 1); - const sphere3 = new BoundingSphere(new Vector3(-32, -2, -2), 15); - - const expected1 = CollisionUtil.frustumContainsSphere(frustum, sphere1); - const expected2 = CollisionUtil.frustumContainsSphere(frustum, sphere2); - const expected3 = CollisionUtil.frustumContainsSphere(frustum, sphere3); - expect(expected1).toEqual(ContainmentType.Contains); - expect(expected2).toEqual(ContainmentType.Disjoint); - expect(expected3).toEqual(ContainmentType.Intersects); - }); -}); diff --git a/packages/math/tests/Color.test.ts b/packages/math/tests/Color.test.ts deleted file mode 100644 index 224dc1436f..0000000000 --- a/packages/math/tests/Color.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Color } from "../src/Color"; - -describe("Color test", () => { - it("Constructor", () => { - const color1 = new Color(1, 0.5, 0.5, 1); - const color2 = new Color(); - color2.r = 1; - color2.g = 0.5; - color2.b = 0.5; - color2.a = 1; - - expect(Color.equals(color1, color2)).toEqual(true); - }); - - it("setValue", () => { - const color1 = new Color(1, 0.5, 0.5, 1); - const color2 = new Color(); - color2.setValue(1, 0.5, 0.5, 1); - - expect(Color.equals(color1, color2)).toEqual(true); - }); - - it("scale", () => { - const color1 = new Color(0.5, 0.5, 0.5, 0.5); - const color2 = new Color(1, 1, 1, 1); - - color1.scale(2); - expect(color1).toEqual(color2); - - Color.scale(color1, 0.5, color2); - expect(color2).toEqual(new Color(0.5, 0.5, 0.5, 0.5)); - }); - - it("add", () => { - const color1 = new Color(1, 0, 0, 0); - const color2 = new Color(0, 1, 0, 0); - - color1.add(color2); - expect(color1).toEqual(new Color(1, 1, 0, 0)); - - Color.add(color1, new Color(0, 0, 1, 0), color2); - expect(color2).toEqual(new Color(1, 1, 1, 0)); - }); - - it("clone", () => { - const a = new Color(); - const b = a.clone(); - - expect(Color.equals(a, b)).toEqual(true); - }); - - it("cloneTo", () => { - const a = new Color(); - const out = new Color(); - - a.cloneTo(out); - expect(Color.equals(a, out)).toEqual(true); - }); - - it("LinearAndGamma", () => { - const fixColor = (color: Color) => { - color.r = Math.floor(color.r * 1000) / 1000; - color.g = Math.floor(color.g * 1000) / 1000; - color.b = Math.floor(color.b * 1000) / 1000; - }; - - const colorLinear = new Color(); - const colorGamma = new Color(); - const colorNewLinear = new Color(); - - for (let i = 0; i < 100; ++i) { - colorLinear.r = Math.random(); - colorLinear.g = Math.random(); - colorLinear.b = Math.random(); - fixColor(colorLinear); - - colorLinear.toGamma(colorGamma); - colorGamma.toLinear(colorNewLinear); - - fixColor(colorLinear); - fixColor(colorNewLinear); - - expect(Color.equals(colorLinear, colorNewLinear)).toEqual(true); - } - }); -}); diff --git a/packages/math/tests/MathUtil.test.ts b/packages/math/tests/MathUtil.test.ts deleted file mode 100644 index 82a4e87acd..0000000000 --- a/packages/math/tests/MathUtil.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MathUtil } from "../src/MathUtil"; - -describe("MathUtil test", () => { - it("clamp", () => { - expect(MathUtil.clamp(1, 10, 20)).toEqual(10); - expect(MathUtil.clamp(25, 10, 20)).toEqual(20); - expect(MathUtil.clamp(15, 10, 20)).toEqual(15); - }); - - it("equals", () => { - expect(MathUtil.equals(10, 10)).toEqual(true); - - let scale = 0.9; - expect(MathUtil.equals(10, 10 - MathUtil.zeroTolerance * scale)).toEqual(true); - expect(MathUtil.equals(10, 10 + MathUtil.zeroTolerance * scale)).toEqual(true); - - expect(MathUtil.equals(10, 10 - MathUtil.zeroTolerance)).toEqual(true); - expect(MathUtil.equals(10, 10 + MathUtil.zeroTolerance)).toEqual(true); - - scale = 1.2; - expect(MathUtil.equals(10, 10 - MathUtil.zeroTolerance * scale)).toEqual(false); - expect(MathUtil.equals(10, 10 + MathUtil.zeroTolerance * scale)).toEqual(false); - }); - - it("isPowerOf2", () => { - expect(MathUtil.isPowerOf2(16)).toEqual(true); - expect(MathUtil.isPowerOf2(15)).toEqual(false); - }); - - it("radianToDegree", () => { - const d = MathUtil.radianToDegree(Math.PI / 3); - expect(MathUtil.equals(d, 60)).toEqual(true); - }); - - it("degreeToRadian", () => { - const r = MathUtil.degreeToRadian(60); - expect(MathUtil.equals(r, Math.PI / 3)).toEqual(true); - }); -}); diff --git a/packages/math/tests/Matrix.test.ts b/packages/math/tests/Matrix.test.ts deleted file mode 100644 index 8b1241ed4c..0000000000 --- a/packages/math/tests/Matrix.test.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { Matrix } from "../src/Matrix"; -import { Vector3 } from "../src/Vector3"; -import { Quaternion } from "../src/Quaternion"; - -describe("Matrix test", () => { - it("static multiply", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const b = new Matrix(16, 15, 14, 13, 12, 11, 10, 9, 8.88, 7, 6, 5, 4, 3, 2, 1); - const out = new Matrix(); - - Matrix.multiply(a, b, out); - expect( - Matrix.equals( - out, - new Matrix( - 386, - 456.6, - 506.8, - 560, - 274, - 325, - 361.6, - 400, - 162.88, - 195.16000000000003, - 219.304, - 243.52, - 50, - 61.8, - 71.2, - 80 - ) - ) - ).toEqual(true); - }); - - it("static equals", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const b = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const c = new Matrix(16, 15, 14, 13, 12, 11, 10, 9, 8.88, 7, 6, 5, 4, 3, 2, 1); - - expect(Matrix.equals(a, b)).toEqual(true); - expect(Matrix.equals(a, c)).toEqual(false); - }); - - it("static lerp", () => { - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - const b = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - const c = new Matrix(); - Matrix.lerp(a, b, 0.7, c); - - expect(Matrix.equals(a, c)).toEqual(true); - expect(Matrix.equals(b, c)).toEqual(true); - }); - - it("static rotationQuaternion", () => { - const q = new Quaternion(1, 2, 3, 4); - const out = new Matrix(); - - Matrix.rotationQuaternion(q, out); - expect(Matrix.equals(out, new Matrix(-25, 28, -10, 0, -20, -19, 20, 0, 22, 4, -9, 0, 0, 0, 0, 1))).toEqual(true); - }); - - it("static rotationAxisAngle", () => { - const out = new Matrix(); - - Matrix.rotationAxisAngle(new Vector3(0, 1, 0), Math.PI / 3, out); - expect( - Matrix.equals( - out, - new Matrix( - 0.5000000000000001, - 0, - -0.8660254037844386, - 0, - 0, - 1, - 0, - 0, - 0.8660254037844386, - 0, - 0.5000000000000001, - 0, - 0, - 0, - 0, - 1 - ) - ) - ).toEqual(true); - }); - - it("static rotationTranslation", () => { - const q = new Quaternion(1, 0.5, 2, 1); - const v = new Vector3(1, 1, 1); - const out = new Matrix(); - - Matrix.rotationTranslation(q, v, out); - expect(Matrix.equals(out, new Matrix(-7.5, 5, 3, 0, -3, -9, 4, 0, 5, 0, -1.5, 0, 1, 1, 1, 1))).toEqual(true); - }); - - it("static affineTransformation", () => { - const q = new Quaternion(1, 0.5, 2, 1); - const v = new Vector3(1, 1, 1); - const s = new Vector3(1, 0.5, 2); - const out = new Matrix(); - - Matrix.affineTransformation(s, q, v, out); - expect(Matrix.equals(out, new Matrix(-7.5, 5, 3, 0, -1.5, -4.5, 2, 0, 10, 0, -3, 0, 1, 1, 1, 1))).toEqual(true); - }); - - it("static scaling", () => { - const a = new Matrix(); - const out = new Matrix(); - - Matrix.scale(a, new Vector3(1, 2, 0.5), out); - expect(Matrix.equals(out, new Matrix(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1))).toEqual(true); - }); - - it("static translation", () => { - const out = new Matrix(); - const v = new Vector3(1, 2, 0.5); - - Matrix.translation(v, out); - expect(Matrix.equals(out, new Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 0.5, 1))).toEqual(true); - }); - - it("static invert", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const out = new Matrix(); - - Matrix.invert(a, out); - expect( - Matrix.equals( - out, - new Matrix( - -1.1111111111111172, - 1.3703703703703825, - -0.7407407407407528, - 0.1481481481481532, - 0, - -0.5555555555555607, - 1.1111111111111214, - -0.5555555555555607, - 3.3333333333333863, - -5.000000000000064, - 0, - 1.6666666666666867, - -2.222222222222265, - 4.0601851851852375, - -0.3703703703703687, - -1.134259259259275 - ) - ) - ).toEqual(true); - }); - - it("static lookAt", () => { - const out = new Matrix(); - const eye = new Vector3(0, 0, -8); - const target = new Vector3(0, 0, 0); - const up = new Vector3(0, 1, 0); - - Matrix.lookAt(eye, target, up, out); - expect(Matrix.equals(out, new Matrix(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, -8, 1))).toEqual(true); - - eye.setValue(0, 0, 0); - target.setValue(0, 1, -1); - up.setValue(0, 1, 0); - Matrix.lookAt(eye, target, up, out); - expect( - Matrix.equals( - out, - new Matrix( - 1, - 0, - 0, - 0, - 0, - 0.7071067690849304, - -0.7071067690849304, - 0, - 0, - 0.7071067690849304, - 0.7071067690849304, - 0, - 0, - 0, - 0, - 1 - ) - ) - ).toEqual(true); - }); - - it("static ortho", () => { - const out = new Matrix(); - Matrix.ortho(0, 2, -1, 1, 0.1, 100, out); - expect( - Matrix.equals( - out, - new Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -0.02002002002002002, 0, -1, 0, -1.002002002002002, 1) - ) - ).toEqual(true); - }); - - it("static perspective", () => { - const out = new Matrix(); - Matrix.perspective(1, 1.5, 0.1, 100, out); - expect( - Matrix.equals( - out, - new Matrix( - 1.2203251478083013, - 0, - 0, - 0, - 0, - 1.830487721712452, - 0, - 0, - 0, - 0, - -1.002002002002002, - -1, - 0, - 0, - -0.20020020020020018, - 0 - ) - ) - ).toEqual(true); - }); - - it("static rotateAxisAngle", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const out = new Matrix(); - - Matrix.rotateAxisAngle(a, new Vector3(0, 1, 0), Math.PI / 3, out); - expect( - Matrix.equals( - out, - new Matrix( - -7.294228634059947, - -8.439676901250381, - -7.876279441628824, - -8.392304845413264, - 5, - 6, - 7, - 8, - 5.366025403784439, - 7.182050807568878, - 8.357883832488648, - 9.464101615137757, - 13, - 14, - 15, - 16 - ) - ) - ).toEqual(true); - }); - - it("static scale", () => { - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - const out = new Matrix(); - - Matrix.scale(a, new Vector3(1, 2, 0.5), out); - expect(Matrix.equals(out, new Matrix(1, 2, 3, 4, 10, 12, 14, 16, 4.5, 5, 5.5, 6, 13, 14, 15, 16))).toEqual(true); - }); - - it("static translate", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const out = new Matrix(); - - Matrix.translate(a, new Vector3(1, 2, 0.5), out); - expect(Matrix.equals(out, new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 28.5, 33.45, 37.8, 42))).toEqual( - true - ); - }); - - it("static transpose", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const out = new Matrix(); - - Matrix.transpose(a, out); - expect(Matrix.equals(out, new Matrix(1, 5, 9, 13, 2, 6, 10.9, 14, 3.3, 7, 11, 15, 4, 8, 12, 16))).toEqual(true); - }); - - it("setValue", () => { - const a = new Matrix(); - a.setValue(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - - expect(Matrix.equals(a, new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16))).toEqual(true); - }); - - it("setValueByArray", () => { - const a = new Matrix(); - a.setValueByArray([1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16]); - - expect(Matrix.equals(a, new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16))).toEqual(true); - }); - - it("toArray", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const b = []; - a.toArray(b); - const c = new Matrix(); - c.setValueByArray(b); - - expect(Matrix.equals(a, c)).toEqual(true); - }); - - it("clone", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const b = a.clone(); - - expect(Matrix.equals(a, b)).toEqual(true); - }); - - it("cloneTo", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const out = new Matrix(); - - a.cloneTo(out); - expect(Matrix.equals(a, out)).toEqual(true); - }); - - it("multiply", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - const b = new Matrix(16, 15, 14, 13, 12, 11, 10, 9, 8.88, 7, 6, 5, 4, 3, 2, 1); - - a.multiply(b); - expect( - Matrix.equals( - a, - new Matrix( - 386, - 456.6, - 506.8, - 560, - 274, - 325, - 361.6, - 400, - 162.88, - 195.16000000000003, - 219.304, - 243.52, - 50, - 61.8, - 71.2, - 80 - ) - ) - ).toEqual(true); - }); - - it("determinant", () => { - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - expect(a.determinant()).toEqual(0); - }); - - it("decompose", () => { - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - // const a = new Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); - const pos = new Vector3(); - const quat = new Quaternion(); - const scale = new Vector3(); - - a.decompose(pos, quat, scale); - expect(Vector3.equals(pos, new Vector3(13, 14, 15))).toEqual(true); - expect( - Quaternion.equals( - quat, - new Quaternion(0.01879039477474769, -0.09554131404261303, 0.01844761344901482, 0.783179537258594) - ) - ).toEqual(true); - expect(Vector3.equals(scale, new Vector3(3.7416573867739413, 10.488088481701515, 17.91116946723357))).toEqual(true); - }); - - it("getXXX", () => { - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - - // getRotation - const quat = new Quaternion(); - a.getRotation(quat); - expect( - Quaternion.equals( - quat, - new Quaternion(-0.44736068104759547, 0.6882472016116852, -0.3441236008058426, 2.179449471770337) - ) - ).toEqual(true); - - // getScaling - const scale = new Vector3(); - a.getScaling(scale); - expect(Vector3.equals(scale, new Vector3(3.7416573867739413, 10.488088481701515, 17.911169699380327))).toEqual( - true - ); - - // getTranslation - const translation = new Vector3(); - a.getTranslation(translation); - expect(Vector3.equals(translation, new Vector3(13, 14, 15))).toEqual(true); - }); - - it("invert", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - - a.invert(); - expect( - Matrix.equals( - a, - new Matrix( - -1.1111111111111172, - 1.3703703703703825, - -0.7407407407407528, - 0.1481481481481532, - 0, - -0.5555555555555607, - 1.1111111111111214, - -0.5555555555555607, - 3.3333333333333863, - -5.000000000000064, - 0, - 1.6666666666666867, - -2.222222222222265, - 4.0601851851852375, - -0.3703703703703687, - -1.134259259259275 - ) - ) - ).toEqual(true); - }); - - it("rotateAxisAngle", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - - a.rotateAxisAngle(new Vector3(0, 1, 0), Math.PI / 3); - expect( - Matrix.equals( - a, - new Matrix( - -7.294228634059947, - -8.439676901250381, - -7.876279441628824, - -8.392304845413264, - 5, - 6, - 7, - 8, - 5.366025403784439, - 7.182050807568878, - 8.357883832488648, - 9.464101615137757, - 13, - 14, - 15, - 16 - ) - ) - ).toEqual(true); - }); - - it("scale", () => { - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - - a.scale(new Vector3(1, 2, 0.5)); - expect(Matrix.equals(a, new Matrix(1, 2, 3, 4, 10, 12, 14, 16, 4.5, 5, 5.5, 6, 13, 14, 15, 16))).toEqual(true); - }); - - it("translate", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - - a.translate(new Vector3(1, 2, 0.5)); - expect(Matrix.equals(a, new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 28.5, 33.45, 37.8, 42))).toEqual( - true - ); - }); - - it("transpose", () => { - const a = new Matrix(1, 2, 3.3, 4, 5, 6, 7, 8, 9, 10.9, 11, 12, 13, 14, 15, 16); - - a.transpose(); - expect(Matrix.equals(a, new Matrix(1, 5, 9, 13, 2, 6, 10.9, 14, 3.3, 7, 11, 15, 4, 8, 12, 16))).toEqual(true); - }); -}); diff --git a/packages/math/tests/Matrix3x3.test.ts b/packages/math/tests/Matrix3x3.test.ts deleted file mode 100644 index 4e6b637ccb..0000000000 --- a/packages/math/tests/Matrix3x3.test.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { Matrix3x3 } from "../src/Matrix3x3"; -import { Matrix } from "../src/Matrix"; -import { Quaternion } from "../src/Quaternion"; -import { Vector2 } from "../src/Vector2"; - -describe("Matrix3x3 test", () => { - it("static add", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - const out = new Matrix3x3(); - - Matrix3x3.add(a, b, out); - expect(Matrix3x3.equals(out, new Matrix3x3(10, 10, 10, 10, 10, 10, 10, 10, 10))).toEqual(true); - }); - - it("static subtract", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - const out = new Matrix3x3(); - - Matrix3x3.subtract(a, b, out); - expect(Matrix3x3.equals(out, new Matrix3x3(-8, -6, -4, -2, 0, 2, 4, 6, 8))).toEqual(true); - }); - - it("static multiply", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - const out = new Matrix3x3(); - - Matrix3x3.multiply(a, b, out); - expect(Matrix3x3.equals(out, new Matrix3x3(90, 114, 138, 54, 69, 84, 18, 24, 30))).toEqual(true); - }); - - it("static equals", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const c = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - - expect(Matrix3x3.equals(a, b)).toEqual(true); - expect(Matrix3x3.equals(a, c)).toEqual(false); - }); - - it("static lerp", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const c = new Matrix3x3(); - Matrix3x3.lerp(a, b, 0.78, c); - - expect(Matrix3x3.equals(a, b)).toEqual(true); - expect(Matrix3x3.equals(a, c)).toEqual(true); - }); - - it("static fromXXX", () => { - const out = new Matrix3x3(); - const a = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); - - // Matrix - out.setValueByMatrix(a); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 2, 3, 5, 6, 7, 9, 10, 11))).toEqual(true); - - // quat - const q = new Quaternion(1, 2, 3, 4); - Matrix3x3.rotationQuaternion(q, out); - expect(Matrix3x3.equals(out, new Matrix3x3(-25, 28, -10, -20, -19, 20, 22, 4, -9))).toEqual(true); - - // scaling - const scale = new Vector2(1, 2); - Matrix3x3.scaling(scale, out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 0, 0, 0, 2, 0, 0, 0, 1))).toEqual(true); - - // translation - const translation = new Vector2(2, 3); - Matrix3x3.translation(translation, out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 0, 0, 0, 1, 0, 2, 3, 1))).toEqual(true); - }); - - it("static invert", () => { - const out = new Matrix3x3(); - const mat3 = new Matrix3x3(1, 2, 3, 2, 2, 4, 3, 1, 3); - - Matrix3x3.invert(mat3, out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, -1.5, 1, 3, -3, 1, -2, 2.5, -1))).toEqual(true); - }); - - it("static normalMatrix", () => { - const out = new Matrix3x3(); - const mat4 = new Matrix(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); - - Matrix3x3.normalMatrix(mat4, out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1))).toEqual(true); - }); - - it("static rotate", () => { - const out = new Matrix3x3(); - const mat3 = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - Matrix3x3.rotate(mat3, Math.PI / 3, out); - expect( - Matrix3x3.equals( - out, - new Matrix3x3( - 3.964101552963257, - 5.330127239227295, - 6.696152210235596, - 1.133974552154541, - 0.7679491639137268, - 0.4019237756729126, - 7, - 8, - 9 - ) - ) - ).toEqual(true); - }); - - it("static scale", () => { - const out = new Matrix3x3(); - const mat3 = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - Matrix3x3.scale(mat3, new Vector2(1, 2), out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 2, 3, 8, 10, 12, 7, 8, 9))).toEqual(true); - }); - - it("static translate", () => { - const out = new Matrix3x3(); - const mat3 = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - Matrix3x3.translate(mat3, new Vector2(1, 2), out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 2, 3, 4, 5, 6, 16, 20, 24))).toEqual(true); - }); - - it("static transpose", () => { - const out = new Matrix3x3(); - const mat3 = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - Matrix3x3.transpose(mat3, out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 4, 7, 2, 5, 8, 3, 6, 9))).toEqual(true); - Matrix3x3.transpose(out, out); - expect(Matrix3x3.equals(out, new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9))).toEqual(true); - }); - - it("setValue", () => { - const a = new Matrix3x3(); - a.setValue(1, 2, 3, 4, 5, 6, 7, 8, 9); - - expect(Matrix3x3.equals(a, new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9))).toEqual(true); - }); - - it("setValueByxxx", () => { - const a = new Matrix3x3(); - a.setValueByArray([1, 2, 3, 4, 5, 6, 7, 8, 9]); - const b = new Matrix3x3(); - b.setValueByMatrix(new Matrix(1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0, 0, 0, 0, 1)); - const c = new Matrix3x3(); - const arr = []; - a.toArray(arr); - c.setValueByArray(arr); - - expect(Matrix3x3.equals(a, b)).toEqual(true); - expect(Matrix3x3.equals(a, c)).toEqual(true); - expect(Matrix3x3.equals(b, c)).toEqual(true); - }); - - it("clone", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = a.clone(); - - expect(Matrix3x3.equals(a, b)).toEqual(true); - }); - - it("cloneTo", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const out = new Matrix3x3(); - - a.cloneTo(out); - expect(Matrix3x3.equals(a, out)).toEqual(true); - }); - - it("add", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - - a.add(b); - expect(Matrix3x3.equals(a, new Matrix3x3(10, 10, 10, 10, 10, 10, 10, 10, 10))).toEqual(true); - }); - - it("static subtract", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - - a.subtract(b); - expect(Matrix3x3.equals(a, new Matrix3x3(-8, -6, -4, -2, 0, 2, 4, 6, 8))).toEqual(true); - }); - - it("multiply", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const b = new Matrix3x3(9, 8, 7, 6, 5, 4, 3, 2, 1); - - a.multiply(b); - expect(Matrix3x3.equals(a, new Matrix3x3(90, 114, 138, 54, 69, 84, 18, 24, 30))).toEqual(true); - }); - - it("determinant", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - expect(a.determinant()).toEqual(0); - }); - - it("invert", () => { - const a = new Matrix3x3(1, 2, 3, 2, 2, 4, 3, 1, 3); - - a.invert(); - expect(Matrix3x3.equals(a, new Matrix3x3(1, -1.5, 1, 3, -3, 1, -2, 2.5, -1))).toEqual(true); - }); - - it("rotate", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - a.rotate(Math.PI / 3); - expect( - Matrix3x3.equals( - a, - new Matrix3x3( - 3.964101552963257, - 5.330127239227295, - 6.696152210235596, - 1.133974552154541, - 0.7679491639137268, - 0.4019237756729126, - 7, - 8, - 9 - ) - ) - ).toEqual(true); - }); - - it("scale", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - a.scale(new Vector2(1, 2)); - expect(Matrix3x3.equals(a, new Matrix3x3(1, 2, 3, 8, 10, 12, 7, 8, 9))).toEqual(true); - }); - - it("translate", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - a.translate(new Vector2(1, 2)); - expect(Matrix3x3.equals(a, new Matrix3x3(1, 2, 3, 4, 5, 6, 16, 20, 24))).toEqual(true); - }); - - it("transpose", () => { - const a = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - - a.transpose(); - expect(Matrix3x3.equals(a, new Matrix3x3(1, 4, 7, 2, 5, 8, 3, 6, 9))).toEqual(true); - a.transpose(); - expect(Matrix3x3.equals(a, new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9))).toEqual(true); - }); -}); diff --git a/packages/math/tests/Plane.test.ts b/packages/math/tests/Plane.test.ts deleted file mode 100644 index 9dba1e5697..0000000000 --- a/packages/math/tests/Plane.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Plane } from "../src/Plane"; -import { Vector3 } from "../src/Vector3"; - -describe("Plane test", () => { - it("Constructor", () => { - const point1 = new Vector3(0, 1, 0); - const point2 = new Vector3(0, 1, 1); - const point3 = new Vector3(1, 1, 0); - const plane1 = new Plane(); - Plane.fromPoints(point1, point2, point3, plane1); - const plane2 = new Plane(new Vector3(0, 1, 0), -1); - - expect(plane1.distance - plane2.distance).toEqual(0); - plane1.normalize(); - plane2.normalize(); - expect(Vector3.equals(plane1.normal, plane2.normal)).toEqual(true); - }); - - it("clone", () => { - const plane1 = new Plane(new Vector3(0, 1, 0), -1); - const plane2 = plane1.clone(); - expect(plane1.distance - plane2.distance).toEqual(0); - - const plane3 = new Plane(); - plane1.cloneTo(plane3); - expect(plane1.distance - plane3.distance).toEqual(0); - }); -}); diff --git a/packages/math/tests/Quaternion.test.ts b/packages/math/tests/Quaternion.test.ts deleted file mode 100644 index d8ae41090a..0000000000 --- a/packages/math/tests/Quaternion.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { MathUtil } from "../src/MathUtil"; -import { Quaternion } from "../src/Quaternion"; -import { Vector3 } from "../src/Vector3"; -import { Matrix3x3 } from "../src/Matrix3x3"; - -function toString(q: Quaternion): string { - return `quat(${q.x}, ${q.y}, ${q.z}, ${q.w})`; -} - -describe("Quaternion test", () => { - it("static add", () => { - const a = new Quaternion(2, 3, 4, 1); - const b = new Quaternion(-3, 5, 0, 2); - const out = new Quaternion(); - - Quaternion.add(a, b, out); - expect(toString(out)).toEqual("quat(-1, 8, 4, 3)"); - }); - - it("static multiply", () => { - const a = new Quaternion(2, 3, 4, 1); - const b = new Quaternion(-3, 5, 0, 2); - const out = new Quaternion(); - - Quaternion.multiply(a, b, out); - expect(toString(out)).toEqual("quat(-19, -1, 27, -7)"); - }); - - it("static conjugate", () => { - const a = new Quaternion(2, 3, 4, 5); - const out = new Quaternion(); - - Quaternion.conjugate(a, out); - expect(toString(out)).toEqual("quat(-2, -3, -4, 5)"); - }); - - it("static dot", () => { - const a = new Quaternion(2, 3, 1, 1); - const b = new Quaternion(-4, 5, 1, 1); - - expect(Quaternion.dot(a, b)).toEqual(9); - expect(a.dot(b)).toEqual(9); - }); - - it("static equals", () => { - const a = new Quaternion(1, 2, 3, 4); - const b = new Quaternion(1 + MathUtil.zeroTolerance * 0.9, 2, 3, 4); - - expect(Quaternion.equals(a, b)).toEqual(true); - }); - - it("static rotationAxisAngle", () => { - const a = new Vector3(3, 7, 5); - const b = new Vector3(); - const out = new Quaternion(); - Quaternion.rotationAxisAngle(a, Math.PI / 3, out); - const rad = out.getAxisAngle(b); - - expect(MathUtil.equals(rad, Math.PI / 3)).toEqual(true); - expect(Vector3.equals(b.normalize(), a.normalize())).toEqual(true); - }); - - it("static rotationEuler | rotationYawPitchRoll", () => { - const out1 = new Quaternion(); - const out2 = new Quaternion(); - Quaternion.rotationEuler(0, Math.PI / 3, Math.PI / 2, out1); - Quaternion.rotationYawPitchRoll(0, Math.PI / 3, Math.PI / 2, out2); - - const a = out1.toEuler(new Vector3()); - const b = out2.toYawPitchRoll(new Vector3()); - expect(Vector3.equals(a, new Vector3(0, Math.PI / 3, Math.PI / 2))).toEqual(true); - expect(Vector3.equals(b, new Vector3(0, Math.PI / 3, Math.PI / 2))).toEqual(true); - }); - - it("static rotationMatrix3x3", () => { - const a1 = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, 9); - const a2 = new Matrix3x3(1, 2, 3, 4, -5, 6, 7, 8, -9); - const a3 = new Matrix3x3(1, 2, 3, 4, 5, 6, 7, 8, -9); - const a4 = new Matrix3x3(-7, 2, 3, 4, -5, 6, 7, 8, 9); - const out = new Quaternion(); - - Quaternion.rotationMatrix3x3(a1, out); - expect(Quaternion.equals(out, new Quaternion(-0.25, 0.5, -0.25, 2))).toEqual(true); - Quaternion.rotationMatrix3x3(a2, out); - expect(Quaternion.equals(out, new Quaternion(2, 0.75, 1.25, -0.25))).toEqual(true); - Quaternion.rotationMatrix3x3(a3, out); - expect( - Quaternion.equals( - out, - new Quaternion(0.8017837257372732, 1.8708286933869707, 1.8708286933869709, 0.5345224838248488) - ) - ).toEqual(true); - Quaternion.rotationMatrix3x3(a4, out); - expect( - Quaternion.equals( - out, - new Quaternion(1.066003581778052, 1.4924050144892729, 2.345207879911715, -0.21320071635561041) - ) - ).toEqual(true); - }); - - it("static invert", () => { - const a = new Quaternion(1, 1, 1, 0.5); - const out = new Quaternion(); - - Quaternion.invert(a, out); - expect( - Quaternion.equals( - out, - new Quaternion(-0.3076923076923077, -0.3076923076923077, -0.3076923076923077, 0.15384615384615385) - ) - ).toEqual(true); - }); - - it("static lerp", () => { - const a = new Quaternion(0, 1, 2, 0); - const b = new Quaternion(2, 2, 0, 0); - const normal = new Quaternion(1, 1.5, 1, 0); - const out = new Quaternion(); - - Quaternion.lerp(a, b, 0.5, out); - expect(Quaternion.equals(out, normal.normalize())).toEqual(true); - a.lerp(b, 0.5); - expect(Quaternion.equals(a, normal.normalize())).toEqual(true); - }); - - it("static slerp", () => { - const a = new Quaternion(1, 1, 1, 0.5); - const b = new Quaternion(0.5, 0.5, 0.5, 0.5); - const out = new Quaternion(); - - Quaternion.slerp(a, b, 0.5, out); - expect(toString(out)).toEqual("quat(0.75, 0.75, 0.75, 0.5)"); - }); - - it("static normalize", () => { - const a = new Quaternion(3, 4, 0, 0); - const out = new Quaternion(); - - Quaternion.normalize(a, out); - expect(Quaternion.equals(out, new Quaternion(0.6, 0.8, 0, 0))).toEqual(true); - }); - - it("static rotation", () => { - const out = new Quaternion(); - - Quaternion.rotationX(1.5, out); - expect(Quaternion.equals(out, new Quaternion(0.6816387600233341, 0, 0, 0.7316888688738209))).toEqual(true); - - Quaternion.rotationY(1.5, out); - expect(Quaternion.equals(out, new Quaternion(0, 0.6816387600233341, 0, 0.7316888688738209))).toEqual(true); - - Quaternion.rotationZ(1.5, out); - expect(Quaternion.equals(out, new Quaternion(0, 0, 0.6816387600233341, 0.7316888688738209))).toEqual(true); - }); - - it("static rotate", () => { - const a = new Quaternion(); - const b = new Quaternion(); - const out = new Quaternion(); - - Quaternion.rotateX(a, 1.5, out); - b.rotateX(1.5); - expect(Quaternion.equals(out, new Quaternion(0.6816387600233341, 0, 0, 0.7316888688738209))).toEqual(true); - expect(Quaternion.equals(out, b)).toEqual(true); - - Quaternion.rotateY(a, 1.5, out); - b.setValue(0, 0, 0, 1); - b.rotateY(1.5); - expect(Quaternion.equals(out, new Quaternion(0, 0.6816387600233341, 0, 0.7316888688738209))).toEqual(true); - expect(Quaternion.equals(out, b)).toEqual(true); - - Quaternion.rotateZ(a, 1.5, out); - b.setValue(0, 0, 0, 1); - b.rotateZ(1.5); - expect(Quaternion.equals(out, new Quaternion(0, 0, 0.6816387600233341, 0.7316888688738209))).toEqual(true); - expect(Quaternion.equals(out, b)).toEqual(true); - }); - - it("static rotatAxisAngle", () => { - const a = new Vector3(0, 5, 0); - const b = 0.5 * Math.PI; - const out = new Quaternion(0, 0, 0, 1); - out.rotateAxisAngle(a, b); - expect(Quaternion.equals(out, new Quaternion(0, 0.7071067811865475, 0, 0.7071067811865476))).toEqual(true); - }); - - it("static scale", () => { - const a = new Quaternion(3, 4, 5, 0); - const out = new Quaternion(); - - Quaternion.scale(a, 3, out); - expect(toString(out)).toEqual("quat(9, 12, 15, 0)"); - }); - - it("static toEuler", () => { - const a = new Quaternion(); - Quaternion.rotationEuler(0, Math.PI / 3, 0, a); - const euler = a.toEuler(new Vector3()); - const ypr = a.toYawPitchRoll(new Vector3()); - expect(Vector3.equals(euler, new Vector3(0, Math.PI / 3, 0))).toEqual(true); - expect(Vector3.equals(ypr, new Vector3(Math.PI / 3, 0, 0))).toEqual(true); - }); - - it("setValue", () => { - const a = new Quaternion(); - a.setValue(1, 1, 1, 1); - const b = new Quaternion(); - b.setValueByArray([1, 1, 1, 1]); - expect(Quaternion.equals(a, b)).toEqual(true); - - const c = []; - b.toArray(c); - const d = new Quaternion(); - d.setValueByArray(c); - expect(Quaternion.equals(a, d)).toEqual(true); - }); - - it("clone", () => { - const a = new Quaternion(3, 4, 5, 0); - const b = a.clone(); - expect(toString(a)).toEqual(toString(b)); - }); - - it("cloneTo", () => { - const a = new Quaternion(3, 4, 5, 0); - const out = new Quaternion(); - a.cloneTo(out); - expect(toString(a)).toEqual(toString(out)); - }); - - it("conjugate", () => { - const a = new Quaternion(1, 1, 1, 1); - expect(toString(a.conjugate())).toEqual("quat(-1, -1, -1, 1)"); - }); - - it("identity", () => { - const a = new Quaternion(); - a.identity(); - - expect(toString(a)).toEqual("quat(0, 0, 0, 1)"); - }); - - it("length", () => { - const a = new Quaternion(3, 4, 5, 0); - expect(MathUtil.equals(Math.sqrt(50), a.length())).toEqual(true); - expect(a.lengthSquared()).toEqual(50); - }); -}); diff --git a/packages/math/tests/Ray.test.ts b/packages/math/tests/Ray.test.ts deleted file mode 100644 index bae7845c94..0000000000 --- a/packages/math/tests/Ray.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { BoundingBox } from "../src/BoundingBox"; -import { BoundingSphere } from "../src/BoundingSphere"; -import { Plane } from "../src/Plane"; -import { Ray } from "../src/Ray"; -import { Vector3 } from "../src/Vector3"; - -describe("Ray test", () => { - it("ray-plane", () => { - const ray = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const plane = new Plane(new Vector3(0, 1, 0), -3); - - expect(ray.intersectPlane(plane)).toEqual(-plane.distance); - }); - - it("ray-sphere", () => { - const ray = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const sphere = new BoundingSphere(new Vector3(0, 5, 0), 1); - - expect(ray.intersectSphere(sphere)).toEqual(4); - }); - - it("ray-box", () => { - const ray = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const box = new BoundingBox(); - BoundingBox.fromCenterAndExtent(new Vector3(0, 20, 0), new Vector3(5, 5, 5), box); - - expect(ray.intersectBox(box)).toEqual(15); - }); - - it("ray-getPoint", () => { - const ray = new Ray(new Vector3(0, 0, 0), new Vector3(0, 1, 0)); - const out = new Vector3(); - ray.getPoint(10, out); - - expect(Vector3.equals(out, new Vector3(0, 10, 0))).toEqual(true); - }); -}); diff --git a/packages/math/tests/Rect.test.ts b/packages/math/tests/Rect.test.ts deleted file mode 100644 index 7cf5d776d5..0000000000 --- a/packages/math/tests/Rect.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Rect } from "../src/Rect"; - -describe("Rect test", () => { - it("setValue", () => { - const a = new Rect(); - a.setValue(0, 0, 1, 1); - expect(a.x).toEqual(0); - expect(a.y).toEqual(0); - expect(a.width).toEqual(1); - expect(a.height).toEqual(1); - }); - - it("clone", () => { - const a = new Rect(0, 0, 1, 2); - const b = a.clone(); - expect(a.x).toEqual(b.x); - expect(a.y).toEqual(b.y); - expect(a.width).toEqual(b.width); - expect(a.height).toEqual(b.height); - }); - - it("cloneTo", () => { - const a = new Rect(0, 0, 1, 2); - const b = new Rect(); - a.cloneTo(b); - expect(a.x).toEqual(b.x); - expect(a.y).toEqual(b.y); - expect(a.width).toEqual(b.width); - expect(a.height).toEqual(b.height); - }); -}); diff --git a/packages/math/tests/SphericalHarmonics3.test.ts b/packages/math/tests/SphericalHarmonics3.test.ts deleted file mode 100644 index f0c6142dd0..0000000000 --- a/packages/math/tests/SphericalHarmonics3.test.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { Color } from "../src/Color"; -import { SphericalHarmonics3 } from "../src/SphericalHarmonics3"; -import { Vector3 } from "../src/Vector3"; - -describe("SphericalHarmonics3 test", () => { - it("addLight", () => { - const a = new SphericalHarmonics3(); - a.addLight(new Vector3(0, 1, 0), new Color(1, 0, 0, 1), 10); - const b = Float32Array.from([ - 2.8209500312805176, - 0, - 0, - -4.886030197143555, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - -3.1539199352264404, - 0, - 0, - 0, - 0, - 0, - -5.462739944458008, - 0, - 0 - ]); - expect(a.coefficients.length).toEqual(b.length); - for (let i = 0, l = b.length; i < l; ++i) { - expect(a.coefficients[i]).toEqual(b[i]); - } - }); - - it("evaluate", () => { - const a = new SphericalHarmonics3(); - a.addLight(new Vector3(0, 1, 0), new Color(1, 0, 0, 1), 10); - const color = new Color(); - a.evaluate(new Vector3(0, 1, 0), color); - expect(color.r).toEqual(10.625004777489186); - }); - - it("scale", () => { - const a = new SphericalHarmonics3(); - a.addLight(new Vector3(0, 1, 0), new Color(1, 0, 0, 1), 10); - a.scale(0.5); - const b = Float32Array.from([ - 1.4104750156402588, - 0, - 0, - -2.4430150985717773, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - -1.5769599676132202, - 0, - 0, - 0, - 0, - 0, - -2.731369972229004, - 0, - 0 - ]); - expect(a.coefficients.length).toEqual(b.length); - for (let i = 0, l = b.length; i < l; ++i) { - expect(a.coefficients[i]).toEqual(b[i]); - } - }); - - it("setValueByArray | toArray", () => { - const a = new SphericalHarmonics3(); - const b = [ - 1.4104750156402588, - 0, - 0, - -2.4430150985717773, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - -1.5769599676132202, - 0, - 0, - 0, - 0, - 0, - -2.731369972229004, - 0, - 0 - ]; - a.setValueByArray(b); - for (let i = 0, l = b.length; i < l; ++i) { - expect(a.coefficients[i]).toEqual(b[i]); - } - const c = []; - a.toArray(c); - for (let i = 0, l = b.length; i < l; ++i) { - expect(c[i]).toEqual(b[i]); - } - }); - - it("clone | cloneTo", () => { - const a = new SphericalHarmonics3(); - a.addLight(new Vector3(0, 1, 0), new Color(1, 0, 0, 1), 10); - const b = a.clone(); - const c = new SphericalHarmonics3(); - a.cloneTo(c); - - const aCoe = a.coefficients; - const bCoe = b.coefficients; - for (let i = 0, l = aCoe.length; i < l; ++i) { - expect(aCoe[i]).toEqual(bCoe[i]); - } - }); -}); diff --git a/packages/math/tests/Vector2.test.ts b/packages/math/tests/Vector2.test.ts deleted file mode 100644 index bc4c65ea3a..0000000000 --- a/packages/math/tests/Vector2.test.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { MathUtil } from "../src/MathUtil"; -import { Vector2 } from "../src/Vector2"; - -function toString(v: Vector2): string { - return `vec2(${v.x}, ${v.y})`; -} - -describe("Vector2 test", () => { - it("static add", () => { - const a = new Vector2(2, 3); - const b = new Vector2(-3, 5); - const out = new Vector2(); - - Vector2.add(a, b, out); - expect(toString(out)).toEqual("vec2(-1, 8)"); - }); - - it("static subtract", () => { - const a = new Vector2(2, 3); - const b = new Vector2(-3, 5); - const out = new Vector2(); - - Vector2.subtract(a, b, out); - expect(toString(out)).toEqual("vec2(5, -2)"); - }); - - it("static multiply", () => { - const a = new Vector2(2, 3); - const b = new Vector2(-3, 5); - const out = new Vector2(); - - Vector2.multiply(a, b, out); - expect(toString(out)).toEqual("vec2(-6, 15)"); - }); - - it("static divide", () => { - const a = new Vector2(2, 3); - const b = new Vector2(-4, 5); - const out = new Vector2(); - - Vector2.divide(a, b, out); - expect(toString(out)).toEqual("vec2(-0.5, 0.6)"); - }); - - it("static dot", () => { - const a = new Vector2(2, 3); - const b = new Vector2(-4, 5); - - expect(Vector2.dot(a, b)).toEqual(7); - }); - - it("static distance", () => { - const a = new Vector2(1, 1); - const b = new Vector2(4, 5); - - expect(Vector2.distance(a, b)).toEqual(5); - }); - - it("static distanceSquared", () => { - const a = new Vector2(1, 1); - const b = new Vector2(4, 5); - - expect(Vector2.distanceSquared(a, b)).toEqual(25); - }); - - it("static equals", () => { - const a = new Vector2(1, 2); - const b = new Vector2(1 + MathUtil.zeroTolerance * 0.9, 2); - - expect(Vector2.equals(a, b)).toEqual(true); - }); - - it("static lerp", () => { - const a = new Vector2(0, 1); - const b = new Vector2(2, 3); - const out = new Vector2(); - - Vector2.lerp(a, b, 0.5, out); - expect(toString(out)).toEqual("vec2(1, 2)"); - }); - - it("static max", () => { - const a = new Vector2(0, 10); - const b = new Vector2(2, 3); - const out = new Vector2(); - - Vector2.max(a, b, out); - expect(toString(out)).toEqual("vec2(2, 10)"); - }); - - it("static min", () => { - const a = new Vector2(0, 10); - const b = new Vector2(2, 3); - const out = new Vector2(); - - Vector2.min(a, b, out); - expect(toString(out)).toEqual("vec2(0, 3)"); - }); - - it("static negate", () => { - const a = new Vector2(4, -4); - const out = new Vector2(); - - Vector2.negate(a, out); - expect(toString(out)).toEqual("vec2(-4, 4)"); - }); - - it("static normalize", () => { - const a = new Vector2(3, 4); - const out = new Vector2(); - - Vector2.normalize(a, out); - expect(Vector2.equals(out, new Vector2(0.6, 0.8))).toEqual(true); - }); - - it("static scale", () => { - const a = new Vector2(3, 4); - const out = new Vector2(); - - Vector2.scale(a, 3, out); - expect(toString(out)).toEqual("vec2(9, 12)"); - }); - - it("setValue", () => { - const a = new Vector2(3, 4); - expect(toString(a.setValue(5, 6))).toEqual("vec2(5, 6)"); - }); - - it("setValueByArray", () => { - const a = new Vector2(3, 4); - expect(toString(a.setValueByArray([5, 6]))).toEqual("vec2(5, 6)"); - const b = []; - a.toArray(b); - expect(b[0]).toEqual(5); - expect(b[1]).toEqual(6); - }); - - it("clone", () => { - const a = new Vector2(3, 4); - const b = a.clone(); - expect(toString(a)).toEqual(toString(b)); - }); - - it("cloneTo", () => { - const a = new Vector2(3, 4); - const out = new Vector2(); - a.cloneTo(out); - expect(toString(a)).toEqual(toString(out)); - }); - - it("add", () => { - const a = new Vector2(3, 4); - const ret = new Vector2(1, 2); - expect(toString(ret.add(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec2(4, 6)"); - }); - - it("subtract", () => { - const a = new Vector2(3, 4); - const ret = new Vector2(1, 2); - expect(toString(ret.subtract(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec2(-2, -2)"); - }); - - it("multiply", () => { - const a = new Vector2(3, 4); - const ret = new Vector2(1, 2); - expect(toString(ret.multiply(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec2(3, 8)"); - }); - - it("divide", () => { - const a = new Vector2(1, 2); - const ret = new Vector2(3, 4); - expect(toString(ret.divide(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec2(3, 2)"); - }); - - it("length", () => { - const a = new Vector2(3, 4); - expect(a.length()).toEqual(5); - }); - - it("lengthSquared", () => { - const a = new Vector2(3, 4); - expect(a.lengthSquared()).toEqual(25); - }); - - it("negate", () => { - const a = new Vector2(3, 4); - expect(toString(a.negate())).toEqual(toString(a)); - expect(toString(a)).toEqual("vec2(-3, -4)"); - }); - - it("normalize", () => { - const a = new Vector2(3, 4); - expect(toString(a.normalize())).toEqual(toString(a)); - expect(Vector2.equals(a, new Vector2(0.6, 0.8))).toEqual(true); - }); - - it("scale", () => { - const a = new Vector2(3, 4); - expect(toString(a.scale(2))).toEqual(toString(a)); - expect(toString(a)).toEqual("vec2(6, 8)"); - }); -}); diff --git a/packages/math/tests/Vector3.test.ts b/packages/math/tests/Vector3.test.ts deleted file mode 100644 index af3962e9af..0000000000 --- a/packages/math/tests/Vector3.test.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { MathUtil } from "../src/MathUtil"; -import { Vector3 } from "../src/Vector3"; -import { Vector4 } from "../src/Vector4"; -import { Quaternion } from "../src/Quaternion"; -import { Matrix3x3 } from "../src/Matrix3x3"; -import { Matrix } from "../src/Matrix"; - -function toString(v: Vector3): string { - return `vec3(${v.x}, ${v.y}, ${v.z})`; -} - -describe("Vector3 test", () => { - it("static add", () => { - const a = new Vector3(2, 3, 4); - const b = new Vector3(-3, 5, 0); - const out = new Vector3(); - - Vector3.add(a, b, out); - expect(toString(out)).toEqual("vec3(-1, 8, 4)"); - }); - - it("static subtract", () => { - const a = new Vector3(2, 3, 4); - const b = new Vector3(-3, 5, 1); - const out = new Vector3(); - - Vector3.subtract(a, b, out); - expect(toString(out)).toEqual("vec3(5, -2, 3)"); - }); - - it("static multiply", () => { - const a = new Vector3(2, 3, 4); - const b = new Vector3(-3, 5, 0.2); - const out = new Vector3(); - - Vector3.multiply(a, b, out); - expect(toString(out)).toEqual("vec3(-6, 15, 0.8)"); - }); - - it("static divide", () => { - const a = new Vector3(2, 3, 4); - const b = new Vector3(-4, 5, 16); - const out = new Vector3(); - - Vector3.divide(a, b, out); - expect(toString(out)).toEqual("vec3(-0.5, 0.6, 0.25)"); - }); - - it("static dot", () => { - const a = new Vector3(2, 3, 1); - const b = new Vector3(-4, 5, 1); - - expect(Vector3.dot(a, b)).toEqual(8); - }); - - it("static cross", () => { - const a = new Vector3(1, 2, 3); - const b = new Vector3(4, 5, 6); - const out = new Vector3(); - - Vector3.cross(a, b, out); - expect(toString(out)).toEqual("vec3(-3, 6, -3)"); - }); - - it("static distance", () => { - const a = new Vector3(1, 2, 3); - const b = new Vector3(4, 6, 3); - - expect(Vector3.distance(a, b)).toEqual(5); - expect(Vector3.distanceSquared(a, b)).toEqual(25); - }); - - it("static equals", () => { - const a = new Vector3(1, 2, 3); - const b = new Vector3(1 + MathUtil.zeroTolerance * 0.9, 2, 3); - - expect(Vector3.equals(a, b)).toEqual(true); - }); - - it("static lerp", () => { - const a = new Vector3(0, 1, 2); - const b = new Vector3(2, 2, 0); - const out = new Vector3(); - - Vector3.lerp(a, b, 0.5, out); - expect(toString(out)).toEqual("vec3(1, 1.5, 1)"); - }); - - it("static max", () => { - const a = new Vector3(0, 10, 1); - const b = new Vector3(2, 3, 5); - const out = new Vector3(); - - Vector3.max(a, b, out); - expect(toString(out)).toEqual("vec3(2, 10, 5)"); - }); - - it("static min", () => { - const a = new Vector3(0, 10, 1); - const b = new Vector3(2, 3, 5); - const out = new Vector3(); - - Vector3.min(a, b, out); - expect(toString(out)).toEqual("vec3(0, 3, 1)"); - }); - - it("static negate", () => { - const a = new Vector3(4, -4, 0); - const out = new Vector3(); - - Vector3.negate(a, out); - expect(toString(out)).toEqual("vec3(-4, 4, 0)"); - }); - - it("static normalize", () => { - const a = new Vector3(3, 4, 0); - const out = new Vector3(); - - Vector3.normalize(a, out); - expect(Vector3.equals(out, new Vector3(0.6, 0.8, 0))).toEqual(true); - }); - - it("static scale", () => { - const a = new Vector3(3, 4, 5); - const out = new Vector3(); - - Vector3.scale(a, 3, out); - expect(toString(out)).toEqual("vec3(9, 12, 15)"); - }); - - it("static transform", () => { - const a = new Vector3(2, 3, 4); - const out = new Vector3(); - - const m44 = new Matrix(2, 7, 17, 0, 3, 11, 19, 0, 5, 13, 23, 0, 0, 0, 0, 1); - Vector3.transformNormal(a, m44, out); - expect(toString(out)).toEqual("vec3(33, 99, 183)"); - - const b = new Vector4(2, 3, 4, 1); - const out4 = new Vector4(); - const m4 = new Matrix(); - m4.setValue(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1); - Vector3.transformCoordinate(a, m4, out); - Vector4.transform(b, m4, out4); - expect(out.x).toEqual(out4.x / out4.w); - expect(out.y).toEqual(out4.y / out4.w); - expect(out.z).toEqual(out4.z / out4.w); - - Vector3.transformByQuat(a, new Quaternion(), out); - expect(toString(a)).toEqual(toString(out)); - Vector3.transformByQuat(a, new Quaternion(2, 3, 4, 5), out); - expect(toString(out)).toEqual("vec3(108, 162, 216)"); - }); - - it("setValue", () => { - const a = new Vector3(3, 4, 5); - expect(toString(a.setValue(5, 6, 7))).toEqual("vec3(5, 6, 7)"); - }); - - it("setValueByArray", () => { - const a = new Vector3(3, 4, 3); - expect(toString(a.setValueByArray([5, 6, 4]))).toEqual("vec3(5, 6, 4)"); - const b = []; - a.toArray(b); - expect(b[0]).toEqual(5); - expect(b[1]).toEqual(6); - expect(b[2]).toEqual(4); - }); - - it("clone", () => { - const a = new Vector3(3, 4, 5); - const b = a.clone(); - expect(toString(a)).toEqual(toString(b)); - }); - - it("cloneTo", () => { - const a = new Vector3(3, 4, 5); - const out = new Vector3(); - a.cloneTo(out); - expect(toString(a)).toEqual(toString(out)); - }); - - it("add", () => { - const a = new Vector3(3, 4, 5); - const ret = new Vector3(1, 2, 4); - expect(toString(ret.add(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec3(4, 6, 9)"); - }); - - it("subtract", () => { - const a = new Vector3(3, 4, 5); - const ret = new Vector3(1, 2, 8); - expect(toString(ret.subtract(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec3(-2, -2, 3)"); - }); - - it("multiply", () => { - const a = new Vector3(3, 4, 5); - const ret = new Vector3(1, 2, 1); - expect(toString(ret.multiply(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec3(3, 8, 5)"); - }); - - it("divide", () => { - const a = new Vector3(1, 2, 3); - const ret = new Vector3(3, 4, 12); - expect(toString(ret.divide(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec3(3, 2, 4)"); - }); - - it("length", () => { - const a = new Vector3(3, 4, 5); - expect(MathUtil.equals(Math.sqrt(50), a.length())).toEqual(true); - expect(a.lengthSquared()).toEqual(50); - }); - - it("negate", () => { - const a = new Vector3(3, 4, 5); - expect(toString(a.negate())).toEqual(toString(a)); - expect(toString(a)).toEqual("vec3(-3, -4, -5)"); - }); - - it("normalize", () => { - const a = new Vector3(3, 4, 0); - expect(toString(a.normalize())).toEqual(toString(a)); - expect(Vector3.equals(a, new Vector3(0.6, 0.8, 0))).toEqual(true); - }); - - it("scale", () => { - const a = new Vector3(3, 4, 0); - expect(toString(a.scale(2))).toEqual(toString(a)); - expect(toString(a)).toEqual("vec3(6, 8, 0)"); - }); - - it("transformToVec3", () => { - const a = new Vector3(2, 3, 4); - const out = new Vector3(2, 3, 5); - const m = new Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1); - a.transformToVec3(m); - expect(a.x).toEqual(out.x); - expect(a.y).toEqual(out.y); - expect(a.z).toEqual(out.z); - }); - - it("transformCoordinate", () => { - const a = new Vector3(2, 3, 4); - const out = new Vector3(); - const b = new Vector4(2, 3, 4, 1); - const out4 = new Vector4(); - const m4 = new Matrix(); - m4.setValue(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1); - Vector3.transformCoordinate(a, m4, out); - Vector4.transform(b, m4, out4); - expect(out.x).toEqual(out4.x / out4.w); - expect(out.y).toEqual(out4.y / out4.w); - expect(out.z).toEqual(out4.z / out4.w); - }); - - it("transformByQuat", () => { - const a = new Vector3(2, 3, 4); - a.transformByQuat(new Quaternion(2, 3, 4, 5)); - expect(toString(a)).toEqual("vec3(108, 162, 216)"); - }); -}); diff --git a/packages/math/tests/Vector4.test.ts b/packages/math/tests/Vector4.test.ts deleted file mode 100644 index c2bc1fd3f8..0000000000 --- a/packages/math/tests/Vector4.test.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { MathUtil } from "../src/MathUtil"; -import { Vector4 } from "../src/Vector4"; -import { Quaternion } from "../src/Quaternion"; -import { Matrix } from "../src/Matrix"; - -function toString(v: Vector4): string { - return `vec4(${v.x}, ${v.y}, ${v.z}, ${v.w})`; -} - -describe("Vector4 test", () => { - it("static add", () => { - const a = new Vector4(2, 3, 4, 1); - const b = new Vector4(-3, 5, 0, 2); - const out = new Vector4(); - - Vector4.add(a, b, out); - expect(toString(out)).toEqual("vec4(-1, 8, 4, 3)"); - }); - - it("static subtract", () => { - const a = new Vector4(2, 3, 4, 1); - const b = new Vector4(-3, 5, 1, 2); - const out = new Vector4(); - - Vector4.subtract(a, b, out); - expect(toString(out)).toEqual("vec4(5, -2, 3, -1)"); - }); - - it("static multiply", () => { - const a = new Vector4(2, 3, 4, 1); - const b = new Vector4(-3, 5, 0.2, 2); - const out = new Vector4(); - - Vector4.multiply(a, b, out); - expect(toString(out)).toEqual("vec4(-6, 15, 0.8, 2)"); - }); - - it("static divide", () => { - const a = new Vector4(2, 3, 4, 1); - const b = new Vector4(-4, 5, 16, 2); - const out = new Vector4(); - - Vector4.divide(a, b, out); - expect(toString(out)).toEqual("vec4(-0.5, 0.6, 0.25, 0.5)"); - }); - - it("static dot", () => { - const a = new Vector4(2, 3, 1, 1); - const b = new Vector4(-4, 5, 1, 1); - - expect(Vector4.dot(a, b)).toEqual(9); - }); - - it("static distance", () => { - const a = new Vector4(1, 2, 3, 0); - const b = new Vector4(4, 6, 3, 0); - - expect(Vector4.distance(a, b)).toEqual(5); - expect(Vector4.distanceSquared(a, b)).toEqual(25); - }); - - it("static equals", () => { - const a = new Vector4(1, 2, 3, 4); - const b = new Vector4(1 + MathUtil.zeroTolerance * 0.9, 2, 3, 4); - - expect(Vector4.equals(a, b)).toEqual(true); - }); - - it("static lerp", () => { - const a = new Vector4(0, 1, 2, 0); - const b = new Vector4(2, 2, 0, 0); - const out = new Vector4(); - - Vector4.lerp(a, b, 0.5, out); - expect(toString(out)).toEqual("vec4(1, 1.5, 1, 0)"); - }); - - it("static max", () => { - const a = new Vector4(0, 10, 1, -1); - const b = new Vector4(2, 3, 5, -5); - const out = new Vector4(); - - Vector4.max(a, b, out); - expect(toString(out)).toEqual("vec4(2, 10, 5, -1)"); - }); - - it("static min", () => { - const a = new Vector4(0, 10, 1, -1); - const b = new Vector4(2, 3, 5, -5); - const out = new Vector4(); - - Vector4.min(a, b, out); - expect(toString(out)).toEqual("vec4(0, 3, 1, -5)"); - }); - - it("static negate", () => { - const a = new Vector4(4, -4, 0, 1); - const out = new Vector4(); - - Vector4.negate(a, out); - expect(toString(out)).toEqual("vec4(-4, 4, 0, -1)"); - }); - - it("static normalize", () => { - const a = new Vector4(3, 4, 0, 0); - const out = new Vector4(); - - Vector4.normalize(a, out); - expect(Vector4.equals(out, new Vector4(0.6, 0.8, 0, 0))).toEqual(true); - }); - - it("static scale", () => { - const a = new Vector4(3, 4, 5, 0); - const out = new Vector4(); - - Vector4.scale(a, 3, out); - expect(toString(out)).toEqual("vec4(9, 12, 15, 0)"); - }); - - it("static transform", () => { - const a = new Vector4(2, 3, 4, 5); - const out = new Vector4(); - const m4 = new Matrix(); - m4.setValue(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0); - Vector4.transform(a, m4, out); - expect(toString(out)).toEqual("vec4(2, 3, 9, 0)"); - - Vector4.transformByQuat(a, new Quaternion(), out); - expect(toString(a)).toEqual(toString(out)); - Vector4.transformByQuat(a, new Quaternion(2, 3, 4, 5), out); - expect(toString(out)).toEqual("vec4(108, 162, 216, 5)"); - }); - - it("setValue", () => { - const a = new Vector4(3, 4, 5, 0); - expect(toString(a.setValue(5, 6, 7, 1))).toEqual("vec4(5, 6, 7, 1)"); - }); - - it("setValueByArray", () => { - const a = new Vector4(3, 4, 3, 8); - expect(toString(a.setValueByArray([5, 6, 4, 1]))).toEqual("vec4(5, 6, 4, 1)"); - const b = []; - a.toArray(b); - expect(b[0]).toEqual(5); - expect(b[1]).toEqual(6); - expect(b[2]).toEqual(4); - expect(b[3]).toEqual(1); - }); - - it("clone", () => { - const a = new Vector4(3, 4, 5, 0); - const b = a.clone(); - expect(toString(a)).toEqual(toString(b)); - }); - - it("cloneTo", () => { - const a = new Vector4(3, 4, 5, 0); - const out = new Vector4(); - a.cloneTo(out); - expect(toString(a)).toEqual(toString(out)); - }); - - it("add", () => { - const a = new Vector4(3, 4, 5, 1); - const ret = new Vector4(1, 2, 4, 1); - expect(toString(ret.add(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec4(4, 6, 9, 2)"); - }); - - it("subtract", () => { - const a = new Vector4(3, 4, 5, 1); - const ret = new Vector4(1, 2, 8, 1); - expect(toString(ret.subtract(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec4(-2, -2, 3, 0)"); - }); - - it("multiply", () => { - const a = new Vector4(3, 4, 5, 1); - const ret = new Vector4(1, 2, 1, 1); - expect(toString(ret.multiply(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec4(3, 8, 5, 1)"); - }); - - it("divide", () => { - const a = new Vector4(1, 2, 3, 1); - const ret = new Vector4(3, 4, 12, 1); - expect(toString(ret.divide(a))).toEqual(toString(ret)); - expect(toString(ret)).toEqual("vec4(3, 2, 4, 1)"); - }); - - it("length", () => { - const a = new Vector4(3, 4, 5, 0); - expect(MathUtil.equals(Math.sqrt(50), a.length())).toEqual(true); - expect(a.lengthSquared()).toEqual(50); - }); - - it("negate", () => { - const a = new Vector4(3, 4, 5, 0); - expect(toString(a.negate())).toEqual(toString(a)); - expect(toString(a)).toEqual("vec4(-3, -4, -5, 0)"); - }); - - it("normalize", () => { - const a = new Vector4(3, 4, 0, 0); - expect(toString(a.normalize())).toEqual(toString(a)); - expect(Vector4.equals(a, new Vector4(0.6, 0.8, 0, 0))).toEqual(true); - }); - - it("scale", () => { - const a = new Vector4(3, 4, 0, 0); - expect(toString(a.scale(2))).toEqual(toString(a)); - expect(toString(a)).toEqual("vec4(6, 8, 0, 0)"); - }); -}); diff --git a/packages/oasis-engine/tests/test.js b/packages/oasis-engine/tests/test.js deleted file mode 100644 index 936ead0b76..0000000000 --- a/packages/oasis-engine/tests/test.js +++ /dev/null @@ -1,5 +0,0 @@ -describe("", () => { - it("It worked!", () => { - // expect().to.be.an(""); - }); -}); diff --git a/packages/rhi-webgl/src/GLTexture.ts b/packages/rhi-webgl/src/GLTexture.ts index 9ba3a44bcb..bfce115bb8 100644 --- a/packages/rhi-webgl/src/GLTexture.ts +++ b/packages/rhi-webgl/src/GLTexture.ts @@ -584,4 +584,4 @@ export class GLTexture implements IPlatformTexture { } return frameBuffer; } -} +} \ No newline at end of file diff --git a/packages/rhi-webgl/tests/WebGLEngine.test.ts b/packages/rhi-webgl/tests/WebGLEngine.test.ts deleted file mode 100644 index ff8e6c3c0d..0000000000 --- a/packages/rhi-webgl/tests/WebGLEngine.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { WebCanvas } from "../src/WebCanvas"; -import { WebGLEngine } from "../src/WebGLEngine"; - -describe("webgl engine test", () => { - it("create a webgl engine", () => { - const canvas = document.createElement("canvas"); - const engine = new WebGLEngine(canvas); - expect(engine.canvas instanceof WebCanvas).toBeTruthy(); - }); -}); diff --git a/packages/stats/tests/Stats-test.js b/packages/stats/tests/Stats-test.js deleted file mode 100644 index f1541fc25b..0000000000 --- a/packages/stats/tests/Stats-test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { Stats } from "../src/Stats"; - -describe("Stats", () => { - it("It worked!", () => { - let stats = new Stats(); - expect(stats).to.be.an("object"); - }); -}); diff --git a/rollup.config.js b/rollup.config.js index edd86d0c92..5100b7dd63 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -126,6 +126,7 @@ function config({ location, pkgJson }) { }, { file: path.join(location, pkgJson.main), + sourcemap: true, format: "commonjs" } ], diff --git a/tests/index.ts b/tests/index.ts new file mode 100644 index 0000000000..40585d7550 --- /dev/null +++ b/tests/index.ts @@ -0,0 +1,18 @@ +import fs from "fs"; +import path from "path"; + +fs.readdirSync(path.join(__dirname, "src")).forEach((file) => { + const root = path.join(__dirname, "src", file); + const stat = fs.statSync(root); + if (stat.isDirectory()) { + describe(file, () => { + fs.readdirSync(root).forEach((file) => { + const filePath = path.join(root, file); + const stat = fs.statSync(filePath); + if (stat.isFile() && filePath.endsWith(".test.ts")) { + require(filePath); + } + }); + }); + } +}); diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 0000000000..553b13ee83 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,25 @@ +{ + "name": "@oasis-engine/tests", + "private": true, + "version": "0.7.0-beta.3", + "license": "MIT", + "main": "dist/main.js", + "module": "dist/module.js", + "types": "types/index.d.ts", + "debug": "src/index.ts", + "scripts": { + "b:types": "echo hi" + }, + "files": [ + "dist/**/*", + "types/**/*" + ], + "dependencies": { + "@oasis-engine/math": "0.7.0-beta.3", + "@oasis-engine/core": "0.7.0-beta.3", + "@oasis-engine/rhi-webgl": "0.7.0-beta.3" + }, + "devDependencies": { + "@oasis-engine/design": "0.7.0-beta.3" + } +} diff --git a/tests/src/core/Camera.test.ts b/tests/src/core/Camera.test.ts new file mode 100644 index 0000000000..a45573800a --- /dev/null +++ b/tests/src/core/Camera.test.ts @@ -0,0 +1,39 @@ +import { MathUtil, Matrix, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; +import { WebGLEngine } from "@oasis-engine/rhi-webgl"; +import { Camera, Entity } from "@oasis-engine/core"; +import { expect } from "chai"; + +const canvasDOM = document.createElement("canvas"); +canvasDOM.width = 1024; +canvasDOM.height = 1024; + +describe("camera test", function () { + let node: Entity; + let camera: Camera; + let identityMatrix: Matrix; + before(() => { + const engine = new WebGLEngine(canvasDOM); + node = engine.sceneManager.activeScene.createRootEntity(); + camera = node.addComponent(Camera); + // camera._onAwake(); + identityMatrix = new Matrix(); + }); + + it("constructor", () => { + expect(camera.aspectRatio).to.eq(1); + // @ts-ignore + expect(camera._renderPipeline).not.to.be.undefined; + expect(camera.entity.transform.worldPosition).not.to.be.undefined; + expect(camera.viewport).to.deep.eq(new Vector4(0, 0, 1, 1)); + expect(camera.fieldOfView).to.eq(45); + expect(camera.isOrthographic).to.eq(false); + }); +}); + +function arrayCloseTo(arr1: ArrayLike, arr2: ArrayLike) { + const len = arr1.length; + // expect(len).toEqual(arr2.length); + // for (let i = 0; i < len; i++) { + // expect(arr1[i]).toBeCloseTo(arr2[i]); + // } +} diff --git a/tests/src/rhi-webgl/WebGLEngine.test.ts b/tests/src/rhi-webgl/WebGLEngine.test.ts new file mode 100644 index 0000000000..08c3f5f86d --- /dev/null +++ b/tests/src/rhi-webgl/WebGLEngine.test.ts @@ -0,0 +1,12 @@ +import { expect } from "chai"; +import { WebGLEngine, WebCanvas } from "@oasis-engine/rhi-webgl"; + +describe("webgl engine test", () => { + it("create a webgl engine", () => { + const canvas = document.createElement("canvas"); + const engine = new WebGLEngine(canvas); + expect(engine).not.be.null; + }); +}); +// npx cross-env TS_NODE_PROJECT=tsconfig.tests.json nyc --reporter=lcov floss -p tests/src/*.test.ts -r ts-node/register +// npx cross-env TS_NODE_PROJECT=tsconfig.tests.json nyc --reporter=lcov floss --path tests -r ts-node/register diff --git a/tools/gen-changelog.js b/tools/gen-changelog.js deleted file mode 100644 index b14b7ede32..0000000000 --- a/tools/gen-changelog.js +++ /dev/null @@ -1,17 +0,0 @@ -const version = process.argv[2] || process.env.VERSION -const cc = require('conventional-changelog') -const file = `./CHANGELOG.md` -const fileStream = require('fs').createWriteStream(file) - -cc({ - preset: 'angular', - pkg: { - transform (pkg) { - pkg.version = `v${version}` - return pkg - } - }, - releaseCount: 2, -}).pipe(fileStream).on('close', () => { - console.log(`Generated release note at ${file}`) -}) \ No newline at end of file diff --git a/tools/jest/jest.transform.glsl.js b/tools/jest/jest.transform.glsl.js deleted file mode 100644 index 649ce4e53a..0000000000 --- a/tools/jest/jest.transform.glsl.js +++ /dev/null @@ -1,9 +0,0 @@ -// custom-transformer.js -"use strict"; - -module.exports = { - process(src, filename) { - const source = `module.exports = \`${src}\`;`; - return source; - } -}; diff --git a/tools/jest/jest.transform.ts.js b/tools/jest/jest.transform.ts.js deleted file mode 100644 index eb105a647a..0000000000 --- a/tools/jest/jest.transform.ts.js +++ /dev/null @@ -1,32 +0,0 @@ -// custom-transformer.js -"use strict"; - -const babel = require("@babel/core"); - -module.exports = { - process(code, filename) { - const res = babel.transformSync(code, { - filename: filename, - presets: [ - [ - "@babel/preset-env", - { - loose: true, - targets: { - node: "current" - } - } - ], - "@babel/preset-typescript" - ], - plugins: [ - ["@babel/plugin-proposal-decorators", { legacy: true }], - ["@babel/plugin-proposal-class-properties", { loose: true }], - "@babel/plugin-proposal-object-rest-spread", - "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-transform-object-assign" - ] - }); - return res.code; - } -}; diff --git a/tsconfig.tests.json b/tsconfig.tests.json new file mode 100644 index 0000000000..b0d71a1c54 --- /dev/null +++ b/tsconfig.tests.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2017", + "module": "CommonJS", + "moduleResolution": "node", + "esModuleInterop": true, + "strict": false, + "lib": [ + "ES2017", + "DOM" + ], + "declaration": true, + "inlineSourceMap": true, + "outDir": "lib" + }, + "include": ["src/*.ts"] +} \ No newline at end of file From 1fd8e0ac4b8cb3216348381f618047743853bfe6 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Wed, 11 May 2022 13:34:01 +0800 Subject: [PATCH 02/33] refactor: remove toolkit features (#780) --- packages/controls/package.json | 20 - packages/controls/src/FreeControl.ts | 289 ------- packages/controls/src/OrbitControl.ts | 800 ------------------ packages/controls/src/OrthoControl.ts | 129 --- packages/controls/src/Spherical.ts | 54 -- packages/controls/src/index.ts | 3 - packages/controls/tsconfig.json | 17 - packages/framebuffer-picker/package.json | 19 - .../framebuffer-picker/src/ColorMaterial.ts | 63 -- .../framebuffer-picker/src/ColorRenderPass.ts | 84 -- .../src/FramebufferPicker.ts | 76 -- packages/framebuffer-picker/src/color.fs.glsl | 10 - packages/framebuffer-picker/src/color.vs.glsl | 13 - packages/framebuffer-picker/src/global.d.ts | 4 - packages/framebuffer-picker/src/index.ts | 1 - packages/framebuffer-picker/tsconfig.json | 19 - packages/stats/package.json | 19 - packages/stats/src/Core.ts | 80 -- packages/stats/src/Monitor.ts | 134 --- packages/stats/src/Stats.ts | 37 - packages/stats/src/hooks/DrawCallHook.ts | 91 -- packages/stats/src/hooks/ShaderHook.ts | 54 -- packages/stats/src/hooks/TextureHook.ts | 56 -- packages/stats/src/index.ts | 6 - packages/stats/src/log.ts | 9 - packages/stats/tsconfig.json | 18 - 26 files changed, 2105 deletions(-) delete mode 100644 packages/controls/package.json delete mode 100644 packages/controls/src/FreeControl.ts delete mode 100644 packages/controls/src/OrbitControl.ts delete mode 100644 packages/controls/src/OrthoControl.ts delete mode 100644 packages/controls/src/Spherical.ts delete mode 100644 packages/controls/src/index.ts delete mode 100644 packages/controls/tsconfig.json delete mode 100755 packages/framebuffer-picker/package.json delete mode 100644 packages/framebuffer-picker/src/ColorMaterial.ts delete mode 100644 packages/framebuffer-picker/src/ColorRenderPass.ts delete mode 100644 packages/framebuffer-picker/src/FramebufferPicker.ts delete mode 100644 packages/framebuffer-picker/src/color.fs.glsl delete mode 100644 packages/framebuffer-picker/src/color.vs.glsl delete mode 100644 packages/framebuffer-picker/src/global.d.ts delete mode 100644 packages/framebuffer-picker/src/index.ts delete mode 100644 packages/framebuffer-picker/tsconfig.json delete mode 100755 packages/stats/package.json delete mode 100644 packages/stats/src/Core.ts delete mode 100644 packages/stats/src/Monitor.ts delete mode 100644 packages/stats/src/Stats.ts delete mode 100644 packages/stats/src/hooks/DrawCallHook.ts delete mode 100644 packages/stats/src/hooks/ShaderHook.ts delete mode 100644 packages/stats/src/hooks/TextureHook.ts delete mode 100644 packages/stats/src/index.ts delete mode 100644 packages/stats/src/log.ts delete mode 100644 packages/stats/tsconfig.json diff --git a/packages/controls/package.json b/packages/controls/package.json deleted file mode 100644 index 6390de10b0..0000000000 --- a/packages/controls/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@oasis-engine/controls", - "version": "0.7.0-beta.3", - "license": "MIT", - "scripts": { - "b:types": "tsc", - "lint:fix": "tslint --fix --project ./tsconfig.json" - }, - "types": "types/index.d.ts", - "browser": "dist/browser.js", - "main": "dist/main.js", - "module": "dist/module.js", - "files": [ - "dist/**/*", - "types/**/*" - ], - "dependencies": { - "oasis-engine": "0.7.0-beta.3" - } -} diff --git a/packages/controls/src/FreeControl.ts b/packages/controls/src/FreeControl.ts deleted file mode 100644 index 05e2079b98..0000000000 --- a/packages/controls/src/FreeControl.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { Entity, MathUtil, Script, Vector3 } from "oasis-engine"; -import { Spherical } from "./Spherical"; - -// Prevent universal lock. -const ESP = MathUtil.zeroTolerance; - -function includes(array, ...filterArray) { - return filterArray.some((e) => array.indexOf(e) !== -1); -} - -/** - * The camera's roaming controller, can move up and down, left and right, and rotate the viewing angle. - */ -export class FreeControl extends Script { - _forward = new Vector3(); - _right = new Vector3(); - camera: Entity; - mainElement: any; - domElement: any; - - /** - * Movement distance per second, the unit is the unit before MVP conversion. - */ - movementSpeed: number; - - /** - * Rotate speed. - */ - rotateSpeed: number; - - /** - * Simulate a ground. - */ - floorMock: boolean; - - /** - * Simulated ground height. - */ - floorY: number; - - /** - * Only rotate when press=true - */ - press: boolean; - keysForward: Array; - keysBackward: Array; - keysLeft: Array; - keysRight: Array; - - /** - * Radian of spherical.theta. - */ - private _theta: number; - - /** - * Radian of spherical.phi. - */ - private _phi: number; - - private _moveForward: boolean; - private _moveBackward: boolean; - private _moveLeft: boolean; - private _moveRight: boolean; - - private _v3Cache: Vector3; - private _spherical: Spherical; - private _rotateOri: Array; - private _events: Array<{ type: string; listener: () => {}; element?: any }>; - - constructor(entity: Entity) { - super(entity); - this.camera = entity; - // @ts-ignore - // @todo In the future, the dependence on html elements will be removed and realized through the input of the packaging engine. - this.mainElement = this.engine.canvas._webCanvas; - this.domElement = document; - - this.movementSpeed = 1.0; - this.rotateSpeed = 1.0; - - this.floorMock = true; - this.floorY = 0; - - this.press = false; - - this.keysForward = ["KeyW", "ArrowUp"]; - this.keysBackward = ["KeyS", "ArrowDown"]; - this.keysLeft = ["KeyA", "ArrowLeft"]; - this.keysRight = ["KeyD", "ArrowRight"]; - - this._theta = 0; - this._phi = 0; - - // private variables - this._moveForward = false; - this._moveBackward = false; - this._moveLeft = false; - this._moveRight = false; - - this._v3Cache = new Vector3(); - this._spherical = new Spherical(); - this._rotateOri = [0, 0]; - - this._events = [ - { type: "mousemove", listener: this.onMouseMove.bind(this) }, - { type: "touchmove", listener: this.onMouseMove.bind(this) }, - { type: "mousedown", listener: this.onMouseDown.bind(this) }, - { type: "touchstart", listener: this.onMouseDown.bind(this) }, - { type: "mouseup", listener: this.onMouseUp.bind(this) }, - { type: "touchend", listener: this.onMouseUp.bind(this) }, - { type: "keydown", listener: this.onKeyDown.bind(this), element: window }, - { type: "keyup", listener: this.onKeyUp.bind(this), element: window }, - { type: "contextmenu", listener: this.onContextMenu.bind(this) } - ]; - - this.initEvents(); - - // init spherical - this.updateSpherical(); - } - - /** - * Browser right click event. - */ - onContextMenu(event): void { - event.preventDefault(); - } - - /** - * Keyboard press event. - */ - onKeyDown(event): void { - const { code, key, keyCode } = event; - if (includes(this.keysForward, code, key, keyCode)) { - this._moveForward = true; - } else if (includes(this.keysBackward, code, key, keyCode)) { - this._moveBackward = true; - } else if (includes(this.keysLeft, code, key, keyCode)) { - this._moveLeft = true; - } else if (includes(this.keysRight, code, key, keyCode)) { - this._moveRight = true; - } - } - - /** - * Keyboard up event. - */ - onKeyUp(event): void { - const { code, key, keyCode } = event; - if (includes(this.keysForward, code, key, keyCode)) { - this._moveForward = false; - } else if (includes(this.keysBackward, code, key, keyCode)) { - this._moveBackward = false; - } else if (includes(this.keysLeft, code, key, keyCode)) { - this._moveLeft = false; - } else if (includes(this.keysRight, code, key, keyCode)) { - this._moveRight = false; - } - } - - /** - * Mouse press event. - */ - onMouseDown(event): void { - event.stopPropagation(); - event = (event.changedTouches && event.changedTouches[0]) || event; - - if (this.domElement !== document) { - this.domElement.focus(); - } - - this.press = true; - this._rotateOri = [event.clientX, event.clientY]; - } - - /** - * Mouse up event. - */ - onMouseUp(event): void { - event.preventDefault(); - event.stopPropagation(); - - this.press = false; - } - - /** - * Mouse movement event. - */ - onMouseMove(event): void { - if (this.press === false) return; - if (this.enabled === false) return; - - event.preventDefault(); - event.stopPropagation(); - event = (event.changedTouches && event.changedTouches[0]) || event; - - const movementX = event.clientX - this._rotateOri[0]; - const movementY = event.clientY - this._rotateOri[1]; - this._rotateOri[0] = event.clientX; - this._rotateOri[1] = event.clientY; - const factorX = 180 / this.mainElement.width; - const factorY = 180 / this.mainElement.height; - const actualX = movementX * factorX; - const actualY = movementY * factorY; - - this.rotate(-actualX, actualY); - } - - /** - * The angle of rotation around the y axis and the x axis respectively. - * @param alpha - Radian to rotate around the y axis - * @param beta - Radian to rotate around the x axis - */ - rotate(alpha: number = 0, beta: number = 0): void { - this._theta += MathUtil.degreeToRadian(alpha); - this._phi += MathUtil.degreeToRadian(beta); - this._phi = MathUtil.clamp(this._phi, ESP, Math.PI - ESP); - this._spherical.theta = this._theta; - this._spherical.phi = this._phi; - this._spherical.setToVec3(this._v3Cache); - Vector3.add(this.camera.transform.position, this._v3Cache, this._v3Cache); - this.camera.transform.lookAt(this._v3Cache, new Vector3(0, 1, 0)); - } - - onUpdate(delta: number): void { - if (this.enabled === false) return; - - const actualMoveSpeed = (delta / 1000) * this.movementSpeed; - this.camera.transform.getWorldForward(this._forward); - this.camera.transform.getWorldRight(this._right); - - if (this._moveForward) { - this.camera.transform.translate(this._forward.scale(actualMoveSpeed), false); - } - if (this._moveBackward) { - this.camera.transform.translate(this._forward.scale(-actualMoveSpeed), false); - } - if (this._moveLeft) { - this.camera.transform.translate(this._right.scale(-actualMoveSpeed), false); - } - if (this._moveRight) { - this.camera.transform.translate(this._right.scale(actualMoveSpeed), false); - } - - if (this.floorMock) { - const position = this.camera.transform.position; - if (position.y !== this.floorY) { - this.camera.transform.setPosition(position.x, this.floorY, position.z); - } - } - } - - /** - * Register browser events. - */ - initEvents(): void { - this._events.forEach((ele) => { - if (ele.element) { - ele.element.addEventListener(ele.type, ele.listener, false); - } else { - this.mainElement.addEventListener(ele.type, ele.listener, false); - } - }); - } - - onDestroy(): void { - this._events.forEach((ele) => { - if (ele.element) { - ele.element.removeEventListener(ele.type, ele.listener, false); - } else { - this.mainElement.removeEventListener(ele.type, ele.listener, false); - } - }); - } - - /** - * must updateSpherical after quaternion has been changed - * @example - * Entity#lookAt([0,1,0],[0,1,0]); - * AFreeControls#updateSpherical(); - */ - updateSpherical(): void { - this._v3Cache.setValue(0, 0, -1); - Vector3.transformByQuat(this._v3Cache, this.camera.transform.rotationQuaternion, this._v3Cache); - this._spherical.setFromVec3(this._v3Cache); - this._theta = this._spherical.theta; - this._phi = this._spherical.phi; - } -} diff --git a/packages/controls/src/OrbitControl.ts b/packages/controls/src/OrbitControl.ts deleted file mode 100644 index b3ede278c4..0000000000 --- a/packages/controls/src/OrbitControl.ts +++ /dev/null @@ -1,800 +0,0 @@ -"use strict"; -import { Entity, Matrix, Script, Vector2, Vector3 } from "oasis-engine"; -import { Spherical } from "./Spherical"; - -type MouseWheelEvent = any; - -/** - * The camera's track controller, can rotate, zoom, pan, support mouse and touch events. - */ -export class OrbitControl extends Script { - camera: Entity; - domElement: HTMLElement | Document; - mainElement: HTMLCanvasElement; - fov: number; - target: Vector3; - up: Vector3; - minDistance: number; - maxDistance: number; - minZoom: number; - maxZoom: number; - enableDamping: boolean; - zoomFactor: number; - enableRotate: boolean; - keyPanSpeed: number; - minPolarAngle: number; - maxPolarAngle: number; - minAzimuthAngle: number; - maxAzimuthAngle: number; - enableZoom: boolean; - dampingFactor: number; - zoomSpeed: number; - enablePan: boolean; - autoRotate: boolean; - /** The radian of automatic rotation per second. */ - autoRotateSpeed: number = Math.PI; - rotateSpeed: number; - enableKeys: boolean; - keys: { LEFT: number; RIGHT: number; UP: number; BOTTOM: number }; - mouseButtons: { ORBIT: number; ZOOM: number; PAN: number }; - touchFingers: { ORBIT: number; ZOOM: number; PAN: number }; - STATE: { - TOUCH_ROTATE: number; - ROTATE: number; - TOUCH_PAN: number; - ZOOM: number; - NONE: number; - PAN: number; - TOUCH_ZOOM: number; - }; - mouseUpEvents: { listener: any; type: string }[]; - constEvents: { listener: any; type: string; element?: Window }[]; - - private _position: Vector3; - private _offset: Vector3; - private _spherical: Spherical; - private _sphericalDelta: Spherical; - private _sphericalDump: Spherical; - private _zoomFrag: number; - private _scale: number; - private _panOffset: Vector3; - private _isMouseUp: boolean; - private _vPan: Vector3; - private _state: any; - private _rotateStart: Vector2; - private _rotateEnd: Vector2; - private _rotateDelta: Vector2; - private _panStart: Vector2; - private _panEnd: Vector2; - private _panDelta: Vector2; - private _zoomStart: Vector2; - private _zoomEnd: Vector2; - private _zoomDelta: Vector2; - - constructor(entity: Entity) { - super(entity); - - this.camera = entity; - // @ts-ignore - // @todo In the future, the dependence on html elements will be removed and realized through the input of the packaging engine. - this.mainElement = this.engine.canvas._webCanvas; - this.domElement = document; - this.fov = 45; - - // Target position. - this.target = new Vector3(); - - // Up vector - this.up = new Vector3(0, 1, 0); - - /** - * The minimum distance, the default is 0.1, should be greater than 0. - */ - this.minDistance = 0.1; - /** - * The maximum distance, the default is infinite, should be greater than the minimum distance - */ - this.maxDistance = Infinity; - - /** - * Minimum zoom speed, the default is 0.0. - * @member {Number} - */ - this.minZoom = 0.0; - - /** - * Maximum zoom speed, the default is positive infinity. - */ - this.maxZoom = Infinity; - - /** - * The minimum radian in the vertical direction, the default is 0 radian, the value range is 0 - Math.PI. - */ - this.minPolarAngle = 0; - - /** - * The maximum radian in the vertical direction, the default is Math.PI, and the value range is 0 - Math.PI. - */ - this.maxPolarAngle = Math.PI; - - /** - * The minimum radian in the horizontal direction, the default is negative infinity. - */ - this.minAzimuthAngle = -Infinity; - - /** - * The maximum radian in the horizontal direction, the default is positive infinity. - */ - this.maxAzimuthAngle = Infinity; - - /** - * Whether to enable camera damping, the default is true. - */ - this.enableDamping = true; - - /** - * Rotation damping parameter, default is 0.1 . - */ - this.dampingFactor = 0.1; - - /** - * Zoom damping parameter, default is 0.2 . - */ - this.zoomFactor = 0.2; - - /** - * Whether to enable zoom, the default is true. - */ - this.enableZoom = true; - - /** - * Camera zoom speed, the default is 1.0. - */ - this.zoomSpeed = 1.0; - - /** - * Whether to enable rotation, the default is true. - */ - this.enableRotate = true; - - /** - * Rotation speed, default is 1.0 . - */ - this.rotateSpeed = 1.0; - - /** - * Whether to enable translation, the default is true. - */ - this.enablePan = true; - - /** - * Keyboard translation speed, the default is 7.0 . - */ - this.keyPanSpeed = 7.0; - - /** - * Whether to automatically rotate the camera, the default is false. - */ - this.autoRotate = false; - - /** - * Whether to enable keyboard. - */ - this.enableKeys = false; - this.keys = { - LEFT: 37, - UP: 38, - RIGHT: 39, - BOTTOM: 40 - }; - - // Control keys. - this.mouseButtons = { - ORBIT: 0, - ZOOM: 1, - PAN: 2 - }; - - this.touchFingers = { - ORBIT: 1, - ZOOM: 2, - PAN: 3 - }; - - // Reuse objects to prevent excessive stack allocation. - // update - this._position = new Vector3(); - this._offset = new Vector3(); - this._spherical = new Spherical(); - this._sphericalDelta = new Spherical(); - this._sphericalDump = new Spherical(); - this._zoomFrag = 0; - this._scale = 1; - this._panOffset = new Vector3(); - this._isMouseUp = true; - - // pan - this._vPan = new Vector3(); - - // state - this._rotateStart = new Vector2(); - this._rotateEnd = new Vector2(); - this._rotateDelta = new Vector2(); - - this._panStart = new Vector2(); - this._panEnd = new Vector2(); - this._panDelta = new Vector2(); - - this._zoomStart = new Vector2(); - this._zoomEnd = new Vector2(); - this._zoomDelta = new Vector2(); - - this.STATE = { - NONE: -1, - ROTATE: 0, - ZOOM: 1, - PAN: 2, - TOUCH_ROTATE: 3, - TOUCH_ZOOM: 4, - TOUCH_PAN: 5 - }; - this._state = this.STATE.NONE; - - this.constEvents = [ - { type: "mousedown", listener: this.onMouseDown.bind(this) }, - { type: "wheel", listener: this.onMouseWheel.bind(this) }, - { type: "keydown", listener: this.onKeyDown.bind(this), element: window }, - { type: "touchstart", listener: this.onTouchStart.bind(this) }, - { type: "touchmove", listener: this.onTouchMove.bind(this) }, - { type: "touchend", listener: this.onTouchEnd.bind(this) }, - { type: "contextmenu", listener: this.onContextMenu.bind(this) } - ]; - - this.mouseUpEvents = [ - { type: "mousemove", listener: this.onMouseMove.bind(this) }, - { type: "mouseup", listener: this.onMouseUp.bind(this) } - ]; - - this.constEvents.forEach((ele) => { - if (ele.element) { - ele.element.addEventListener(ele.type, ele.listener, false); - } else { - this.mainElement.addEventListener(ele.type, ele.listener, false); - } - }); - } - - onDisable(): void { - const element = this.domElement === document ? this.domElement.body : this.domElement; - this.mainElement.removeEventListener(this.mouseUpEvents[0].type, this.mouseUpEvents[0].listener, false); - element.removeEventListener(this.mouseUpEvents[1].type, this.mouseUpEvents[1].listener, false); - } - - onDestroy() { - this.constEvents.forEach((ele) => { - if (ele.element) { - ele.element.removeEventListener(ele.type, ele.listener, false); - } else { - this.mainElement.removeEventListener(ele.type, ele.listener, false); - } - }); - const element = this.domElement === document ? this.domElement.body : this.domElement; - this.mainElement.removeEventListener(this.mouseUpEvents[0].type, this.mouseUpEvents[0].listener, false); - element.removeEventListener(this.mouseUpEvents[1].type, this.mouseUpEvents[1].listener, false); - } - - onUpdate(dtime) { - if (!this.enabled) return; - - const position: Vector3 = this.camera.transform.position; - position.cloneTo(this._offset); - this._offset.subtract(this.target); - this._spherical.setFromVec3(this._offset); - - if (this.autoRotate && this._state === this.STATE.NONE) { - this.rotateLeft(this.getAutoRotationAngle(dtime)); - } - - this._spherical.theta += this._sphericalDelta.theta; - this._spherical.phi += this._sphericalDelta.phi; - - this._spherical.theta = Math.max(this.minAzimuthAngle, Math.min(this.maxAzimuthAngle, this._spherical.theta)); - this._spherical.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this._spherical.phi)); - this._spherical.makeSafe(); - - if (this._scale !== 1) { - this._zoomFrag = this._spherical.radius * (this._scale - 1); - } - - this._spherical.radius += this._zoomFrag; - this._spherical.radius = Math.max(this.minDistance, Math.min(this.maxDistance, this._spherical.radius)); - - this.target.add(this._panOffset); - this._spherical.setToVec3(this._offset); - this.target.cloneTo(this._position); - this._position.add(this._offset); - - this.camera.transform.position = this._position; - this.camera.transform.lookAt(this.target, this.up); - - if (this.enableDamping === true) { - this._sphericalDump.theta *= 1 - this.dampingFactor; - this._sphericalDump.phi *= 1 - this.dampingFactor; - this._zoomFrag *= 1 - this.zoomFactor; - - if (this._isMouseUp) { - this._sphericalDelta.theta = this._sphericalDump.theta; - this._sphericalDelta.phi = this._sphericalDump.phi; - } else { - this._sphericalDelta.set(0, 0, 0); - } - } else { - this._sphericalDelta.set(0, 0, 0); - this._zoomFrag = 0; - } - - this._scale = 1; - this._panOffset.setValue(0, 0, 0); - } - - /** - * Get the radian of automatic rotation. - */ - getAutoRotationAngle(dtime: number) { - return (this.autoRotateSpeed / 1000) * dtime; - } - - /** - * Get zoom value. - */ - getZoomScale() { - return Math.pow(0.95, this.zoomSpeed); - } - - /** - * Rotate to the left by a certain radian. - * @param radian - Radian value of rotation - */ - rotateLeft(radian: number) { - this._sphericalDelta.theta -= radian; - if (this.enableDamping) { - this._sphericalDump.theta = -radian; - } - } - - /** - * Rotate to the right by a certain radian. - * @param radian - Radian value of rotation - */ - rotateUp(radian: number) { - this._sphericalDelta.phi -= radian; - if (this.enableDamping) { - this._sphericalDump.phi = -radian; - } - } - - /** - * Pan left. - */ - panLeft(distance: number, worldMatrix: Matrix) { - const e = worldMatrix.elements; - this._vPan.setValue(e[0], e[1], e[2]); - this._vPan.scale(distance); - this._panOffset.add(this._vPan); - } - - /** - * Pan right. - */ - panUp(distance: number, worldMatrix: Matrix) { - const e = worldMatrix.elements; - this._vPan.setValue(e[4], e[5], e[6]); - this._vPan.scale(distance); - this._panOffset.add(this._vPan); - } - - /** - * Pan. - * @param deltaX - The amount of translation from the screen distance in the x direction - * @param deltaY - The amount of translation from the screen distance in the y direction - */ - pan(deltaX: number, deltaY: number) { - // perspective only - const position: Vector3 = this.camera.transform.position; - position.cloneTo(this._vPan); - this._vPan.subtract(this.target); - let targetDistance = this._vPan.length(); - - targetDistance *= (this.fov / 2) * (Math.PI / 180); - - this.panLeft(-2 * deltaX * (targetDistance / this.mainElement.clientHeight), this.camera.transform.worldMatrix); - this.panUp(2 * deltaY * (targetDistance / this.mainElement.clientHeight), this.camera.transform.worldMatrix); - } - - /** - * Zoom in. - */ - zoomIn(zoomScale: number): void { - // perspective only - this._scale *= zoomScale; - } - - /** - * Zoom out. - */ - zoomOut(zoomScale: number): void { - // perspective only - this._scale /= zoomScale; - } - - /** - * Rotation parameter update on mouse click. - */ - handleMouseDownRotate(event) { - this._rotateStart.setValue(event.clientX, event.clientY); - } - - /** - * Zoom parameter update on mouse click. - */ - handleMouseDownZoom(event) { - this._zoomStart.setValue(event.clientX, event.clientY); - } - - /** - * Pan parameter update on mouse click. - */ - handleMouseDownPan(event) { - this._panStart.setValue(event.clientX, event.clientY); - } - - /** - * Rotation parameter update when the mouse moves. - */ - handleMouseMoveRotate(event) { - this._rotateEnd.setValue(event.clientX, event.clientY); - Vector2.subtract(this._rotateEnd, this._rotateStart, this._rotateDelta); - - this.rotateLeft(2 * Math.PI * (this._rotateDelta.x / this.mainElement.clientWidth) * this.rotateSpeed); - this.rotateUp(2 * Math.PI * (this._rotateDelta.y / this.mainElement.clientHeight) * this.rotateSpeed); - - this._rotateEnd.cloneTo(this._rotateStart); - } - - /** - * Zoom parameters update when the mouse moves. - */ - handleMouseMoveZoom(event) { - this._zoomEnd.setValue(event.clientX, event.clientY); - Vector2.subtract(this._zoomEnd, this._zoomStart, this._zoomDelta); - - if (this._zoomDelta.y > 0) { - this.zoomOut(this.getZoomScale()); - } else if (this._zoomDelta.y < 0) { - this.zoomIn(this.getZoomScale()); - } - - this._zoomEnd.cloneTo(this._zoomStart); - } - - /** - * Pan parameters update when the mouse moves. - */ - handleMouseMovePan(event: MouseEvent): void { - this._panEnd.setValue(event.clientX, event.clientY); - Vector2.subtract(this._panEnd, this._panStart, this._panDelta); - - this.pan(this._panDelta.x, this._panDelta.y); - - this._panEnd.cloneTo(this._panStart); - } - - /** - * Zoom parameter update when the mouse wheel is scrolled. - */ - handleMouseWheel(event: MouseWheelEvent): void { - if (event.deltaY < 0) { - this.zoomIn(this.getZoomScale()); - } else if (event.deltaY > 0) { - this.zoomOut(this.getZoomScale()); - } - } - - /** - * Pan parameter update when keyboard is pressed. - */ - handleKeyDown(event: KeyboardEvent) { - switch (event.keyCode) { - case this.keys.UP: - this.pan(0, this.keyPanSpeed); - break; - case this.keys.BOTTOM: - this.pan(0, -this.keyPanSpeed); - break; - case this.keys.LEFT: - this.pan(this.keyPanSpeed, 0); - break; - case this.keys.RIGHT: - this.pan(-this.keyPanSpeed, 0); - break; - } - } - - /** - * Rotation parameter update when touch is dropped. - */ - handleTouchStartRotate(event: TouchEvent) { - this._rotateStart.setValue(event.touches[0].pageX, event.touches[0].pageY); - } - - /** - * Zoom parameter update when touch down. - */ - handleTouchStartZoom(event: TouchEvent) { - const dx = event.touches[0].pageX - event.touches[1].pageX; - const dy = event.touches[0].pageY - event.touches[1].pageY; - - const distance = Math.sqrt(dx * dx + dy * dy); - - this._zoomStart.setValue(0, distance); - } - - /** - * Update the translation parameter when touch down. - */ - handleTouchStartPan(event: TouchEvent) { - this._panStart.setValue(event.touches[0].pageX, event.touches[0].pageY); - } - - /** - * Rotation parameter update when touch to move. - */ - handleTouchMoveRotate(event: TouchEvent) { - this._rotateEnd.setValue(event.touches[0].pageX, event.touches[0].pageY); - Vector2.subtract(this._rotateEnd, this._rotateStart, this._rotateDelta); - - this.rotateLeft(((2 * Math.PI * this._rotateDelta.x) / this.mainElement.clientWidth) * this.rotateSpeed); - this.rotateUp(((2 * Math.PI * this._rotateDelta.y) / this.mainElement.clientHeight) * this.rotateSpeed); - - this._rotateEnd.cloneTo(this._rotateStart); - } - - /** - * Zoom parameter update when touch to move. - */ - handleTouchMoveZoom(event) { - const dx = event.touches[0].pageX - event.touches[1].pageX; - const dy = event.touches[0].pageY - event.touches[1].pageY; - - const distance = Math.sqrt(dx * dx + dy * dy); - - this._zoomEnd.setValue(0, distance); - - Vector2.subtract(this._zoomEnd, this._zoomStart, this._zoomDelta); - - if (this._zoomDelta.y > 0) { - this.zoomIn(this.getZoomScale()); - } else if (this._zoomDelta.y < 0) { - this.zoomOut(this.getZoomScale()); - } - - this._zoomEnd.cloneTo(this._zoomStart); - } - - /** - * Pan parameter update when touch moves. - */ - handleTouchMovePan(event: TouchEvent) { - this._panEnd.setValue(event.touches[0].pageX, event.touches[0].pageY); - - Vector2.subtract(this._panEnd, this._panStart, this._panDelta); - - this.pan(this._panDelta.x, this._panDelta.y); - - this._panEnd.cloneTo(this._panStart); - } - - /** - * Total handling of mouse down events. - */ - onMouseDown(event: MouseEvent) { - if (this.enabled === false) return; - - event.preventDefault(); - - this._isMouseUp = false; - - switch (event.button) { - case this.mouseButtons.ORBIT: - if (this.enableRotate === false) return; - - this.handleMouseDownRotate(event); - this._state = this.STATE.ROTATE; - break; - - case this.mouseButtons.ZOOM: - if (this.enableZoom === false) return; - - this.handleMouseDownZoom(event); - this._state = this.STATE.ZOOM; - break; - - case this.mouseButtons.PAN: - if (this.enablePan === false) return; - - this.handleMouseDownPan(event); - this._state = this.STATE.PAN; - break; - } - - if (this._state !== this.STATE.NONE) { - const element = this.domElement === document ? this.domElement.body : this.domElement; - this.mainElement.addEventListener(this.mouseUpEvents[0].type, this.mouseUpEvents[0].listener, false); - element.addEventListener(this.mouseUpEvents[1].type, this.mouseUpEvents[1].listener, false); - } - } - - /** - * Total handling of mouse movement events. - */ - onMouseMove(event: MouseEvent) { - if (this.enabled === false) return; - - event.preventDefault(); - - switch (this._state) { - case this.STATE.ROTATE: - if (this.enableRotate === false) return; - - this.handleMouseMoveRotate(event); - break; - - case this.STATE.ZOOM: - if (this.enableZoom === false) return; - - this.handleMouseMoveZoom(event); - break; - - case this.STATE.PAN: - if (this.enablePan === false) return; - - this.handleMouseMovePan(event); - break; - } - } - - /** - * Total handling of mouse up events. - */ - onMouseUp() { - if (this.enabled === false) return; - - this._isMouseUp = true; - - this.mouseUpEvents.forEach((ele) => { - const element = this.domElement === document ? this.domElement.body : this.domElement; - element.removeEventListener(ele.type, ele.listener, false); - this.mainElement.removeEventListener(ele.type, ele.listener, false); - }); - - this._state = this.STATE.NONE; - } - - /** - * Total handling of mouse wheel events. - */ - onMouseWheel(event: MouseWheelEvent) { - if ( - this.enabled === false || - this.enableZoom === false || - (this._state !== this.STATE.NONE && this._state !== this.STATE.ROTATE) - ) - return; - - event.preventDefault(); - event.stopPropagation(); - - this.handleMouseWheel(event); - } - - /** - * Total handling of keyboard down events. - */ - onKeyDown(event: KeyboardEvent) { - if (this.enabled === false || this.enableKeys === false || this.enablePan === false) return; - - this.handleKeyDown(event); - } - - /** - * Total handling of touch start events. - */ - onTouchStart(event: TouchEvent) { - if (this.enabled === false) return; - - this._isMouseUp = false; - - switch (event.touches.length) { - case this.touchFingers.ORBIT: - if (this.enableRotate === false) return; - - this.handleTouchStartRotate(event); - this._state = this.STATE.TOUCH_ROTATE; - - break; - - case this.touchFingers.ZOOM: - if (this.enableZoom === false) return; - - this.handleTouchStartZoom(event); - this._state = this.STATE.TOUCH_ZOOM; - - break; - - case this.touchFingers.PAN: - if (this.enablePan === false) return; - - this.handleTouchStartPan(event); - this._state = this.STATE.TOUCH_PAN; - - break; - - default: - this._state = this.STATE.NONE; - } - } - - /** - * Total handling of touch movement events. - */ - onTouchMove(event: TouchEvent) { - if (this.enabled === false) return; - - event.preventDefault(); - event.stopPropagation(); - - switch (event.touches.length) { - case this.touchFingers.ORBIT: - if (this.enableRotate === false) return; - if (this._state !== this.STATE.TOUCH_ROTATE) return; - this.handleTouchMoveRotate(event); - - break; - - case this.touchFingers.ZOOM: - if (this.enableZoom === false) return; - if (this._state !== this.STATE.TOUCH_ZOOM) return; - this.handleTouchMoveZoom(event); - - break; - - case this.touchFingers.PAN: - if (this.enablePan === false) return; - if (this._state !== this.STATE.TOUCH_PAN) return; - this.handleTouchMovePan(event); - - break; - - default: - this._state = this.STATE.NONE; - } - } - - /** - * Total handling of touch end events. - */ - onTouchEnd() { - if (this.enabled === false) return; - - this._isMouseUp = true; - this._state = this.STATE.NONE; - } - - /** - * Context event hiding. - */ - onContextMenu(event) { - if (this.enabled === false) return; - event.preventDefault(); - } -} diff --git a/packages/controls/src/OrthoControl.ts b/packages/controls/src/OrthoControl.ts deleted file mode 100644 index ccb85b16ee..0000000000 --- a/packages/controls/src/OrthoControl.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Camera, Entity, Logger, Script, Vector2, Vector3 } from "oasis-engine"; - -/** - * The camera's 2D controller, can zoom and pan. - */ -export class OrthoControl extends Script { - cameraEntity: Entity; - camera: Camera; - - private _zoomSpeed: number = 1.0; - private _zoomScale: number = 1.0; - private _zoomScaleUnit: number = 25.0; - private _zoomMinSize: number = 0.0; - private _zoomMaxSize: number = Infinity; - private _isPanStart: boolean = false; - private _panStartPos: Vector3 = new Vector3(); - private _panStart: Vector2 = new Vector2(); - private _panEnd: Vector2 = new Vector2(); - private _panDelta: Vector2 = new Vector2(); - - /** - * The zoom speed. - */ - get zoomSpeed(): number { - return this._zoomSpeed; - } - - set zoomSpeed(value: number) { - this._zoomSpeed = value; - } - - constructor(entity: Entity) { - super(entity); - - this.cameraEntity = entity; - this.camera = entity.getComponent(Camera); - } - - onUpdate(dt: number): void { - if (this._zoomScale !== 1) { - const { camera } = this; - const sizeDiff = this._zoomScaleUnit * (this._zoomScale - 1); - const size = camera.orthographicSize + sizeDiff; - camera.orthographicSize = Math.max(this._zoomMinSize, Math.min(this._zoomMaxSize, size)); - this._zoomScale = 1; - } - - if (this._isPanStart) { - const { _panStart: panStart, _panEnd: panEnd } = this; - const panDelta = this._panDelta; - Vector2.subtract(panEnd, panStart, panDelta); - if (panDelta.x === 0 && panDelta.y === 0) { - return; - } - this._handlePan(); - panEnd.cloneTo(panStart); - } - } - - /** - * Zoom in. - */ - zoomIn(): void { - if (!this.enabled) return; - this._zoomScale *= this._getZoomScale(); - } - - /** - * Zoom out. - */ - zoomOut(): void { - if (!this.enabled) return; - this._zoomScale /= this._getZoomScale(); - } - - /** - * Start pan. - * @param x - The x-axis coordinate (unit: pixel) - * @param y - The y-axis coordinate (unit: pixel) - */ - panStart(x: number, y: number): void { - if (!this.enabled) return; - - this.cameraEntity.transform.position.cloneTo(this._panStartPos); - this._panStart.setValue(x, y); - this._panEnd.setValue(x, y); - this._isPanStart = true; - } - - /** - * Panning. - * @param x - The x-axis coordinate (unit: pixel) - * @param y - The y-axis coordinate (unit: pixel) - * - * @remarks Make sure to call panStart before calling panMove. - */ - panMove(x: number, y: number): void { - if (!this.enabled) return; - if (!this._isPanStart) { - Logger.warn("Make sure to call panStart before calling panMove"); - } - this._panEnd.setValue(x, y); - } - - /** - * End pan. - */ - panEnd(): void { - if (!this.enabled) return; - this._isPanStart = false; - } - - private _getZoomScale(): number { - return Math.pow(0.95, this.zoomSpeed); - } - - private _handlePan(): void { - const { width, height } = this.engine.canvas; - const { x, y } = this._panDelta; - const { camera } = this; - const doubleOrthographicSize = camera.orthographicSize * 2; - const width3D = doubleOrthographicSize * camera.aspectRatio; - const height3D = doubleOrthographicSize; - const pos = this._panStartPos; - pos.x -= (x * width3D) / width; - pos.y += (y * height3D) / height; - this.cameraEntity.transform.position = pos; - } -} diff --git a/packages/controls/src/Spherical.ts b/packages/controls/src/Spherical.ts deleted file mode 100644 index 1d01aed262..0000000000 --- a/packages/controls/src/Spherical.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Vector3, MathUtil } from "oasis-engine"; - -// Prevent gimbal lock. -const ESP = MathUtil.zeroTolerance; - -// Spherical. -export class Spherical { - public radius; - public phi; - public theta; - - constructor(radius?, phi?, theta?) { - this.radius = radius !== undefined ? radius : 1.0; - this.phi = phi !== undefined ? phi : 0; - this.theta = theta !== undefined ? theta : 0; - } - - set(radius, phi, theta) { - this.radius = radius; - this.phi = phi; - this.theta = theta; - - return this; - } - - makeSafe() { - this.phi = MathUtil.clamp(this.phi, ESP, Math.PI - ESP); - return this; - } - - setFromVec3(v3: Vector3) { - this.radius = v3.length(); - if (this.radius === 0) { - this.theta = 0; - this.phi = 0; - } else { - this.theta = Math.atan2(v3.x, v3.z); - this.phi = Math.acos(MathUtil.clamp(v3.y / this.radius, -1, 1)); - } - - return this; - } - - setToVec3(v3: Vector3) { - const sinPhiRadius = Math.sin(this.phi) * this.radius; - v3.setValue( - sinPhiRadius * Math.sin(this.theta), - Math.cos(this.phi) * this.radius, - sinPhiRadius * Math.cos(this.theta) - ); - - return this; - } -} diff --git a/packages/controls/src/index.ts b/packages/controls/src/index.ts deleted file mode 100644 index 16f610636c..0000000000 --- a/packages/controls/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FreeControl } from "./FreeControl"; -export { OrbitControl } from "./OrbitControl"; -export { OrthoControl } from "./OrthoControl"; diff --git a/packages/controls/tsconfig.json b/packages/controls/tsconfig.json deleted file mode 100644 index 51fad95808..0000000000 --- a/packages/controls/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "esnext", - "declaration": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "declarationDir": "types", - "skipLibCheck": true, - "emitDeclarationOnly": true, - "sourceMap": true - }, - "include": [ - "src/**/*" - ] -} diff --git a/packages/framebuffer-picker/package.json b/packages/framebuffer-picker/package.json deleted file mode 100755 index 819349e156..0000000000 --- a/packages/framebuffer-picker/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "@oasis-engine/framebuffer-picker", - "version": "0.7.0-beta.3", - "license": "MIT", - "main": "dist/main.js", - "module": "dist/module.js", - "browser": "dist/browser.js", - "scripts": { - "b:types": "tsc" - }, - "types": "types/index.d.ts", - "files": [ - "dist/**/*", - "types/**/*" - ], - "dependencies": { - "oasis-engine": "0.7.0-beta.3" - } -} diff --git a/packages/framebuffer-picker/src/ColorMaterial.ts b/packages/framebuffer-picker/src/ColorMaterial.ts deleted file mode 100644 index 44216f45e3..0000000000 --- a/packages/framebuffer-picker/src/ColorMaterial.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Engine, Logger, Material, RenderElement, Shader, Vector3 } from "oasis-engine"; -import fs from "./color.fs.glsl"; -import vs from "./color.vs.glsl"; - -Shader.create("framebuffer-picker-color", vs, fs); - -/** - * Color material, render as marker. - */ -export class ColorMaterial extends Material { - private _currentId: number = 0; - private _primitivesMap = []; - - constructor(engine: Engine) { - super(engine, Shader.find("framebuffer-picker-color")); - } - - /** - * Reset id and renderer element table. - */ - reset(): void { - this._currentId = 0; - this._primitivesMap = []; - } - - /** - * Convert id to RGB color value, 0 and 0xffffff are illegal values. - */ - id2Color(id: number): Vector3 { - if (id >= 0xffffff) { - Logger.warn("Framebuffer Picker encounter primitive's id greater than " + 0xffffff); - return new Vector3(0, 0, 0); - } - - const color = new Vector3((id & 0xff) / 255, ((id & 0xff00) >> 8) / 255, ((id & 0xff0000) >> 16) / 255); - return color; - } - - /** - * Convert RGB color to id. - * @param color - Color - */ - color2Id(color): number { - return color[0] | (color[1] << 8) | (color[2] << 16); - } - - /** - * Get renderer element by color. - */ - getObjectByColor(color) { - return this._primitivesMap[this.color2Id(color)]; - } - - /** - * @override - */ - _preRender(renderElement: RenderElement) { - const { component, mesh } = renderElement; - this._currentId += 1; - this._primitivesMap[this._currentId] = { component, mesh }; - component.shaderData.setVector3("u_colorId", this.id2Color(this._currentId)); - } -} diff --git a/packages/framebuffer-picker/src/ColorRenderPass.ts b/packages/framebuffer-picker/src/ColorRenderPass.ts deleted file mode 100644 index ed6e446667..0000000000 --- a/packages/framebuffer-picker/src/ColorRenderPass.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Camera, Engine, Layer, RenderPass, RenderTarget, Texture2D } from "oasis-engine"; -import { ColorMaterial } from "./ColorMaterial"; - -/** - * Color render Pass, used to render marker. - */ -class ColorRenderPass extends RenderPass { - private _needPick: boolean; - private onPick: Function; - private _pickPos; - - constructor(name: string, priority: number, renderTarget: RenderTarget, mask: Layer, engine?: Engine) { - super(name, priority, renderTarget, new ColorMaterial(engine), mask); - - this._needPick = false; - this.onPick = (o: any) => console.log(o); - } - - /** - * Determine whether need to render pass, reset state. - * @override - */ - preRender() { - if (this._needPick) { - this.enabled = true; - (this.replaceMaterial as ColorMaterial).reset(); - } else { - this.enabled = false; - } - } - - /** - * Determine whether to pick up. - * @override - */ - postRender(camera: Camera) { - if (this._needPick) { - const color = this.readColorFromRenderTarget(camera); - const object = (this.replaceMaterial as ColorMaterial).getObjectByColor(color); - this._needPick = false; - - if (this.onPick) this.onPick(object); - } - } - - /** - * Pick up coordinate pixels. - */ - pick(x: number, y: number) { - this._pickPos = [x, y]; - this._needPick = true; - } - - /** - * Get pixel color value from framebuffer. - */ - readColorFromRenderTarget(camera: Camera) { - const gl = camera.engine._hardwareRenderer.gl; - const screenPoint = this._pickPos; - const canvas = gl.canvas; - const clientWidth = canvas.clientWidth; - const clientHeight = canvas.clientHeight; - const canvasWidth = gl.drawingBufferWidth; - const canvasHeight = gl.drawingBufferHeight; - - const px = (screenPoint[0] / clientWidth) * canvasWidth; - const py = (screenPoint[1] / clientHeight) * canvasHeight; - - const viewport = camera.viewport; - const viewWidth = (viewport.z - viewport.x) * canvasWidth; - const viewHeight = (viewport.w - viewport.y) * canvasHeight; - - const nx = (px - viewport.x) / viewWidth; - const ny = (py - viewport.y) / viewHeight; - const left = Math.floor(nx * (this.renderTarget.width - 1)); - const bottom = Math.floor((1 - ny) * (this.renderTarget.height - 1)); - const pixel = new Uint8Array(4); - - (this.renderTarget.getColorTexture()).getPixelBuffer(left, bottom, 1, 1, 0, pixel); - return pixel; - } -} - -export { ColorRenderPass }; diff --git a/packages/framebuffer-picker/src/FramebufferPicker.ts b/packages/framebuffer-picker/src/FramebufferPicker.ts deleted file mode 100644 index e9b6766670..0000000000 --- a/packages/framebuffer-picker/src/FramebufferPicker.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Camera, Entity, RenderTarget, Script, Texture2D } from "oasis-engine"; -import { ColorRenderPass } from "./ColorRenderPass"; - -/** - * Framebuffer picker. - * @remarks Can pick up renderer at pixel level. - */ -export class FramebufferPicker extends Script { - public colorRenderTarget: RenderTarget; - public colorRenderPass: ColorRenderPass; - - private _camera: Camera; - private _needPick: boolean; - private _pickPos: [number, number]; - - /** - * Camera. - */ - get camera(): Camera { - return this._camera; - } - - set camera(value: Camera) { - if (this._camera !== value) { - this._camera = value; - //@ts-ignore - this.camera._renderPipeline.addRenderPass(this.colorRenderPass); - } - } - - constructor(entity: Entity) { - super(entity); - const width = 1024; - const height = 1024; - this.colorRenderTarget = new RenderTarget(this.engine, width, height, new Texture2D(this.engine, width, height)); - this.colorRenderPass = new ColorRenderPass("ColorRenderTarget_FBP", -1, this.colorRenderTarget, 0, this.engine); - } - - /** - * Set the callback function after pick up. - * @param {Function} fun Callback function. if there is an renderer selected, the parameter 1 is {component, primitive }, otherwise it is undefined - */ - set onPick(fun: Function) { - if (typeof fun === "function") { - (this.colorRenderPass as any).onPick = fun; - } - } - - /** - * Pick the object at the screen coordinate position. - * @param offsetX Relative X coordinate of the canvas - * @param offsetY Relative Y coordinate of the canvas - */ - pick(offsetX: number, offsetY: number) { - if (this.enabled) { - this._needPick = true; - this._pickPos = [offsetX, offsetY]; - } - } - - onUpdate(deltaTime: number) { - super.onUpdate(deltaTime); - - if (this.enabled && this._needPick) { - this.colorRenderPass.pick(this._pickPos[0], this._pickPos[1]); - this._needPick = false; - } - } - - onDestroy() { - if (!this.camera.destroyed) { - //@ts-ignore - this.camera._renderPipeline.removeRenderPass(this.colorRenderPass); - } - } -} diff --git a/packages/framebuffer-picker/src/color.fs.glsl b/packages/framebuffer-picker/src/color.fs.glsl deleted file mode 100644 index 541c2ffc21..0000000000 --- a/packages/framebuffer-picker/src/color.fs.glsl +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -uniform vec3 u_colorId; - -void main() { - - gl_FragColor = vec4( u_colorId, 1.0 ); - -} diff --git a/packages/framebuffer-picker/src/color.vs.glsl b/packages/framebuffer-picker/src/color.vs.glsl deleted file mode 100644 index cd588ab990..0000000000 --- a/packages/framebuffer-picker/src/color.vs.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include - -void main() { - - #include - #include - #include - #include - #include - -} diff --git a/packages/framebuffer-picker/src/global.d.ts b/packages/framebuffer-picker/src/global.d.ts deleted file mode 100644 index 35e0469eab..0000000000 --- a/packages/framebuffer-picker/src/global.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.glsl" { - const value: string; - export default value; -} diff --git a/packages/framebuffer-picker/src/index.ts b/packages/framebuffer-picker/src/index.ts deleted file mode 100644 index ae50ce5bfd..0000000000 --- a/packages/framebuffer-picker/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { FramebufferPicker } from "./FramebufferPicker"; diff --git a/packages/framebuffer-picker/tsconfig.json b/packages/framebuffer-picker/tsconfig.json deleted file mode 100644 index 757c16677a..0000000000 --- a/packages/framebuffer-picker/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "esnext", - "declaration": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "declarationDir": "types", - "emitDeclarationOnly": true, - "sourceMap": true, - "skipLibCheck": true, - "strict": false, - "incremental": false - }, - "include": [ - "src/**/*" - ] -} \ No newline at end of file diff --git a/packages/stats/package.json b/packages/stats/package.json deleted file mode 100755 index b20f0f42d4..0000000000 --- a/packages/stats/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "@oasis-engine/stats", - "version": "0.7.0-beta.3", - "license": "MIT", - "scripts": { - "b:types": "tsc" - }, - "types": "types/index.d.ts", - "main": "dist/main.js", - "module": "dist/module.js", - "browser": "dist/browser.min.js", - "files": [ - "dist/**/*", - "types/**/*" - ], - "dependencies": { - "oasis-engine": "0.7.0-beta.3" - } -} diff --git a/packages/stats/src/Core.ts b/packages/stats/src/Core.ts deleted file mode 100644 index ca76b5c90f..0000000000 --- a/packages/stats/src/Core.ts +++ /dev/null @@ -1,80 +0,0 @@ -import DrawCallHook from "./hooks/DrawCallHook"; -import ShaderHook from "./hooks/ShaderHook"; -import TextureHook from "./hooks/TextureHook"; - -declare global { - interface Performance { - memory: any; - } -} - -/** - * @class Core - */ -export default class Core { - private gl: WebGLRenderingContext | WebGL2RenderingContext; - private drawCallHook: DrawCallHook; - private textureHook: TextureHook; - private shaderHook: ShaderHook; - private samplingFrames: number = 60; - private samplingIndex: number = 0; - private updateCounter: number = 0; - private updateTime: number = 0; - - constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) { - this.gl = gl; - this.hook(gl); - } - - private hook(gl: WebGLRenderingContext | WebGL2RenderingContext) { - this.drawCallHook = new DrawCallHook(gl); - this.textureHook = new TextureHook(gl); - this.shaderHook = new ShaderHook(gl); - } - - public reset() { - this.drawCallHook && this.drawCallHook.reset(); - } - - public release() { - this.drawCallHook && this.drawCallHook.release(); - this.textureHook && this.textureHook.release(); - this.shaderHook && this.shaderHook.release(); - } - - public update() { - this.updateCounter++; - let now = performance.now(); - if (now - this.updateTime < 1000) { - return; - } - - if (this.samplingIndex !== this.samplingFrames) { - this.reset(); - this.samplingIndex++; - return; - } - - this.samplingIndex = 0; - - let data = { - fps: Math.round((this.updateCounter * 1000) / (now - this.updateTime)), - memory: performance.memory && (performance.memory.usedJSHeapSize / 1048576) >> 0, - drawCall: this.drawCallHook.drawCall, - triangles: this.drawCallHook.triangles, - lines: this.drawCallHook.lines, - points: this.drawCallHook.points, - textures: this.textureHook.textures, - shaders: this.shaderHook.shaders, - webglContext: - window.hasOwnProperty("WebGL2RenderingContext") && this.gl instanceof WebGL2RenderingContext ? "2.0" : "1.0" - }; - - this.reset(); - - this.updateCounter = 0; - this.updateTime = now; - - return data; - } -} diff --git a/packages/stats/src/Monitor.ts b/packages/stats/src/Monitor.ts deleted file mode 100644 index 81b92535de..0000000000 --- a/packages/stats/src/Monitor.ts +++ /dev/null @@ -1,134 +0,0 @@ -import Core from "./Core"; - -let tpl = ` -
-
FPS
-
0
-
Memory (MB)
-
0
-
DrawCall
-
0
-
Triangles
-
0
-
Textures
-
0
-
Shaders
-
0
-
WebGL
-
-
-`; -let css = ` - .gl-perf { - pointer-events: none; - user-select: none; - position: fixed; - top: 0; - left: 0; - padding: ${10 / 7.5}vh ${10 / 7.5}vh 0 ${10 / 7.5}vh; - background: rgba(0, 0, 0, 0.3); - color: #fff; - font: ${10 / 7.5}vh arial; - } - - .gl-perf dl, - .gl-perf dt, - .gl-perf dd { - padding: 0; - margin: 0; - } - - .gl-perf dt { - color: #fff; - text-shadow: #000 0 0 1px; - } - - .gl-perf dt .unit{ - font-size: ${10 / 7.5}vh; - } - - .gl-perf dd { - font-size: ${20 / 7.5}vh; - padding: ${10 / 7.5}vh 0 ${10 / 7.5}vh; - } -`; - -export default class Monitor { - private core: Core; - private doms: HTMLElement[]; - private items: string[]; - private container: HTMLElement; - - constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) { - this.core = new Core(gl); - this.items = []; - this.items = ["fps", "memory", "drawCall", "triangles", "textures", "shaders", "webglContext"]; - this.createContainer(); - this.update = this.update.bind(this); - } - - private createContainer() { - let container = document.createElement("div"); - container.classList.add("gl-perf"); - container.innerHTML = tpl; - - container.appendChild(this.createStyle()); - - document.body.appendChild(container); - - this.doms = Array.prototype.slice.apply(container.querySelectorAll("dd")); - this.container = container; - } - - private createStyle() { - let style: HTMLStyleElement = document.createElement("style"); - - style.type = "text/css"; - - style.appendChild(document.createTextNode(css)); - - return style; - } - - /** - * Update per frame - */ - public update() { - let data = this.core.update(); - - if (data) { - for (let i = 0, l = this.items.length; i < l; i++) { - let dom = this.doms[i]; - let item = this.items[i]; - let value = data[item] || 0; - - // see: http://wilsonpage.co.uk/preventing-layout-thrashing/ - requestAnimationFrame(() => { - dom.innerText = value; - }); - } - } - } - - /** - * reset all hooks - */ - public reset() { - this.core.reset(); - } - - /** - * release all hooks - */ - public release() { - this.core.release(); - } - - /** - * destroy the instance - */ - public destroy() { - this.release(); - document.body.removeChild(this.container); - } -} diff --git a/packages/stats/src/Stats.ts b/packages/stats/src/Stats.ts deleted file mode 100644 index 9966fc550d..0000000000 --- a/packages/stats/src/Stats.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { EngineFeature, Engine, Scene } from "oasis-engine"; -import Monitor from "./Monitor"; - -/** - * Engine Feature: Display engine status data such as FPS. - */ -export class Stats extends EngineFeature { - private monitor: Monitor; - - /** - * Constructor of Stats. - */ - constructor() { - super(); - } - - /** - * Tick pre-callback. - */ - preTick(engine: Engine, currentScene: Scene): void { - if (!this.monitor) { - const gl = currentScene.engine._hardwareRenderer.gl; - if (gl) { - this.monitor = new Monitor(gl); - } - } - } - - /** - * Tick post-callback. - */ - postTick(engine: Engine, currentScene: Scene): void { - if (this.monitor) { - this.monitor.update(); - } - } -} diff --git a/packages/stats/src/hooks/DrawCallHook.ts b/packages/stats/src/hooks/DrawCallHook.ts deleted file mode 100644 index 031ca4a9e0..0000000000 --- a/packages/stats/src/hooks/DrawCallHook.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { log, errorLog } from "../log"; - -/** - * @class DrawCallHook - */ -export default class DrawCallHook { - public drawCall: number = 0; - public triangles: number = 0; - public lines: number = 0; - public points: number = 0; - private hooked: boolean; - private realDrawElements: any; - private realDrawArrays: any; - private gl: WebGLRenderingContext | WebGL2RenderingContext; - - constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) { - this.realDrawElements = gl.drawElements; - this.realDrawArrays = gl.drawArrays; - - gl.drawElements = this.hookedDrawElements.bind(this); - gl.drawArrays = this.hookedDrawArrays.bind(this); - - this.hooked = true; - this.gl = gl; - - log(`DrawCall is hooked.`); - } - - private hookedDrawElements(mode: number, count: number, type: number, offset: number) { - this.realDrawElements.call(this.gl, mode, count, type, offset); - this.update(count, mode); - } - - private hookedDrawArrays(mode: number, first: number, count: number) { - this.realDrawArrays.call(this.gl, mode, first, count); - this.update(count, mode); - } - - private update(count: number, mode: number) { - const { gl } = this; - - this.drawCall++; - - switch (mode) { - case gl.TRIANGLES: - this.triangles += count / 3; - break; - - case gl.TRIANGLE_STRIP: - case gl.TRIANGLE_FAN: - this.triangles += count - 2; - break; - - case gl.LINES: - this.lines += count / 2; - break; - - case gl.LINE_STRIP: - this.lines += count - 1; - break; - - case gl.LINE_LOOP: - this.lines += count; - break; - - case gl.POINTS: - this.points += count; - break; - - default: - errorLog(`Unknown draw mode: ${mode}`); - break; - } - } - - public reset(): void { - this.drawCall = 0; - this.triangles = 0; - this.lines = 0; - this.points = 0; - } - - public release(): void { - if (this.hooked) { - this.gl.drawElements = this.realDrawElements; - this.gl.drawArrays = this.realDrawArrays; - } - - this.hooked = false; - } -} diff --git a/packages/stats/src/hooks/ShaderHook.ts b/packages/stats/src/hooks/ShaderHook.ts deleted file mode 100644 index 844c64f938..0000000000 --- a/packages/stats/src/hooks/ShaderHook.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { log, errorLog } from "../log"; - -/** - * @class ShaderHook - */ -export default class ShaderHook { - public shaders: number = 0; - private realAttachShader: any; - private realDetachShader: any; - private hooked: boolean; - private gl: WebGLRenderingContext | WebGL2RenderingContext; - - constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) { - this.realAttachShader = gl.attachShader; - this.realDetachShader = gl.detachShader; - - gl.attachShader = this.hookedAttachShader.bind(this); - gl.detachShader = this.hookedDetachShader.bind(this); - - this.hooked = true; - this.gl = gl; - - log(`Shader is hooked.`); - } - - private hookedAttachShader(program: any, shader: any) { - this.realAttachShader.call(this.gl, program, shader); - - this.shaders++; - - log(`AttachShader:`, shader, `shaders: ${this.shaders}`); - } - - private hookedDetachShader(program: any, shader: any) { - this.realDetachShader.call(this.gl, program, shader); - - this.shaders--; - - log(`DetachShader. shaders: ${this.shaders}`); - } - - public reset() { - this.shaders = 0; - } - - public release() { - if (this.hooked) { - this.gl.attachShader = this.realAttachShader; - this.gl.detachShader = this.realDetachShader; - } - - this.hooked = false; - } -} diff --git a/packages/stats/src/hooks/TextureHook.ts b/packages/stats/src/hooks/TextureHook.ts deleted file mode 100644 index 71318b783e..0000000000 --- a/packages/stats/src/hooks/TextureHook.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { log, errorLog } from "../log"; - -/** - * @class TextureHook - */ -export default class TextureHook { - public textures: number = 0; - private realCreateTexture: any; - private realDeleteTexture: any; - private hooked: boolean; - private gl: WebGLRenderingContext | WebGL2RenderingContext; - - constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) { - this.realCreateTexture = gl.createTexture; - this.realDeleteTexture = gl.deleteTexture; - - gl.createTexture = this.hookedCreateTexture.bind(this); - gl.deleteTexture = this.hookedDeleteTexture.bind(this); - - this.hooked = true; - this.gl = gl; - - log(`Texture is hooked.`); - } - - private hookedCreateTexture() { - let texture = this.realCreateTexture.call(this.gl); - - this.textures++; - - log(`CreateTexture:`, texture, `textures: ${this.textures}`); - - return texture; - } - - private hookedDeleteTexture(texture: any) { - this.realDeleteTexture.call(this.gl, texture); - - this.textures--; - - log(`DeleteTexture. textures: ${this.textures}`); - } - - public reset() { - this.textures = 0; - } - - public release() { - if (this.hooked) { - this.gl.createTexture = this.realCreateTexture; - this.gl.deleteTexture = this.realDeleteTexture; - } - - this.hooked = false; - } -} diff --git a/packages/stats/src/index.ts b/packages/stats/src/index.ts deleted file mode 100644 index 5fddda8d68..0000000000 --- a/packages/stats/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Engine } from "oasis-engine"; -import { Stats } from "./Stats"; - -Engine.registerFeature(Stats); - -export { Stats }; diff --git a/packages/stats/src/log.ts b/packages/stats/src/log.ts deleted file mode 100644 index e5e1dee9dc..0000000000 --- a/packages/stats/src/log.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Logger } from "oasis-engine"; - -export function log(...args: any) { - Logger.info("🚀 [o3-engine-stats]", ...args); -} - -export function errorLog(...args: any) { - Logger.error("🚀 [o3-engine-stats]", ...args); -} diff --git a/packages/stats/tsconfig.json b/packages/stats/tsconfig.json deleted file mode 100644 index 1dc8cad306..0000000000 --- a/packages/stats/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "esnext", - "declaration": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "declarationDir": "types", - "emitDeclarationOnly": true, - "sourceMap": true, - "skipLibCheck": true, - "incremental": false - }, - "include": [ - "src/**/*" - ] -} \ No newline at end of file From 8ef6926ba761e07fff0e6fe460a1560417fe3861 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Wed, 11 May 2022 14:14:28 +0800 Subject: [PATCH 03/33] v0.7.0-beta.4 (#795) --- lerna.json | 2 +- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/lerna.json b/lerna.json index 24383ebabd..2d86f82025 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index db0f5afb57..502913146e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.7.0-beta.3" + "@oasis-engine/math": "0.7.0-beta.4" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.3" + "@oasis-engine/design": "0.7.0-beta.4" } } diff --git a/packages/design/package.json b/packages/design/package.json index 0c6cb4844e..68919b6d00 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -13,6 +13,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.7.0-beta.3" + "@oasis-engine/math": "0.7.0-beta.4" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index cbc4b13a59..4932303682 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "scripts": { "b:types": "tsc" @@ -13,6 +13,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.3" + "@oasis-engine/core": "0.7.0-beta.4" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index c5b30244b3..2e44ff4b7c 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "types": "types/index.d.ts", "scripts": { @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.3", - "@oasis-engine/draco": "0.7.0-beta.3", - "@oasis-engine/math": "0.7.0-beta.3", - "@oasis-engine/rhi-webgl": "0.7.0-beta.3" + "@oasis-engine/core": "0.7.0-beta.4", + "@oasis-engine/draco": "0.7.0-beta.4", + "@oasis-engine/math": "0.7.0-beta.4", + "@oasis-engine/rhi-webgl": "0.7.0-beta.4" } } diff --git a/packages/math/package.json b/packages/math/package.json index 49d792c357..463d9d2ebb 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index af328767f5..e313ca9ba2 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "scripts": { "b:types": "tsc" @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.3", - "@oasis-engine/loader": "0.7.0-beta.3", - "@oasis-engine/math": "0.7.0-beta.3", - "@oasis-engine/rhi-webgl": "0.7.0-beta.3" + "@oasis-engine/core": "0.7.0-beta.4", + "@oasis-engine/loader": "0.7.0-beta.4", + "@oasis-engine/math": "0.7.0-beta.4", + "@oasis-engine/rhi-webgl": "0.7.0-beta.4" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index d10bd9ecd4..afad790f11 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.3", - "oasis-engine": "0.7.0-beta.3" + "@oasis-engine/design": "0.7.0-beta.4", + "oasis-engine": "0.7.0-beta.4" }, "publishConfig": { "access": "public" diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 7c73fb15b9..afb0edbfe3 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.3", - "oasis-engine": "0.7.0-beta.3" + "@oasis-engine/design": "0.7.0-beta.4", + "oasis-engine": "0.7.0-beta.4" }, "publishConfig": { "access": "public" diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 12df90025f..6ec31dfa66 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,10 +14,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.3", - "@oasis-engine/math": "0.7.0-beta.3" + "@oasis-engine/core": "0.7.0-beta.4", + "@oasis-engine/math": "0.7.0-beta.4" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.3" + "@oasis-engine/design": "0.7.0-beta.4" } } From 42e5a739bc7fd8a6f8b3f44ad0f9aa4d6f5ecbfc Mon Sep 17 00:00:00 2001 From: AZhan Date: Mon, 16 May 2022 12:09:43 +0800 Subject: [PATCH 04/33] Fix:local translate (#706) * fix(transform):local translate --- packages/core/src/Transform.ts | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 0d5b5392e0..1432b6974c 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -425,19 +425,19 @@ export class Transform extends Component { return up.normalize(); } - /** - * Translate along the passed Vector3. + /** + * Translate in the direction and distance of the translation. * @param translation - Direction and distance of translation - * @param relativeToLocal - Relative to local space + * @param relativeToLocal - Is relative to the local coordinate system */ translate(translation: Vector3, relativeToLocal?: boolean): void; /** - * Translate along the passed X, Y, Z value. - * @param x - Translate direction and distance along x axis - * @param y - Translate direction and distance along y axis - * @param z - Translate direction and distance along z axis - * @param relativeToLocal - Relative to local space + * Translate some distance by x along the x axis, y along the y axis, and z along the z axis. + * @param x - Distance along the x axis + * @param y - Distance along the y axis + * @param z - Distance along the z axis + * @param relativeToLocal - Is relative to the local coordinate system */ translate(x: number, y: number, z: number, relativeToLocal?: boolean): void; @@ -459,7 +459,7 @@ export class Transform extends Component { /** * Rotate around the passed Vector3. * @param rotation - Euler angle in degrees - * @param relativeToLocal - Relative to local space + * @param relativeToLocal - Is relative to the local coordinate system */ rotate(rotation: Vector3, relativeToLocal?: boolean): void; @@ -468,7 +468,7 @@ export class Transform extends Component { * @param x - Rotation along x axis, in degrees * @param y - Rotation along y axis, in degrees * @param z - Rotation along z axis, in degrees - * @param relativeToLocal - Relative to local space + * @param relativeToLocal - Is relative to the local coordinate system */ rotate(x: number, y: number, z: number, relativeToLocal?: boolean): void; @@ -520,7 +520,7 @@ export class Transform extends Component { axisLen = xAxis.length(); if (axisLen <= MathUtil.zeroTolerance) { // @todo: - // 1.worldup is(0,0,0) + // 1.worldUp is(0,0,0) // 2.worldUp is parallel to zAxis return; } @@ -710,7 +710,7 @@ export class Transform extends Component { this._updateFlagManager.dispatch(); } - private _rotateByQuat(rotateQuat: Quaternion, relativeToLocal: boolean) { + private _rotateByQuat(rotateQuat: Quaternion, relativeToLocal: boolean): void { if (relativeToLocal) { Quaternion.multiply(this.rotationQuaternion, rotateQuat, this._rotationQuaternion); } else { @@ -718,15 +718,17 @@ export class Transform extends Component { } } - private _translate(translation: Vector3, relativeToLocal: boolean = true): void { + private _translate(translation: Vector3, relativeToLocal: boolean): void { if (relativeToLocal) { - this._position.add(translation); + const { _tempVec30 } = Transform; + Vector3.transformByQuat(translation, this.worldRotationQuaternion, _tempVec30); + this._worldPosition.add(_tempVec30); } else { this._worldPosition.add(translation); } } - private _rotateXYZ(x: number, y: number, z: number, relativeToLocal: boolean = true): void { + private _rotateXYZ(x: number, y: number, z: number, relativeToLocal: boolean): void { const radFactor = MathUtil.degreeToRadFactor; const rotQuat = Transform._tempQuat0; Quaternion.rotationEuler(x * radFactor, y * radFactor, z * radFactor, rotQuat); From 0655f282bfc23100a29141a1a5ca699277d000d9 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Mon, 16 May 2022 14:03:41 +0800 Subject: [PATCH 05/33] Add component denpendent decorator (#796) * feat: add `dependentComponents` decorator --- packages/core/src/Camera.ts | 9 +++--- packages/core/src/ComponentsDependencies.ts | 33 +++++++++++--------- packages/core/src/Renderer.ts | 11 +++++-- packages/core/src/Transform.ts | 3 ++ packages/core/src/fog/Fog.ts | 3 ++ packages/core/src/index.ts | 2 +- packages/core/src/mesh/MeshRenderer.ts | 1 - packages/core/src/physics/Collider.ts | 22 ++++++++----- packages/core/src/physics/DynamicCollider.ts | 5 ++- packages/core/src/physics/StaticCollider.ts | 3 ++ 10 files changed, 58 insertions(+), 34 deletions(-) diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 6f638ce8c0..baf066289b 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -3,7 +3,7 @@ import { Logger } from "./base"; import { BoolUpdateFlag } from "./BoolUpdateFlag"; import { deepClone, ignoreClone } from "./clone/CloneManager"; import { Component } from "./Component"; -import { dependencies } from "./ComponentsDependencies"; +import { dependentComponents } from "./ComponentsDependencies"; import { Entity } from "./Entity"; import { CameraClearFlags } from "./enums/CameraClearFlags"; import { Layer } from "./Layer"; @@ -16,7 +16,6 @@ import { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; import { TextureCubeFace } from "./texture/enums/TextureCubeFace"; import { RenderTarget } from "./texture/RenderTarget"; import { Transform } from "./Transform"; -import { UpdateFlag } from "./UpdateFlag"; class MathTemp { static tempVec4 = new Vector4(); @@ -26,8 +25,9 @@ class MathTemp { /** * Camera component, as the entrance to the three-dimensional world. + * @decorator `@dependentComponents(Transform)` */ -@dependencies(Transform) +@dependentComponents(Transform) export class Camera extends Component { private static _viewMatrixProperty = Shader.getPropertyByName("u_viewMat"); private static _projectionMatrixProperty = Shader.getPropertyByName("u_projMat"); @@ -314,8 +314,7 @@ export class Camera extends Component { } /** - * Create the Camera component. - * @param entity - Entity + * @internal */ constructor(entity: Entity) { super(entity); diff --git a/packages/core/src/ComponentsDependencies.ts b/packages/core/src/ComponentsDependencies.ts index dd24d813f4..3cb1054eff 100644 --- a/packages/core/src/ComponentsDependencies.ts +++ b/packages/core/src/ComponentsDependencies.ts @@ -14,11 +14,9 @@ export class ComponentsDependencies { private static _invDependenciesMap = new Map(); /** - * Register component dependencies. - * @param currentComponent - The component you want to be register. - * @param dependentComponent - The component's dependencies. + * @internal */ - static register(currentComponent: ComponentConstructor, dependentComponent: ComponentConstructor) { + static _register(currentComponent: ComponentConstructor, dependentComponent: ComponentConstructor): void { this._addDependency(currentComponent, dependentComponent, this._dependenciesMap); this._addDependency(dependentComponent, currentComponent, this._invDependenciesMap); } @@ -26,13 +24,14 @@ export class ComponentsDependencies { /** * @internal */ - static _addCheck(entity: Entity, type: ComponentConstructor) { + static _addCheck(entity: Entity, type: ComponentConstructor): void { // Check if there are dependent components. - const dependencies = ComponentsDependencies._dependenciesMap.get(type); - if (dependencies) { - for (let i = 0, len = dependencies.length; i < len; i++) { - if (!entity.getComponent(dependencies[i])) { - throw `you should add ${dependencies[i]} before adding ${type}`; + const dependentComponents = ComponentsDependencies._dependenciesMap.get(type); + if (dependentComponents) { + for (let i = 0, n = dependentComponents.length; i < n; i++) { + const dependentComponent = dependentComponents[i]; + if (!entity.getComponent(dependentComponent)) { + entity.addComponent(dependentComponent); } } } @@ -41,7 +40,7 @@ export class ComponentsDependencies { /** * @internal */ - static _removeCheck(entity: Entity, type: ComponentConstructor) { + static _removeCheck(entity: Entity, type: ComponentConstructor): void { const invDependencies = ComponentsDependencies._invDependenciesMap.get(type); if (invDependencies) { for (let i = 0, len = invDependencies.length; i < len; i++) { @@ -55,8 +54,8 @@ export class ComponentsDependencies { private static _addDependency( currentComponent: ComponentConstructor, dependentComponent: ComponentConstructor, - map: Map - ) { + map: Map + ): void { let components = map.get(currentComponent); if (!components) { components = []; @@ -70,8 +69,12 @@ export class ComponentsDependencies { private constructor() {} } -export function dependencies(...componentClass: ComponentConstructor[]) { +/** + * Dependent components, automatically added if they do not exist. + * @param components - Dependent components + */ +export function dependentComponents(...components: ComponentConstructor[]) { return function (target: T): void { - componentClass.forEach((component) => ComponentsDependencies.register(target, component)); + components.forEach((component) => ComponentsDependencies._register(target, component)); }; } diff --git a/packages/core/src/Renderer.ts b/packages/core/src/Renderer.ts index 2f52b7109d..1d55dd41ad 100644 --- a/packages/core/src/Renderer.ts +++ b/packages/core/src/Renderer.ts @@ -3,6 +3,7 @@ import { BoolUpdateFlag } from "./BoolUpdateFlag"; import { Camera } from "./Camera"; import { deepClone, ignoreClone, shallowClone } from "./clone/CloneManager"; import { Component } from "./Component"; +import { dependentComponents } from "./ComponentsDependencies"; import { Entity } from "./Entity"; import { Material } from "./material/Material"; import { RenderContext } from "./RenderPipeline/RenderContext"; @@ -10,12 +11,14 @@ import { Shader } from "./shader"; import { ShaderDataGroup } from "./shader/enums/ShaderDataGroup"; import { ShaderData } from "./shader/ShaderData"; import { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; -import { UpdateFlag } from "./UpdateFlag"; +import { Transform } from "./Transform"; /** * Renderable component. + * @decorator `@dependentComponents(Transform)` */ -export abstract class Renderer extends Component { +@dependentComponents(Transform) +export class Renderer extends Component { private static _localMatrixProperty = Shader.getPropertyByName("u_localMat"); private static _worldMatrixProperty = Shader.getPropertyByName("u_modelMat"); private static _mvMatrixProperty = Shader.getPropertyByName("u_MVMat"); @@ -286,7 +289,9 @@ export abstract class Renderer extends Component { /** * @internal */ - abstract _render(camera: Camera): void; + _render(camera: Camera): void { + throw "not implement"; + } /** * @internal diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 1432b6974c..23cc1ee580 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -292,6 +292,9 @@ export class Transform extends Component { this._setDirtyFlagFalse(TransformFlag.WorldMatrix); } + /** + * @internal + */ constructor(entity: Entity) { super(entity); diff --git a/packages/core/src/fog/Fog.ts b/packages/core/src/fog/Fog.ts index 0d6187a9c9..549567c039 100644 --- a/packages/core/src/fog/Fog.ts +++ b/packages/core/src/fog/Fog.ts @@ -23,6 +23,9 @@ export class Fog extends Component { private _color: Color = new Color(1, 0, 0, 1); + /** + * @internal + */ constructor(entity: Entity) { super(entity); this.color = this._color; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c8e6031e54..b0b39a674f 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -11,7 +11,7 @@ export { Entity } from "./Entity"; export { Component } from "./Component"; export { Script } from "./Script"; export { Renderer } from "./Renderer"; -export { dependencies } from "./ComponentsDependencies"; +export { dependentComponents } from "./ComponentsDependencies"; export { Camera } from "./Camera"; export { Transform } from "./Transform"; export { UpdateFlag } from "./UpdateFlag"; diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index 5814da842b..fce3566518 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -8,7 +8,6 @@ import { Entity } from "../Entity"; import { Mesh } from "../graphic/Mesh"; import { Renderer } from "../Renderer"; import { Shader } from "../shader/Shader"; -import { UpdateFlag } from "../UpdateFlag"; /** * MeshRenderer Component. diff --git a/packages/core/src/physics/Collider.ts b/packages/core/src/physics/Collider.ts index 6733c66010..9a2be76a3a 100644 --- a/packages/core/src/physics/Collider.ts +++ b/packages/core/src/physics/Collider.ts @@ -1,15 +1,18 @@ -import { Component } from "../Component"; -import { ignoreClone } from "../clone/CloneManager"; import { ICollider } from "@oasis-engine/design"; -import { ColliderShape } from "./shape/ColliderShape"; -import { UpdateFlag } from "../UpdateFlag"; -import { Entity } from "../Entity"; import { BoolUpdateFlag } from "../BoolUpdateFlag"; +import { ignoreClone } from "../clone/CloneManager"; +import { Component } from "../Component"; +import { dependentComponents } from "../ComponentsDependencies"; +import { Entity } from "../Entity"; +import { Transform } from "../Transform"; +import { ColliderShape } from "./shape/ColliderShape"; /** - * Abstract class for collider shapes. + * Base class for all colliders. + * @decorator `@dependentComponents(Transform)` */ -export abstract class Collider extends Component { +@dependentComponents(Transform) +export class Collider extends Component { /** @internal */ @ignoreClone _index: number = -1; @@ -27,7 +30,10 @@ export abstract class Collider extends Component { return this._shapes; } - protected constructor(entity: Entity) { + /** + * @internal + */ + constructor(entity: Entity) { super(entity); this._updateFlag = this.entity.transform.registerWorldChangeFlag(); } diff --git a/packages/core/src/physics/DynamicCollider.ts b/packages/core/src/physics/DynamicCollider.ts index e14949be6d..9b9a9dab0d 100644 --- a/packages/core/src/physics/DynamicCollider.ts +++ b/packages/core/src/physics/DynamicCollider.ts @@ -1,8 +1,8 @@ import { IDynamicCollider } from "@oasis-engine/design"; +import { Quaternion, Vector3 } from "@oasis-engine/math"; import { Entity } from "../Entity"; import { Collider } from "./Collider"; import { PhysicsManager } from "./PhysicsManager"; -import { Vector3, Quaternion } from "@oasis-engine/math"; /** * A dynamic collider can act with self-defined movement or physical force. @@ -199,6 +199,9 @@ export class DynamicCollider extends Collider { (this._nativeCollider).setCollisionDetectionMode(value); } + /** + * @internal + */ constructor(entity: Entity) { super(entity); const { transform } = this.entity; diff --git a/packages/core/src/physics/StaticCollider.ts b/packages/core/src/physics/StaticCollider.ts index 99d0e96c38..a6364a34d9 100644 --- a/packages/core/src/physics/StaticCollider.ts +++ b/packages/core/src/physics/StaticCollider.ts @@ -7,6 +7,9 @@ import { PhysicsManager } from "./PhysicsManager"; * @remarks Mostly used for object which always stays at the same place and never moves around. */ export class StaticCollider extends Collider { + /** + * @internal + */ constructor(entity: Entity) { super(entity); const { transform } = this.entity; From e66263d78ef5e5f1a281fe6a42a8743a3c2ea337 Mon Sep 17 00:00:00 2001 From: Hu Song Date: Mon, 16 May 2022 14:24:20 +0800 Subject: [PATCH 06/33] ci: remove ci on node 12 (#801) --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 2ef22da218..f7db80c4c1 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: - node-version: [12.x, 15.x] + node-version: [15.x] steps: - uses: actions/checkout@v2 From 4de42c92173b85b45081429bc3bca54e6f555af5 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Mon, 16 May 2022 15:04:25 +0800 Subject: [PATCH 07/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9732938384..41b4c24ece 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Make sure to read the [Contributing Guide](.github/HOW_TO_CONTRIBUTE.md) / [贡 ## Build -If you don't already have Node.js and NPM, go install them. Then, in the folder where you have cloned the repository, install the build dependencies using npm: +If you don't already have [Node.js v15.0.0+](https://nodejs.org/en/) and NPM, go install them. Then, in the folder where you have cloned the repository, install the build dependencies using npm: ```sh npm run bootstrap From b2f8b5fc2aaf3c2b7634503800d85a1ed21787ce Mon Sep 17 00:00:00 2001 From: Hu Song Date: Mon, 16 May 2022 19:25:20 +0800 Subject: [PATCH 08/33] Fix Test Version Error (#802) * ci: remove ci on node 12 * test: fix version --- tests/package.json | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/package.json b/tests/package.json index 553b13ee83..4f12584065 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,7 +1,6 @@ { "name": "@oasis-engine/tests", - "private": true, - "version": "0.7.0-beta.3", + "version": "0.7.0-beta.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,11 +14,11 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.7.0-beta.3", - "@oasis-engine/core": "0.7.0-beta.3", - "@oasis-engine/rhi-webgl": "0.7.0-beta.3" + "@oasis-engine/math": "0.7.0-beta.4", + "@oasis-engine/core": "0.7.0-beta.4", + "@oasis-engine/rhi-webgl": "0.7.0-beta.4" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.3" + "@oasis-engine/design": "0.7.0-beta.4" } } From 6f0e38cfca7a4e86a33508014676e91c39a39457 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 24 May 2022 19:18:36 +0800 Subject: [PATCH 09/33] feat: add `priority` for renderer to order(#803) * feat(renderer): add `priority` for renderer to order --- .../src/RenderPipeline/BasicRenderPipeline.ts | 18 ++++++++++-------- .../core/src/RenderPipeline/RenderQueue.ts | 10 ++++------ packages/core/src/Renderer.ts | 17 +++++++++++++---- .../core/src/material/enums/RenderQueueType.ts | 6 +++--- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 5a687087b7..16b4c98b80 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -202,14 +202,16 @@ export class BasicRenderPipeline { * @param element - Render element */ pushPrimitive(element: RenderElement | SpriteElement) { - const renderQueueType = element.material.renderQueueType; - - if (renderQueueType > (RenderQueueType.Transparent + RenderQueueType.AlphaTest) >> 1) { - this._transparentQueue.pushPrimitive(element); - } else if (renderQueueType > (RenderQueueType.AlphaTest + RenderQueueType.Opaque) >> 1) { - this._alphaTestQueue.pushPrimitive(element); - } else { - this._opaqueQueue.pushPrimitive(element); + switch (element.material.renderQueueType) { + case RenderQueueType.Transparent: + this._transparentQueue.pushPrimitive(element); + break; + case RenderQueueType.AlphaTest: + this._alphaTestQueue.pushPrimitive(element); + break; + case RenderQueueType.Opaque: + this._opaqueQueue.pushPrimitive(element); + break; } } diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index beb204a213..757c9ad0fb 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -19,9 +19,8 @@ export class RenderQueue { */ static _compareFromNearToFar(a: Item, b: Item): number { return ( - a.material.renderQueueType - b.material.renderQueueType || - a.component._distanceForSort - b.component._distanceForSort || - b.component._renderSortId - a.component._renderSortId + a.component.priority - b.component.priority || + a.component._distanceForSort - b.component._distanceForSort ); } @@ -30,9 +29,8 @@ export class RenderQueue { */ static _compareFromFarToNear(a: Item, b: Item): number { return ( - a.material.renderQueueType - b.material.renderQueueType || - b.component._distanceForSort - a.component._distanceForSort || - b.component._renderSortId - a.component._renderSortId + a.component.priority - b.component.priority || + b.component._distanceForSort - a.component._distanceForSort ); } diff --git a/packages/core/src/Renderer.ts b/packages/core/src/Renderer.ts index 1d55dd41ad..cdbdb4b624 100644 --- a/packages/core/src/Renderer.ts +++ b/packages/core/src/Renderer.ts @@ -46,10 +46,6 @@ export class Renderer extends Component { @ignoreClone _globalShaderMacro: ShaderMacroCollection = new ShaderMacroCollection(); - /** @internal temp solution. */ - @ignoreClone - _renderSortId: number = 0; - @ignoreClone protected _overrideUpdate: boolean = false; @shallowClone @@ -69,6 +65,8 @@ export class Renderer extends Component { private _normalMatrix: Matrix = new Matrix(); @ignoreClone private _materialsInstanced: boolean[] = []; + @ignoreClone + private _priority: number = 0; /** * Material count. @@ -97,6 +95,17 @@ export class Renderer extends Component { return this._bounds; } + /** + * The render priority of the renderer, lower values are rendered first and higher values are rendered last. + */ + get priority(): number { + return this._priority; + } + + set priority(value: number) { + this._priority = value; + } + /** * @internal */ diff --git a/packages/core/src/material/enums/RenderQueueType.ts b/packages/core/src/material/enums/RenderQueueType.ts index 18563f5ae3..e913e7426e 100644 --- a/packages/core/src/material/enums/RenderQueueType.ts +++ b/packages/core/src/material/enums/RenderQueueType.ts @@ -3,9 +3,9 @@ */ export enum RenderQueueType { /** Opaque queue. */ - Opaque = 1000, + Opaque, /** Opaque queue, alpha cutoff. */ - AlphaTest = 2000, + AlphaTest, /** Transparent queue, rendering from back to front to ensure correct rendering of transparent objects. */ - Transparent = 3000 + Transparent } From 4a97c91c1f443b8dd625d681453094566a17e8d3 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Thu, 2 Jun 2022 11:38:57 +0800 Subject: [PATCH 10/33] Fix SkyBox render mirror problem (#816) * refactor: fix skybox mirror problem --- packages/core/src/shaderlib/extra/skybox.vs.glsl | 4 ++-- packages/core/src/shaderlib/pbr/ibl_frag_define.glsl | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/shaderlib/extra/skybox.vs.glsl b/packages/core/src/shaderlib/extra/skybox.vs.glsl index e397b0b0b4..a7ecc9a397 100644 --- a/packages/core/src/shaderlib/extra/skybox.vs.glsl +++ b/packages/core/src/shaderlib/extra/skybox.vs.glsl @@ -6,8 +6,8 @@ varying vec3 v_cubeUV; void main() { - v_cubeUV = POSITION.xyz; + v_cubeUV = vec3( -POSITION.x, POSITION.yz );// TextureCube is left-hand,so x need inverse gl_Position = u_mvpNoscale * vec4( POSITION, 1.0 ); gl_Position.z = gl_Position.w; -} +} \ No newline at end of file diff --git a/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl b/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl index 2b523ceefa..9f46499bee 100644 --- a/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl +++ b/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl @@ -51,6 +51,7 @@ vec3 getLightProbeRadiance(vec3 viewDir, vec3 normal, float roughness, int maxMI #else vec3 reflectVec = reflect( -viewDir, normal ); + reflectVec.x = -reflectVec.x; // TextureCube is left-hand,so x need inverse float specularMIPLevel = getSpecularMIPLevel(roughness, maxMIPLevel ); From 3bcf55af92f95c926cfc705492f4d84f1996f4ba Mon Sep 17 00:00:00 2001 From: AZhan Date: Thu, 2 Jun 2022 15:33:15 +0800 Subject: [PATCH 11/33] fix: change `region` and `pivot` origin to left-bottom (#809) * fix: change `region` and `pivot` origin to left-bottom --- packages/core/src/2d/sprite/Sprite.ts | 153 +++++++------------------- 1 file changed, 42 insertions(+), 111 deletions(-) diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index ed24a791e1..5d9c637f02 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -112,10 +112,8 @@ export class Sprite extends RefObject { set pivot(value: Vector2) { const pivot = this._pivot; - const x = MathUtil.clamp(value.x, 0, 1); - const y = MathUtil.clamp(value.y, 0, 1); - if (pivot === value || pivot.x !== x || pivot.y !== y) { - pivot.setValue(x, y); + if (pivot === value || pivot.x !== value.x || pivot.y !== value.y) { + pivot.setValue(value.x, value.y); this._setDirtyFlagTrue(DirtyFlag.positions); } } @@ -220,59 +218,35 @@ export class Sprite extends RefObject { private _updatePositionsAndBounds(): void { const { _texture: texture, _bounds: bounds } = this; if (texture) { - const { _atlasRegion: atlasRegion, _pivot: pivot, _atlasRegionOffset: atlasRegionOffset } = this; + const { _atlasRegion: atlasRegion, _pivot: pivot } = this; + const { x: blankLeft, y: blankTop, z: blankRight, w: blankBottom } = this._atlasRegionOffset; const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; - const pPUReciprocal = 1.0 / this._pixelsPerUnit; + const regionRight = 1 - regionX - regionW; + const regionBottom = 1 - regionY - regionH; + // Real rendering size. + const realRenderW = + (texture.width * atlasRegion.width * regionW) / ((1 - blankLeft - blankRight) * this._pixelsPerUnit); + const realRenderH = + (texture.height * atlasRegion.height * regionH) / ((1 - blankTop - blankBottom) * this._pixelsPerUnit); // Coordinates of the four boundaries. - let lx: number, ty: number, rx: number, by: number; - // TextureSize - let textureW: number, textureH: number; - if (this._atlasRotated) { - textureW = texture.height * atlasRegion.height * pPUReciprocal; - textureH = texture.width * atlasRegion.width * pPUReciprocal; - } else { - textureW = texture.width * atlasRegion.width * pPUReciprocal; - textureH = texture.height * atlasRegion.height * pPUReciprocal; - } - // Determine whether it has been trimmed. - if ( - atlasRegionOffset.x == 0 && - atlasRegionOffset.y == 0 && - atlasRegionOffset.z == 0 && - atlasRegionOffset.w == 0 - ) { - // Real rendering size. - const realRenderW = textureW * regionW; - const realRenderH = textureH * regionH; - lx = -pivot.x * realRenderW; - by = -pivot.y * realRenderH; - rx = realRenderW + lx; - ty = realRenderH + by; - } else { - const { x: blankLeft, y: blankTop, z: blankRight, w: blankBottom } = atlasRegionOffset; - const oriWidth = textureW / (1 - blankRight - blankLeft); - const oriHeight = textureH / (1 - blankBottom - blankTop); - // The size of the real rendering. - lx = (-pivot.x * regionW + Math.max(blankLeft, regionX) - regionX) * oriWidth; - ty = (pivot.y * regionH - Math.max(blankTop, regionY) + regionY) * oriHeight; - rx = (-pivot.x * regionW + Math.min(1 - blankRight, regionX + regionW) - regionX) * oriWidth; - by = (pivot.y * regionH - Math.min(1 - blankBottom, regionY + regionH) + regionY) * oriHeight; - } - + const left = (Math.max(blankLeft - regionX, 0) / regionW - pivot.x) * realRenderW; + const right = (1 - Math.max(blankRight - regionRight, 0) / regionW - pivot.x) * realRenderW; + const top = (1 - Math.max(blankTop - regionBottom, 0) / regionH - pivot.y) * realRenderH; + const bottom = (Math.max(blankBottom - regionY, 0) / regionH - pivot.y) * realRenderH; // Assign values ​​to _positions const positions = this._positions; // Top-left. - positions[0].setValue(lx, ty); + positions[0].setValue(left, top); // Top-right. - positions[1].setValue(rx, ty); + positions[1].setValue(right, top); // Bottom-right. - positions[2].setValue(rx, by); + positions[2].setValue(right, bottom); // Bottom-left. - positions[3].setValue(lx, by); + positions[3].setValue(left, bottom); // Update bounds. - bounds.min.setValue(lx, by, 0); - bounds.max.setValue(rx, ty, 0); + bounds.min.setValue(left, bottom, 0); + bounds.max.setValue(right, top, 0); } else { // Update bounds. bounds.min.setValue(0, 0, 0); @@ -289,71 +263,28 @@ export class Sprite extends RefObject { } if (this._isContainDirtyFlag(DirtyFlag.uv)) { - const { _atlasRegion, _uv: uv, _region: region, _atlasRotated, _atlasRegionOffset: atlasRegionOffset } = this; - let left: number, top: number, right: number, bottom: number; - // Determine whether it has been trimmed. - if ( - atlasRegionOffset.x == 0 && - atlasRegionOffset.y == 0 && - atlasRegionOffset.z == 0 && - atlasRegionOffset.w == 0 - ) { - const { width: atlasRegionW, height: atlasRegionH } = _atlasRegion; - if (_atlasRotated) { - left = atlasRegionW * (1 - region.y - region.height) + _atlasRegion.x; - top = atlasRegionH * region.x + _atlasRegion.y; - right = atlasRegionW * region.height + left; - bottom = atlasRegionH * region.width + top; - } else { - left = atlasRegionW * region.x + _atlasRegion.x; - top = atlasRegionH * region.y + _atlasRegion.y; - right = atlasRegionW * region.width + left; - bottom = atlasRegionH * region.height + top; - } - } else { - const { x: regionX, y: regionY } = region; - const { x: atlasRegionX, y: atlasRegionY } = _atlasRegion; - const { x: blankLeft, y: blankTop, z: blankRight, w: blankBottom } = atlasRegionOffset; - // Proportion of the original sprite size in the atlas. - if (_atlasRotated) { - const textureW = _atlasRegion.width / (1 - blankBottom - blankTop); - const textureH = _atlasRegion.height / (1 - blankRight - blankLeft); - left = (Math.max(blankBottom, 1 - regionY - region.height) - blankBottom) * textureW + atlasRegionX; - top = (Math.max(blankLeft, regionX) - blankLeft) * textureH + atlasRegionY; - right = (Math.min(1 - blankTop, 1 - regionY) - blankBottom) * textureW + atlasRegionX; - bottom = (Math.min(1 - blankRight, regionX + region.width) - blankLeft) * textureH + atlasRegionY; - } else { - const textureW = _atlasRegion.width / (1 - blankRight - blankLeft); - const textureH = _atlasRegion.height / (1 - blankBottom - blankTop); - left = (Math.max(blankLeft, regionX) - blankLeft) * textureW + atlasRegionX; - top = (Math.max(blankTop, regionY) - blankTop) * textureH + atlasRegionY; - right = (Math.min(1 - blankRight, regionX + region.width) - blankLeft) * textureW + atlasRegionX; - bottom = (Math.min(1 - blankBottom, regionY + region.height) - blankTop) * textureH + atlasRegionY; - } - } - - if (_atlasRotated) { - // If it is rotated, we need to rotate the UV 90 degrees counterclockwise to correct it. - // Top-right. - uv[0].setValue(right, top); - // Bottom-right. - uv[1].setValue(right, bottom); - // Bottom-left. - uv[2].setValue(left, bottom); - // Top-left. - uv[3].setValue(left, top); - } else { - // Top-left. - uv[0].setValue(left, top); - // Top-right. - uv[1].setValue(right, top); - // Bottom-right. - uv[2].setValue(right, bottom); - // Bottom-left. - uv[3].setValue(left, bottom); - } + const { _uv: uv, _atlasRegionOffset: atlasRegionOffset } = this; + const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; + const regionRight = 1 - regionX - regionW; + const regionBottom = 1 - regionY - regionH; + const { x: atlasRegionX, y: atlasRegionY, width: atlasRegionW, height: atlasRegionH } = this._atlasRegion; + const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; + const realWidth = atlasRegionW / (1 - offsetLeft - offsetRight); + const realHeight = atlasRegionH / (1 - offsetTop - offsetBottom); + // Coordinates of the four boundaries. + const left = Math.max(regionX - offsetLeft, 0) * realWidth + atlasRegionX; + const top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; + const right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; + const bottom = atlasRegionH + atlasRegionY - Math.max(regionY - offsetBottom, 0) * realHeight; + // Top-left. + uv[0].setValue(left, top); + // Top-right. + uv[1].setValue(right, top); + // Bottom-right. + uv[2].setValue(right, bottom); + // Bottom-left. + uv[3].setValue(left, bottom); } - this._setDirtyFlagFalse(DirtyFlag.all); } From aef4a7738a66a40b6e322233caa295f04d550765 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Tue, 7 Jun 2022 13:57:22 +0800 Subject: [PATCH 12/33] Merge latest main (#820) * v0.7.0-beta.4 * Update README.md * Update README.md * Update README.md * Add component denpendent decorator (#796) (#807) * feat: add `dependentComponents` decorator * fix(Renderer): destroy crash when material is null (#808) * Improve BlendShape when use attribute mode (#804) * feat: improve BlendShape when use attribute mode * v0.7.0-beta.5 * refactor: fix skybox mirror problem * fix: fixed the bug of animator revert when blendWeight length exceeds 4 (#817) * fix: fixed the bug of animator revert when blendWeight length exceeds 4 * v0.7.0-beta.6 * refactor: fix shader * fix(text): fix horizontal and vertical alignment error (#772) * fix(text): fix horizontal alignment error Co-authored-by: luzhuang <364439895@qq.com> Co-authored-by: singlecoder --- README.md | 3 +- lerna.json | 2 +- packages/core/package.json | 6 +- packages/core/src/2d/sprite/Sprite.ts | 5 +- packages/core/src/2d/text/TextRenderer.ts | 46 +- packages/core/src/Renderer.ts | 44 +- .../animation/internal/AnimationCurveOwner.ts | 9 +- packages/core/src/graphic/Mesh.ts | 23 +- packages/core/src/graphic/VertexElement.ts | 10 +- packages/core/src/mesh/BlendShapeManager.ts | 492 +++++++++++++----- packages/core/src/mesh/ModelMesh.ts | 236 ++++----- packages/core/src/mesh/SkinnedMeshRenderer.ts | 41 +- packages/design/package.json | 4 +- packages/draco/package.json | 4 +- packages/loader/package.json | 10 +- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +- packages/physics-lite/package.json | 6 +- packages/physics-physx/package.json | 6 +- packages/rhi-webgl/package.json | 8 +- packages/rhi-webgl/src/GLPrimitive.ts | 14 +- 21 files changed, 591 insertions(+), 390 deletions(-) diff --git a/README.md b/README.md index 41b4c24ece..6f511c5993 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,14 @@ ![npm-download](https://img.shields.io/npm/dm/oasis-engine) [![codecov](https://codecov.io/gh/oasis-engine/engine/branch/main/graph/badge.svg?token=KR2UBKE3OX)](https://codecov.io/gh/oasis-engine/engine) -This is a **web-first** and **mobile-first** high-performance real-time development platform. Use **component system design** and pursue ease of use and light weight. Developers can independently use and write Typescript scripts to develop projects using pure code. +This is a **web-first** and **mobile-first** high-performance real-time interactive engine. Use **component system design** and pursue ease of use and light weight. Developers can independently use and write Typescript scripts to develop projects using pure code. ## Features - 🖥  **Platform** - Suppport HTML5 and Alipay miniprogram - 🔮  **Graphics** - Advanced 2D + 3D graphics engine - 🏃  **Animation** - Powerful animation system +- 🧱  **Physics** - Powerful and easy-to-use physical features - 📑  **Scripts** - Use TypeScript to write logic efficiently ## Usage diff --git a/lerna.json b/lerna.json index 2d86f82025..ee78876ba4 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index 502913146e..f10f2df357 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.7.0-beta.4" + "@oasis-engine/math": "0.7.0-beta.6" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.4" + "@oasis-engine/design": "0.7.0-beta.6" } } diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index 5d9c637f02..e32f826833 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -112,8 +112,9 @@ export class Sprite extends RefObject { set pivot(value: Vector2) { const pivot = this._pivot; - if (pivot === value || pivot.x !== value.x || pivot.y !== value.y) { - pivot.setValue(value.x, value.y); + const { x, y } = value; + if (pivot === value || pivot.x !== x || pivot.y !== y) { + pivot.setValue(x, y); this._setDirtyFlagTrue(DirtyFlag.positions); } } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index d54b446855..2e54ab06c7 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -329,19 +329,12 @@ export class TextRenderer extends Renderer { * @override */ protected _updateBounds(worldBounds: BoundingBox): void { - const sprite = this._sprite; - if (sprite && sprite.texture) { - if (this._customLocalBounds && this._customRootEntity) { - const worldMatrix = this._customRootEntity.transform.worldMatrix; - BoundingBox.transform(this._customLocalBounds, worldMatrix, worldBounds); - } else { - const localBounds = sprite.bounds; - const worldMatrix = this._entity.transform.worldMatrix; - BoundingBox.transform(localBounds, worldMatrix, worldBounds); - } + if (this._customLocalBounds && this._customRootEntity) { + const worldMatrix = this._customRootEntity.transform.worldMatrix; + BoundingBox.transform(this._customLocalBounds, worldMatrix, worldBounds); } else { - worldBounds.min.setValue(0, 0, 0); - worldBounds.max.setValue(0, 0, 0); + const worldMatrix = this._entity.transform.worldMatrix; + BoundingBox.transform(this._sprite.bounds, worldMatrix, worldBounds); } } @@ -378,7 +371,34 @@ export class TextRenderer extends Renderer { const { width, height } = trimData; const canvas = TextUtils.updateCanvas(width, height, trimData.data); this._clearTexture(); - const { _sprite: sprite } = this; + const { _sprite: sprite, horizontalAlignment, verticalAlignment } = this; + + // Handle the case that width or height of text is larger than real width or height. + const { pixelsPerUnit, pivot } = sprite; + switch (horizontalAlignment) { + case TextHorizontalAlignment.Left: + pivot.x = (this.width * pixelsPerUnit) / width * 0.5; + break; + case TextHorizontalAlignment.Right: + pivot.x = 1 - (this.width * pixelsPerUnit) / width * 0.5; + break; + case TextHorizontalAlignment.Center: + pivot.x = 0.5; + break; + } + switch (verticalAlignment) { + case TextVerticalAlignment.Top: + pivot.y = 1 - (this.height * pixelsPerUnit) / height * 0.5; + break; + case TextVerticalAlignment.Bottom: + pivot.y = (this.height * pixelsPerUnit) / height * 0.5; + break; + case TextVerticalAlignment.Center: + pivot.y = 0.5; + break; + } + sprite.pivot = pivot; + // If add fail, set texture for sprite. if (!this.engine._dynamicTextAtlasManager.addSprite(sprite, canvas)) { const texture = new Texture2D(this.engine, width, height); diff --git a/packages/core/src/Renderer.ts b/packages/core/src/Renderer.ts index cdbdb4b624..1ca9d1b801 100644 --- a/packages/core/src/Renderer.ts +++ b/packages/core/src/Renderer.ts @@ -14,7 +14,7 @@ import { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; import { Transform } from "./Transform"; /** - * Renderable component. + * Basis for all renderers. * @decorator `@dependentComponents(Transform)` */ @dependentComponents(Transform) @@ -177,26 +177,10 @@ export class Renderer extends Component { setMaterial(index: number, material: Material): void; setMaterial(indexOrMaterial: number | Material, material: Material = null): void { - let index; if (typeof indexOrMaterial === "number") { - index = indexOrMaterial; + this._setMaterial(indexOrMaterial, material); } else { - index = 0; - material = indexOrMaterial; - } - - const materials = this._materials; - if (index >= materials.length) { - materials.length = index + 1; - } - - const materialsInstance = this._materialsInstanced; - const internalMaterial = materials[index]; - if (internalMaterial !== material) { - materials[index] = material; - index < materialsInstance.length && (materialsInstance[index] = false); - internalMaterial && internalMaterial._addRefCount(-1); - material && material._addRefCount(1); + this._setMaterial(0, indexOrMaterial); } } @@ -314,8 +298,9 @@ export class Renderer extends Component { this.shaderData._addRefCount(-1); - for (let i = 0, n = this._materials.length; i < n; i++) { - this._materials[i]._addRefCount(-1); + const materials = this._materials; + for (let i = 0, n = materials.length; i < n; i++) { + materials[i]?._addRefCount(-1); } } @@ -330,4 +315,21 @@ export class Renderer extends Component { this._materials[index] = insMaterial; return insMaterial; } + + private _setMaterial(index: number, material: Material): void { + const materials = this._materials; + if (index >= materials.length) { + materials.length = index + 1; + } + + const internalMaterial = materials[index]; + if (internalMaterial !== material) { + const materialsInstance = this._materialsInstanced; + index < materialsInstance.length && (materialsInstance[index] = false); + + internalMaterial && internalMaterial._addRefCount(-1); + material && material._addRefCount(1); + materials[index] = material; + } + } } diff --git a/packages/core/src/animation/internal/AnimationCurveOwner.ts b/packages/core/src/animation/internal/AnimationCurveOwner.ts index 9b4bf29005..11ef24a3b7 100644 --- a/packages/core/src/animation/internal/AnimationCurveOwner.ts +++ b/packages/core/src/animation/internal/AnimationCurveOwner.ts @@ -18,7 +18,7 @@ export class AnimationCurveOwner { readonly component: Component; readonly defaultValue: InterpolableValue; readonly fixedPoseValue: InterpolableValue; - + /** @internal */ _hasSavedDefaultValue: boolean = false; @@ -43,9 +43,10 @@ export class AnimationCurveOwner { this.component = target.transform; break; case AnimationProperty.BlendShapeWeights: - this.defaultValue = new Float32Array(4); - this.fixedPoseValue = new Float32Array(4); this.component = target.getComponent(SkinnedMeshRenderer); + const weightLength = (this.component).blendShapeWeights.length; + this.defaultValue = new Float32Array(weightLength); + this.fixedPoseValue = new Float32Array(weightLength); break; } } @@ -64,7 +65,7 @@ export class AnimationCurveOwner { case AnimationProperty.BlendShapeWeights: const { blendShapeWeights } = this.component; for (let i = 0, length = blendShapeWeights.length; i < length; ++i) { - this.defaultValue[i] = (this.component).blendShapeWeights[i]; + this.defaultValue[i] = blendShapeWeights[i]; } break; } diff --git a/packages/core/src/graphic/Mesh.ts b/packages/core/src/graphic/Mesh.ts index b1622e1982..b6e6de5922 100644 --- a/packages/core/src/graphic/Mesh.ts +++ b/packages/core/src/graphic/Mesh.ts @@ -34,6 +34,8 @@ export abstract class Mesh extends RefObject { _indexBufferBinding: IndexBufferBinding = null; /** @internal */ _vertexElements: VertexElement[] = []; + /** @internal */ + _enableVAO: boolean = true; private _subMeshes: SubMesh[] = []; private _updateFlagManager: UpdateFlagManager = new UpdateFlagManager(); @@ -139,6 +141,18 @@ export abstract class Mesh extends RefObject { this._updateFlagManager.dispatch(); } + /** + * @internal + */ + _setVertexBufferBinding(index: number, binding: VertexBufferBinding): void { + if (this._getRefCount() > 0) { + const lastBinding = this._vertexBufferBindings[index]; + lastBinding && lastBinding._buffer._addRefCount(-1); + binding._buffer._addRefCount(1); + } + this._vertexBufferBindings[index] = binding; + } + /** * @internal */ @@ -176,15 +190,6 @@ export abstract class Mesh extends RefObject { } } - protected _setVertexBufferBinding(index: number, binding: VertexBufferBinding): void { - if (this._getRefCount() > 0) { - const lastBinding = this._vertexBufferBindings[index]; - lastBinding && lastBinding._buffer._addRefCount(-1); - binding._buffer._addRefCount(1); - } - this._vertexBufferBindings[index] = binding; - } - protected _setIndexBufferBinding(binding: IndexBufferBinding | null): void { if (binding) { this._indexBufferBinding = binding; diff --git a/packages/core/src/graphic/VertexElement.ts b/packages/core/src/graphic/VertexElement.ts index 6c117ccea0..ffc39d9cf1 100644 --- a/packages/core/src/graphic/VertexElement.ts +++ b/packages/core/src/graphic/VertexElement.ts @@ -1,5 +1,5 @@ +import { BufferUtil, ElementInfo } from "./BufferUtil"; import { VertexElementFormat } from "./enums/VertexElementFormat"; -import { ElementInfo, BufferUtil } from "./BufferUtil"; /** * Vertex element. @@ -27,6 +27,10 @@ export class VertexElement { return this._offset; } + set offset(value: number) { + this._offset = value; + } + /** * Vertex data format. */ @@ -41,6 +45,10 @@ export class VertexElement { return this._bindingIndex; } + set bindingIndex(value: number) { + this._bindingIndex = value; + } + /** * Instance cadence, the number of instances drawn for each vertex in the buffer, non-instance elements must be 0. */ diff --git a/packages/core/src/mesh/BlendShapeManager.ts b/packages/core/src/mesh/BlendShapeManager.ts index 1a894ab6a6..c21e2bf2c1 100644 --- a/packages/core/src/mesh/BlendShapeManager.ts +++ b/packages/core/src/mesh/BlendShapeManager.ts @@ -1,46 +1,67 @@ -import { Vector3 } from "@oasis-engine/math"; +import { Vector2, Vector3 } from "@oasis-engine/math"; import { BoolUpdateFlag } from "../BoolUpdateFlag"; import { Engine } from "../Engine"; -import { VertexElement, VertexElementFormat } from "../graphic"; +import { Buffer } from "../graphic/Buffer"; +import { BufferBindFlag } from "../graphic/enums/BufferBindFlag"; +import { BufferUsage } from "../graphic/enums/BufferUsage"; +import { VertexElementFormat } from "../graphic/enums/VertexElementFormat"; +import { VertexBufferBinding } from "../graphic/VertexBufferBinding"; +import { VertexElement } from "../graphic/VertexElement"; import { ListenerUpdateFlag } from "../ListenerUpdateFlag"; +import { Shader } from "../shader/Shader"; +import { ShaderData } from "../shader/ShaderData"; import { Texture2DArray, TextureFilterMode, TextureFormat } from "../texture"; import { BlendShape } from "./BlendShape"; import { ModelMesh } from "./ModelMesh"; +import { SkinnedMeshRenderer } from "./SkinnedMeshRenderer"; /** * @internal */ export class BlendShapeManager { + private static _blendShapeMacro = Shader.getMacroByName("OASIS_BLENDSHAPE"); + private static _blendShapeTextureMacro = Shader.getMacroByName("OASIS_BLENDSHAPE_TEXTURE"); + private static _blendShapeNormalMacro = Shader.getMacroByName("OASIS_BLENDSHAPE_NORMAL"); + private static _blendShapeTangentMacro = Shader.getMacroByName("OASIS_BLENDSHAPE_TANGENT"); + + private static _blendShapeWeightsProperty = Shader.getPropertyByName("u_blendShapeWeights"); + private static _blendShapeTextureProperty = Shader.getPropertyByName("u_blendShapeTexture"); + private static _blendShapeTextureInfoProperty = Shader.getPropertyByName("u_blendShapeTextureInfo"); + /** @internal */ - _useBlendNormal: boolean = true; - /** @internal */ - _useBlendTangent: boolean = true; + _blendShapeCount: number = 0; /** @internal */ _blendShapes: BlendShape[] = []; /** @internal */ _blendShapeNames: string[]; /** @internal */ - _blendShapeCount: number = 0; - /** @internal */ _layoutDirtyFlag: ListenerUpdateFlag = new ListenerUpdateFlag(); /** @internal */ _subDataDirtyFlags: BoolUpdateFlag[] = []; - /** @internal */ - _dataTextureBuffer: Float32Array; + _vertexTexture: Texture2DArray; /** @internal */ - _dataTexture: Texture2DArray; + _vertexBuffers: Buffer[] = []; /** @internal */ - readonly _dataTextureInfo: Vector3 = new Vector3(); - + _vertices: Float32Array; + + private _useBlendNormal: boolean = false; + private _useBlendTangent: boolean = false; + private _vertexElementCount: number = 0; + private _vertexElementOffset: number; + private _storeInVertexBufferInfo: Vector2[] = []; + private _maxCountSingleVertexBuffer: number = 0; private readonly _engine: Engine; - private readonly _lastUpdateLayoutAndCountInfo: Vector3 = new Vector3(0, 0, 0); + private readonly _modelMesh: ModelMesh; + private readonly _lastCreateHostInfo: Vector3 = new Vector3(0, 0, 0); private readonly _canUseTextureStoreData: boolean = true; + private readonly _dataTextureInfo: Vector3 = new Vector3(); - constructor(engine: Engine) { + constructor(engine: Engine, modelMesh: ModelMesh) { this._engine = engine; + this._modelMesh = modelMesh; this._canUseTextureStoreData = this._engine._hardwareRenderer.capability.canUseFloatTextureBlendShape; - this._layoutDirtyFlag.listener = this._updateUsePropertyFlag.bind(this); + this._layoutDirtyFlag.listener = this._updateLayoutChange.bind(this); } /** @@ -51,7 +72,7 @@ export class BlendShapeManager { this._blendShapeCount++; blendShape._addLayoutChangeFlag(this._layoutDirtyFlag); - this._updateUsePropertyFlag(blendShape); + this._updateLayoutChange(blendShape); this._subDataDirtyFlags.push(blendShape._createSubDataDirtyFlag()); } @@ -60,8 +81,9 @@ export class BlendShapeManager { * @internal */ _clearBlendShapes(): void { - this._useBlendNormal = true; - this._useBlendTangent = true; + this._useBlendNormal = false; + this._useBlendTangent = false; + this._vertexElementCount = 0; this._blendShapes.length = 0; this._blendShapeCount = 0; @@ -76,30 +98,82 @@ export class BlendShapeManager { /** * @internal */ - _useTextureStore(): boolean { - if (!this._canUseTextureStoreData) { - return false; - } + _updateShaderData(shaderData: ShaderData, skinnedMeshRenderer: SkinnedMeshRenderer): void { + const blendShapeCount = this._blendShapeCount; + if (blendShapeCount > 0) { + shaderData.enableMacro(BlendShapeManager._blendShapeMacro); + shaderData.enableMacro("OASIS_BLENDSHAPE_COUNT", blendShapeCount.toString()); + if (this._useTextureMode()) { + shaderData.enableMacro(BlendShapeManager._blendShapeTextureMacro); + shaderData.setTexture(BlendShapeManager._blendShapeTextureProperty, this._vertexTexture); + shaderData.setVector3(BlendShapeManager._blendShapeTextureInfoProperty, this._dataTextureInfo); + shaderData.setFloatArray(BlendShapeManager._blendShapeWeightsProperty, skinnedMeshRenderer._blendShapeWeights); + } else { + const maxBlendCount = this._getVertexBufferModeSupportCount(); + if (blendShapeCount > maxBlendCount) { + let condensedBlendShapeWeights = skinnedMeshRenderer._condensedBlendShapeWeights; + if (!condensedBlendShapeWeights) { + condensedBlendShapeWeights = new Float32Array(maxBlendCount); + skinnedMeshRenderer._condensedBlendShapeWeights = condensedBlendShapeWeights; + } + this._filterCondensedBlendShapeWeights(skinnedMeshRenderer._blendShapeWeights, condensedBlendShapeWeights); + shaderData.setFloatArray(BlendShapeManager._blendShapeWeightsProperty, condensedBlendShapeWeights); + this._modelMesh._enableVAO = false; + } else { + shaderData.setFloatArray( + BlendShapeManager._blendShapeWeightsProperty, + skinnedMeshRenderer._blendShapeWeights + ); + this._modelMesh._enableVAO = true; + } + shaderData.disableMacro(BlendShapeManager._blendShapeTextureMacro); + } - if (this._useBlendNormal || this._useBlendTangent) { - return this._blendShapeCount > 4; + if (this._useBlendNormal) { + shaderData.enableMacro(BlendShapeManager._blendShapeNormalMacro); + } else { + shaderData.disableMacro(BlendShapeManager._blendShapeNormalMacro); + } + if (this._useBlendTangent) { + shaderData.enableMacro(BlendShapeManager._blendShapeTangentMacro); + } else { + shaderData.disableMacro(BlendShapeManager._blendShapeTangentMacro); + } } else { - return this._blendShapeCount > 8; + shaderData.disableMacro(BlendShapeManager._blendShapeMacro); + shaderData.disableMacro("OASIS_BLENDSHAPE_COUNT"); } } /** * @internal */ - _layoutOrCountChange(): boolean { - const lastInfo = this._lastUpdateLayoutAndCountInfo; - if ( - lastInfo.x !== this._blendShapeCount || - !!lastInfo.y !== this._useBlendNormal || - !!lastInfo.z !== this._useBlendTangent - ) { - return true; + _useTextureMode(): boolean { + if (!this._canUseTextureStoreData) { + return false; } + return this._blendShapeCount > this._getVertexBufferModeSupportCount(); + } + + /** + * @internal + */ + _layoutOrCountChange(): boolean { + const last = this._lastCreateHostInfo; + return last.x !== this._blendShapeCount || !!last.y !== this._useBlendNormal || !!last.z !== this._useBlendTangent; + } + + /** + * @internal + */ + _vertexElementsNeedUpdate(): boolean { + const maxSupportCount = this._getVertexBufferModeSupportCount(); + const info = this._lastCreateHostInfo; + return ( + Math.min(info.x, maxSupportCount) !== Math.min(this._blendShapeCount, maxSupportCount) || + !!info.y !== this._useBlendNormal || + !!info.z !== this._useBlendTangent + ); } /** @@ -118,39 +192,148 @@ export class BlendShapeManager { /** * @internal */ - _updateVertexElements(modelMesh: ModelMesh, offset: number): number { - let elementCount = 0; - for (let i = 0, n = this._blendShapeCount; i < n; i++) { - modelMesh._addVertexElement(new VertexElement(`POSITION_BS${i}`, offset, VertexElementFormat.Vector3, 0)); + _addVertexElements(modelMesh: ModelMesh): void { + let offset = 0; + this._vertexElementOffset = modelMesh._vertexElements.length; + for (let i = 0, n = Math.min(this._blendShapeCount, this._getVertexBufferModeSupportCount()); i < n; i++) { + modelMesh._addVertexElement(new VertexElement(`POSITION_BS${i}`, offset, VertexElementFormat.Vector3, 1)); offset += 12; - elementCount += 3; if (this._useBlendNormal) { - modelMesh._addVertexElement(new VertexElement(`NORMAL_BS${i}`, offset, VertexElementFormat.Vector3, 0)); + modelMesh._addVertexElement(new VertexElement(`NORMAL_BS${i}`, offset, VertexElementFormat.Vector3, 1)); offset += 12; - elementCount += 3; } if (this._useBlendTangent) { - modelMesh._addVertexElement(new VertexElement(`TANGENT_BS${i}`, offset, VertexElementFormat.Vector3, 0)); - elementCount += 3; + modelMesh._addVertexElement(new VertexElement(`TANGENT_BS${i}`, offset, VertexElementFormat.Vector3, 1)); + offset += 12; } } + } - this._lastUpdateLayoutAndCountInfo.setValue(this._blendShapeCount, +this._useBlendNormal, +this._useBlendTangent); - return elementCount; + /** + * @internal + */ + _update(vertexCountChange: boolean, noLongerAccessible: boolean): void { + const { vertexCount } = this._modelMesh; + const useTexture = this._useTextureMode(); + const createHost = this._layoutOrCountChange() || vertexCountChange; + + if (createHost) { + if (useTexture) { + this._createTextureArray(vertexCount); + } else { + this._createVertexBuffers(vertexCount, noLongerAccessible); + } + this._lastCreateHostInfo.setValue(this._blendShapeCount, +this._useBlendNormal, +this._useBlendTangent); + } + if (this._needUpdateData()) { + if (useTexture) { + this._updateTextureArray(vertexCount, createHost); + } else { + this._updateVertexBuffers(vertexCount, createHost); + } + } } /** * @internal */ - _updateDataToVertices( - vertices: Float32Array, - offset: number, - vertexCount: number, - elementCount: number, - force: boolean - ): void { - const blendShapes = this._blendShapes; + _releaseMemoryCache(): void { + const { _blendShapes: blendShapes } = this; + const { length: blendShapeCount } = blendShapes; + + const blendShapeNamesMap = new Array(blendShapeCount); + for (let i = 0; i < blendShapeCount; i++) { + blendShapeNamesMap[i] = blendShapes[i].name; + } + this._blendShapeNames = blendShapeNamesMap; + + this._layoutDirtyFlag.destroy(); + const dataChangedFlags = this._subDataDirtyFlags; + for (let i = 0, n = dataChangedFlags.length; i < n; i++) { + dataChangedFlags[i].destroy(); + } + + this._layoutDirtyFlag = null; + this._subDataDirtyFlags = null; + this._blendShapes = null; + this._vertices = null; + } + + private _createVertexBuffers(vertexCount: number, noLongerAccessible: boolean): void { + const { + _engine: engine, + _modelMesh: modelMesh, + _blendShapeCount: blendShapeCount, + _vertexBuffers: vertexBuffers + } = this; + const vertexFloatCount = this._vertexElementCount * 3; + const vertexByteCount = vertexFloatCount * 4; + const maxCountSingleBuffer = Math.floor(255 / vertexByteCount); // 255: Attribute MaxStride + const bufferCount = Math.ceil(blendShapeCount / maxCountSingleBuffer); + const floatCount = vertexFloatCount * vertexCount * Math.min(maxCountSingleBuffer, blendShapeCount); + + vertexBuffers.length = bufferCount; + this._vertices = new Float32Array(floatCount); + this._maxCountSingleVertexBuffer = maxCountSingleBuffer; + this._storeInVertexBufferInfo.length = blendShapeCount; + + for (let i = 0; i < bufferCount; i++) { + const lastIndex = bufferCount - 1; + const containCount = i === lastIndex ? blendShapeCount - lastIndex * maxCountSingleBuffer : maxCountSingleBuffer; + const stride = containCount * vertexByteCount; + const byteLength = stride * vertexCount; + + const usage = noLongerAccessible ? BufferUsage.Static : BufferUsage.Dynamic; + + const blendShapeBuffer = new Buffer(engine, BufferBindFlag.VertexBuffer, byteLength, usage); + modelMesh._setVertexBufferBinding(i + 1, new VertexBufferBinding(blendShapeBuffer, stride)); + vertexBuffers[i] = blendShapeBuffer; + } + } + + private _createTextureArray(vertexCount: number): void { + const maxTextureSize = this._engine._hardwareRenderer.capability.maxTextureSize; + const vertexPixelStride = this._vertexElementCount; + + let textureWidth = vertexPixelStride * vertexCount; + let textureHeight = 1; + if (textureWidth > maxTextureSize) { + textureHeight = Math.ceil(textureWidth / maxTextureSize); + textureWidth = maxTextureSize; + } + + let blendShapeDataTexture = this._vertexTexture; + const blendShapeCount = this._blendShapes.length; + + blendShapeDataTexture && blendShapeDataTexture.destroy(); + + blendShapeDataTexture = new Texture2DArray( + this._engine, + textureWidth, + textureHeight, + blendShapeCount, + TextureFormat.R32G32B32A32, + false + ); + blendShapeDataTexture.filterMode = TextureFilterMode.Point; + + this._vertices = new Float32Array(blendShapeCount * textureWidth * textureHeight * 4); + this._vertexTexture = blendShapeDataTexture; + this._dataTextureInfo.setValue(vertexPixelStride, textureWidth, textureHeight); + } + + /** + * @internal + */ + _updateVertexBuffers(vertexCount: number, force: boolean): void { + const { _blendShapes: blendShapes, _maxCountSingleVertexBuffer: maxCountSingleBuffer } = this; + const { _vertices: vertices, _vertexBuffers: vertexBuffers, _storeInVertexBufferInfo: storeInfos } = this; + const subDataDirtyFlags = this._subDataDirtyFlags; + const blendShapeFloatStride = this._vertexElementCount * 3; + const blendShapeByteStride = blendShapeFloatStride * 4; + + // @todo: should fix bug when dataChangedFlag is true for (let i = 0, n = blendShapes.length; i < n; i++) { const dataChangedFlag = subDataDirtyFlags[i]; if (force || dataChangedFlag.flag) { @@ -161,9 +344,20 @@ export class BlendShapeManager { throw "BlendShape frame deltaPositions length must same with mesh vertexCount."; } + const bufferIndex = Math.floor(i / maxCountSingleBuffer); + const indexInBuffer = i % maxCountSingleBuffer; + const buffer = vertexBuffers[bufferIndex]; + const bufferFloatStride = buffer.byteLength / (vertexCount * 4); + + let offset = indexInBuffer * blendShapeFloatStride; + + let storeInfo = storeInfos[i]; + storeInfo || (storeInfos[i] = storeInfo = new Vector2()); + storeInfo.setValue(bufferIndex + 1, indexInBuffer * blendShapeByteStride); // BlendShape buffer is start from 1 + const { deltaPositions } = endFrame; for (let j = 0; j < vertexCount; j++) { - const start = elementCount * j + offset; + const start = offset + bufferFloatStride * j; const deltaPosition = deltaPositions[j]; if (deltaPosition) { vertices[start] = deltaPosition.x; @@ -177,7 +371,7 @@ export class BlendShapeManager { const { deltaNormals } = endFrame; if (deltaNormals) { for (let j = 0; j < vertexCount; j++) { - const start = elementCount * j + offset; + const start = offset + bufferFloatStride * j; const deltaNormal = deltaNormals[j]; if (deltaNormal) { vertices[start] = deltaNormal.x; @@ -193,7 +387,7 @@ export class BlendShapeManager { const { deltaTangents } = endFrame; if (deltaTangents) { for (let j = 0; j < vertexCount; j++) { - const start = elementCount * j + offset; + const start = offset + bufferFloatStride * j; const deltaTangent = deltaTangents[j]; if (deltaTangent) { vertices[start] = deltaTangent.x; @@ -204,76 +398,28 @@ export class BlendShapeManager { } offset += 3; } + + if (indexInBuffer === maxCountSingleBuffer - 1 || i === n - 1) { + // @todo: can optimize in setData + buffer.setData(vertices, 0, 0, buffer.byteLength / 4); + } + dataChangedFlag.flag = false; } } } - /** - * @internal - */ - _updateTexture( - layoutOrCountChange: boolean, - vertexCountChange: boolean, - needUpdateBlendShape: boolean, - vertexCount: number - ): void { - let reCreateTexture = !this._dataTexture || layoutOrCountChange || vertexCountChange; - if (reCreateTexture) { - this._createDataTexture(vertexCount); - this._lastUpdateLayoutAndCountInfo.setValue(this._blendShapeCount, +this._useBlendNormal, +this._useBlendTangent); - } - if (needUpdateBlendShape) { - this._updateDataToTexture(vertexCount, reCreateTexture); - } - } - - private _createDataTexture(vertexCount: number): void { - const maxTextureSize = this._engine._hardwareRenderer.capability.maxTextureSize; - - let vertexPixelStride = 1; - this._useBlendNormal && vertexPixelStride++; - this._useBlendTangent && vertexPixelStride++; - - let textureWidth = vertexPixelStride * vertexCount; - let textureHeight = 1; - if (textureWidth > maxTextureSize) { - textureHeight = Math.ceil(textureWidth / maxTextureSize); - textureWidth = maxTextureSize; - } - - let blendShapeDataTexture = this._dataTexture; - const blendShapeCount = this._blendShapes.length; - - blendShapeDataTexture && blendShapeDataTexture.destroy(); - - blendShapeDataTexture = new Texture2DArray( - this._engine, - textureWidth, - textureHeight, - blendShapeCount, - TextureFormat.R32G32B32A32, - false - ); - blendShapeDataTexture.filterMode = TextureFilterMode.Point; - - this._dataTextureBuffer = new Float32Array(blendShapeCount * textureWidth * textureHeight * 4); - this._dataTexture = blendShapeDataTexture; - this._dataTextureInfo.setValue(vertexPixelStride, textureWidth, textureHeight); - } - - private _updateDataToTexture(vertexCount: number, force: boolean): void { + private _updateTextureArray(vertexCount: number, force: boolean): void { const { _blendShapes: blendShapes, - _dataTexture: dataTexture, - _dataTextureBuffer: buffer, + _vertexTexture: vertexTexture, + _vertices: vertices, _subDataDirtyFlags: subDataDirtyFlags } = this; - let offset = 0; for (let i = 0, n = blendShapes.length; i < n; i++) { const subDirtyFlag = subDataDirtyFlags[i]; - const subBlendShapeDataStride = dataTexture.width * dataTexture.height * 4; + const subBlendShapeDataStride = vertexTexture.width * vertexTexture.height * 4; if (force || subDirtyFlag.flag) { const { frames } = blendShapes[i]; const frameCount = frames.length; @@ -281,61 +427,121 @@ export class BlendShapeManager { if (frameCount > 0 && endFrame.deltaPositions.length !== vertexCount) { throw "BlendShape frame deltaPositions length must same with mesh vertexCount."; } + const { deltaPositions, deltaNormals, deltaTangents } = endFrame; - offset = i * subBlendShapeDataStride; + let offset = i * subBlendShapeDataStride; for (let j = 0; j < vertexCount; j++) { const position = deltaPositions[j]; - buffer[offset] = position.x; - buffer[offset + 1] = position.y; - buffer[offset + 2] = position.z; + vertices[offset] = position.x; + vertices[offset + 1] = position.y; + vertices[offset + 2] = position.z; offset += 4; if (deltaNormals) { const normal = deltaNormals[j]; - buffer[offset] = normal.x; - buffer[offset + 1] = normal.y; - buffer[offset + 2] = normal.z; + vertices[offset] = normal.x; + vertices[offset + 1] = normal.y; + vertices[offset + 2] = normal.z; offset += 4; } if (deltaTangents) { const tangent = deltaTangents[j]; - buffer[offset] = tangent.x; - buffer[offset + 1] = tangent.y; - buffer[offset + 2] = tangent.z; + vertices[offset] = tangent.x; + vertices[offset + 1] = tangent.y; + vertices[offset + 2] = tangent.z; offset += 4; } } subDirtyFlag.flag = false; } } - dataTexture.setPixelBuffer(0, buffer); + vertexTexture.setPixelBuffer(0, vertices); } - /** - * @internal - */ - _releaseMemoryCache(): void { - const { _blendShapes: blendShapes } = this; - const blendShapeNamesMap = new Array(blendShapes.length); - for (let i = 0, n = blendShapes.length; i < n; i++) { - blendShapeNamesMap[i] = blendShapes[i].name; + private _updateLayoutChange(blendShape: BlendShape): void { + const notFirst = this._blendShapeCount > 1; + let vertexElementCount = 1; + let useBlendNormal = blendShape._useBlendShapeNormal; + let useBlendTangent = blendShape._useBlendShapeTangent; + if (notFirst) { + useBlendNormal &&= this._useBlendNormal; + useBlendTangent &&= this._useBlendTangent; } - this._blendShapeNames = blendShapeNamesMap; - this._layoutDirtyFlag.destroy(); - const dataChangedFlags = this._subDataDirtyFlags; - for (let i = 0, n = dataChangedFlags.length; i < n; i++) { - dataChangedFlags[i].destroy(); + useBlendNormal && vertexElementCount++; + useBlendTangent && vertexElementCount++; + + this._useBlendNormal = useBlendNormal; + this._useBlendTangent = useBlendTangent; + this._vertexElementCount = vertexElementCount; + } + + private _attributeModeUpdateVertexElement( + vertexElements: VertexElement[], + vertexBufferStoreInfo: Vector2[], + index: number, + condensedIndex: number + ): void { + let elementOffset = this._vertexElementOffset + this._vertexElementCount * condensedIndex; + + let { x: bufferIndex, y: offset } = vertexBufferStoreInfo[index]; + const vertexElement = vertexElements[elementOffset]; + vertexElement.bindingIndex = bufferIndex; + vertexElement.offset = offset; + if (this._useBlendNormal) { + const vertexElement = vertexElements[++elementOffset]; + offset += 12; + vertexElement.bindingIndex = bufferIndex; + vertexElement.offset = offset; } + if (this._useBlendTangent) { + const vertexElement = vertexElements[++elementOffset]; + offset += 12; + vertexElement.bindingIndex = bufferIndex; + vertexElement.offset = offset; + } + } - this._layoutDirtyFlag = null; - this._subDataDirtyFlags = null; - this._blendShapes = null; + private _getVertexBufferModeSupportCount(): number { + if (this._useBlendNormal || this._useBlendTangent) { + return 4; + } else { + return 8; + } } - private _updateUsePropertyFlag(blendShape: BlendShape): void { - this._useBlendNormal = blendShape._useBlendShapeNormal && this._useBlendNormal; - this._useBlendTangent = blendShape._useBlendShapeTangent && this._useBlendTangent; + private _filterCondensedBlendShapeWeights( + blendShapeWeights: Float32Array, + condensedBlendShapeWeights: Float32Array + ): void { + const condensedWeightsCount = condensedBlendShapeWeights.length; + const vertexElements = this._modelMesh._vertexElements; + const vertexBufferStoreInfo = this._storeInVertexBufferInfo; + let thresholdWeight = Number.POSITIVE_INFINITY; + let thresholdIndex: number; + for (let i = 0, n = Math.min(blendShapeWeights.length, this._blendShapeCount); i < n; i++) { + const weight = blendShapeWeights[i]; + if (i < condensedWeightsCount) { + this._attributeModeUpdateVertexElement(vertexElements, vertexBufferStoreInfo, i, i); + condensedBlendShapeWeights[i] = weight; + if (weight < thresholdWeight) { + thresholdWeight = weight; + thresholdIndex = i; + } + } else if (weight > thresholdWeight) { + this._attributeModeUpdateVertexElement(vertexElements, vertexBufferStoreInfo, i, thresholdIndex); + condensedBlendShapeWeights[thresholdIndex] = weight; + + thresholdWeight = Number.POSITIVE_INFINITY; + for (let j = 0; j < condensedWeightsCount; j++) { + const condensedWeight = condensedBlendShapeWeights[j]; + if (condensedWeight < thresholdWeight) { + thresholdWeight = condensedWeight; + thresholdIndex = j; + } + } + } + } } } diff --git a/packages/core/src/mesh/ModelMesh.ts b/packages/core/src/mesh/ModelMesh.ts index 787a9b86f8..98975f2605 100644 --- a/packages/core/src/mesh/ModelMesh.ts +++ b/packages/core/src/mesh/ModelMesh.ts @@ -28,7 +28,7 @@ export class ModelMesh extends Mesh { private _vertexSlotChanged: boolean = true; private _vertexChangeFlag: number = 0; private _indicesChangeFlag: boolean = false; - private _elementCount: number = 0; + private _vertexStrideFloat: number = 0; private _lastUploadVertexCount: number = -1; private _positions: Vector3[] = []; @@ -85,7 +85,7 @@ export class ModelMesh extends Mesh { constructor(engine: Engine, name?: string) { super(engine); this.name = name; - this._blendShapeManager = new BlendShapeManager(engine); + this._blendShapeManager = new BlendShapeManager(engine, this); } /** @@ -433,7 +433,7 @@ export class ModelMesh extends Mesh { } /** - * Upload Mesh Data to the graphics API. + * Upload Mesh Data to GPU. * @param noLongerAccessible - Whether to access data later. If true, you'll never access data anymore (free memory cache) */ uploadData(noLongerAccessible: boolean): void { @@ -441,31 +441,20 @@ export class ModelMesh extends Mesh { throw "Not allowed to access data while accessible is false."; } - const blendManager = this._blendShapeManager; - const blendTextureStore = blendManager._useTextureStore(); - const blendLayoutOrCountChange = blendManager._layoutOrCountChange(); - const blendDataUpdate = blendManager._needUpdateData(); - const blendVertexElementChanged = !blendTextureStore && blendLayoutOrCountChange; - const vertexElementUpdate = this._vertexSlotChanged || blendVertexElementChanged; - - // Vertex element change - if (vertexElementUpdate) { - this._updateVertexElements(blendVertexElementChanged); - } - const { _vertexCount: vertexCount } = this; + const vertexElementChanged = this._updateVertexElements(); const vertexCountChange = this._lastUploadVertexCount !== vertexCount; // Vertex count change const vertexBuffer = this._vertexBufferBindings[0]?._buffer; if (vertexCountChange) { vertexBuffer?.destroy(); - const elementCount = this._elementCount; + const elementCount = this._vertexStrideFloat; const vertexFloatCount = elementCount * vertexCount; const vertices = new Float32Array(vertexFloatCount); this._verticesFloat32 = vertices; this._verticesUint8 = new Uint8Array(vertices.buffer); - this._updateVertices(vertices, !blendTextureStore, true); + this._updateVertices(vertices, true); const newVertexBuffer = new Buffer( this._engine, @@ -477,24 +466,23 @@ export class ModelMesh extends Mesh { this._setVertexBufferBinding(0, new VertexBufferBinding(newVertexBuffer, elementCount * 4)); this._lastUploadVertexCount = vertexCount; } else { - const blendVerticesUpdate = !blendTextureStore && blendDataUpdate; - if (this._vertexChangeFlag & ValueChanged.All || blendVerticesUpdate) { + if (this._vertexChangeFlag & ValueChanged.All) { const vertices = this._verticesFloat32; - this._updateVertices(vertices, blendVerticesUpdate, vertexElementUpdate); + this._updateVertices(vertices, vertexElementChanged); vertexBuffer.setData(vertices); } } - const { _indices } = this; + const { _indices: indices } = this; const indexBuffer = this._indexBufferBinding?._buffer; - if (_indices) { - if (!indexBuffer || _indices.byteLength != indexBuffer.byteLength) { + if (indices) { + if (!indexBuffer || indices.byteLength != indexBuffer.byteLength) { indexBuffer?.destroy(); - const newIndexBuffer = new Buffer(this._engine, BufferBindFlag.IndexBuffer, _indices); + const newIndexBuffer = new Buffer(this._engine, BufferBindFlag.IndexBuffer, indices); this._setIndexBufferBinding(new IndexBufferBinding(newIndexBuffer, this._indicesFormat)); this._indicesChangeFlag = false; } else if (this._indicesChangeFlag) { - indexBuffer.setData(_indices); + indexBuffer.setData(indices); if (this._indexBufferBinding._format !== this._indicesFormat) { this._setIndexBufferBinding(new IndexBufferBinding(indexBuffer, this._indicesFormat)); } @@ -505,9 +493,8 @@ export class ModelMesh extends Mesh { this._setIndexBufferBinding(null); } - if (blendTextureStore) { - blendManager._updateTexture(blendLayoutOrCountChange, vertexCountChange, blendDataUpdate, vertexCount); - } + const { _blendShapeManager: blendShapeManager } = this; + blendShapeManager._blendShapeCount > 0 && blendShapeManager._update(vertexCountChange, noLongerAccessible); if (noLongerAccessible) { this._accessible = false; @@ -524,95 +511,100 @@ export class ModelMesh extends Mesh { this._accessible && this._releaseCache(); } - private _updateVertexElements(blendVertexElementChanged: boolean): void { - this._clearVertexElements(); - this._addVertexElement(POSITION_VERTEX_ELEMENT); - - let offset = 12; - let elementCount = 3; - if (this._normals) { - this._addVertexElement(new VertexElement("NORMAL", offset, VertexElementFormat.Vector3, 0)); - offset += 12; - elementCount += 3; - } - if (this._colors) { - this._addVertexElement(new VertexElement("COLOR_0", offset, VertexElementFormat.Vector4, 0)); - offset += 16; - elementCount += 4; - } - if (this._boneWeights) { - this._addVertexElement(new VertexElement("WEIGHTS_0", offset, VertexElementFormat.Vector4, 0)); - offset += 16; - elementCount += 4; - } - if (this._boneIndices) { - this._addVertexElement(new VertexElement("JOINTS_0", offset, VertexElementFormat.UByte4, 0)); - offset += 4; - elementCount += 1; - } - if (this._tangents) { - this._addVertexElement(new VertexElement("TANGENT", offset, VertexElementFormat.Vector4, 0)); - offset += 16; - elementCount += 4; - } - if (this._uv) { - this._addVertexElement(new VertexElement("TEXCOORD_0", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv1) { - this._addVertexElement(new VertexElement("TEXCOORD_1", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv2) { - this._addVertexElement(new VertexElement("TEXCOORD_2", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv3) { - this._addVertexElement(new VertexElement("TEXCOORD_3", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv4) { - this._addVertexElement(new VertexElement("TEXCOORD_4", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv5) { - this._addVertexElement(new VertexElement("TEXCOORD_5", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv6) { - this._addVertexElement(new VertexElement("TEXCOORD_6", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - if (this._uv7) { - this._addVertexElement(new VertexElement("TEXCOORD_7", offset, VertexElementFormat.Vector2, 0)); - offset += 8; - elementCount += 2; - } - this._vertexSlotChanged = false; + private _updateVertexElements(): boolean { + const blendShapeManager = this._blendShapeManager; + const attributeMode = !blendShapeManager._useTextureMode(); - if (blendVertexElementChanged) { - elementCount += this._blendShapeManager._updateVertexElements(this, offset); - } + if (this._vertexSlotChanged || (attributeMode && blendShapeManager._vertexElementsNeedUpdate())) { + let offset = 12; + let elementCount = 3; + this._clearVertexElements(); + this._addVertexElement(POSITION_VERTEX_ELEMENT); - this._elementCount = elementCount; + if (this._normals) { + this._addVertexElement(new VertexElement("NORMAL", offset, VertexElementFormat.Vector3, 0)); + offset += 12; + elementCount += 3; + } + if (this._colors) { + this._addVertexElement(new VertexElement("COLOR_0", offset, VertexElementFormat.Vector4, 0)); + offset += 16; + elementCount += 4; + } + if (this._boneWeights) { + this._addVertexElement(new VertexElement("WEIGHTS_0", offset, VertexElementFormat.Vector4, 0)); + offset += 16; + elementCount += 4; + } + if (this._boneIndices) { + this._addVertexElement(new VertexElement("JOINTS_0", offset, VertexElementFormat.UByte4, 0)); + offset += 4; + elementCount += 1; + } + if (this._tangents) { + this._addVertexElement(new VertexElement("TANGENT", offset, VertexElementFormat.Vector4, 0)); + offset += 16; + elementCount += 4; + } + if (this._uv) { + this._addVertexElement(new VertexElement("TEXCOORD_0", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv1) { + this._addVertexElement(new VertexElement("TEXCOORD_1", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv2) { + this._addVertexElement(new VertexElement("TEXCOORD_2", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv3) { + this._addVertexElement(new VertexElement("TEXCOORD_3", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv4) { + this._addVertexElement(new VertexElement("TEXCOORD_4", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv5) { + this._addVertexElement(new VertexElement("TEXCOORD_5", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv6) { + this._addVertexElement(new VertexElement("TEXCOORD_6", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (this._uv7) { + this._addVertexElement(new VertexElement("TEXCOORD_7", offset, VertexElementFormat.Vector2, 0)); + offset += 8; + elementCount += 2; + } + if (attributeMode) { + blendShapeManager._blendShapeCount > 0 && blendShapeManager._addVertexElements(this); + } + this._vertexSlotChanged = false; + this._vertexStrideFloat = elementCount; + return true; + } + return false; } - private _updateVertices(vertices: Float32Array, blendVerticesUpdate: boolean, force: boolean): void { + private _updateVertices(vertices: Float32Array, force: boolean): void { // prettier-ignore - const { _elementCount,_vertexCount, _positions, _normals, _colors, _vertexChangeFlag, _boneWeights, _boneIndices, _tangents, _uv, _uv1, _uv2, _uv3, _uv4, _uv5, _uv6, _uv7 } = this; + const { _vertexStrideFloat,_vertexCount, _positions, _normals, _colors, _vertexChangeFlag, _boneWeights, _boneIndices, _tangents, _uv, _uv1, _uv2, _uv3, _uv4, _uv5, _uv6, _uv7 } = this; force && (this._vertexChangeFlag = ValueChanged.All); if (_vertexChangeFlag & ValueChanged.Position) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i; + const start = _vertexStrideFloat * i; const position = _positions[i]; vertices[start] = position.x; vertices[start + 1] = position.y; @@ -625,7 +617,7 @@ export class ModelMesh extends Mesh { if (_normals) { if (_vertexChangeFlag & ValueChanged.Normal) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const normal = _normals[i]; if (normal) { vertices[start] = normal.x; @@ -640,7 +632,7 @@ export class ModelMesh extends Mesh { if (_colors) { if (_vertexChangeFlag & ValueChanged.Color) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const color = _colors[i]; if (color) { vertices[start] = color.r; @@ -656,7 +648,7 @@ export class ModelMesh extends Mesh { if (_boneWeights) { if (_vertexChangeFlag & ValueChanged.BoneWeight) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const weight = _boneWeights[i]; if (weight) { vertices[start] = weight.x; @@ -673,7 +665,7 @@ export class ModelMesh extends Mesh { if (_vertexChangeFlag & ValueChanged.BoneIndex) { const { _verticesUint8 } = this; for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const joint = _boneIndices[i]; if (joint) { const internalStart = start * 4; @@ -690,7 +682,7 @@ export class ModelMesh extends Mesh { if (_tangents) { if (_vertexChangeFlag & ValueChanged.Tangent) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const tangent = _tangents[i]; if (tangent) { vertices[start] = tangent.x; @@ -704,7 +696,7 @@ export class ModelMesh extends Mesh { if (_uv) { if (_vertexChangeFlag & ValueChanged.UV) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv[i]; if (uv) { vertices[start] = uv.x; @@ -717,7 +709,7 @@ export class ModelMesh extends Mesh { if (_uv1) { if (_vertexChangeFlag & ValueChanged.UV1) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv1[i]; if (uv) { vertices[start] = uv.x; @@ -730,7 +722,7 @@ export class ModelMesh extends Mesh { if (_uv2) { if (_vertexChangeFlag & ValueChanged.UV2) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv2[i]; if (uv) { vertices[start] = uv.x; @@ -743,7 +735,7 @@ export class ModelMesh extends Mesh { if (_uv3) { if (_vertexChangeFlag & ValueChanged.UV3) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv3[i]; if (uv) { vertices[start] = uv.x; @@ -756,7 +748,7 @@ export class ModelMesh extends Mesh { if (_uv4) { if (_vertexChangeFlag & ValueChanged.UV4) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv4[i]; if (uv) { vertices[start] = uv.x; @@ -769,7 +761,7 @@ export class ModelMesh extends Mesh { if (_uv5) { if (_vertexChangeFlag & ValueChanged.UV5) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv5[i]; if (uv) { vertices[start] = uv.x; @@ -782,7 +774,7 @@ export class ModelMesh extends Mesh { if (_uv6) { if (_vertexChangeFlag & ValueChanged.UV6) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv6[i]; if (uv) { vertices[start] = uv.x; @@ -795,7 +787,7 @@ export class ModelMesh extends Mesh { if (_uv7) { if (_vertexChangeFlag & ValueChanged.UV7) { for (let i = 0; i < _vertexCount; i++) { - const start = _elementCount * i + offset; + const start = _vertexStrideFloat * i + offset; const uv = _uv7[i]; if (uv) { vertices[start] = uv.x; @@ -806,10 +798,6 @@ export class ModelMesh extends Mesh { offset += 2; } this._vertexChangeFlag = 0; - - if (blendVerticesUpdate) { - this._blendShapeManager._updateDataToVertices(vertices, offset, _vertexCount, _elementCount, force); - } } private _releaseCache(): void { diff --git a/packages/core/src/mesh/SkinnedMeshRenderer.ts b/packages/core/src/mesh/SkinnedMeshRenderer.ts index 70421a8e58..3954ec95a8 100644 --- a/packages/core/src/mesh/SkinnedMeshRenderer.ts +++ b/packages/core/src/mesh/SkinnedMeshRenderer.ts @@ -15,17 +15,9 @@ import { Skin } from "./Skin"; * SkinnedMeshRenderer. */ export class SkinnedMeshRenderer extends MeshRenderer { - private static _blendShapeMacro = Shader.getMacroByName("OASIS_BLENDSHAPE"); - private static _blendShapeTextureMacro = Shader.getMacroByName("OASIS_BLENDSHAPE_TEXTURE"); - private static _blendShapeNormalMacro = Shader.getMacroByName("OASIS_BLENDSHAPE_NORMAL"); - private static _blendShapeTangentMacro = Shader.getMacroByName("OASIS_BLENDSHAPE_TANGENT"); - private static _jointCountProperty = Shader.getPropertyByName("u_jointCount"); private static _jointSamplerProperty = Shader.getPropertyByName("u_jointSampler"); private static _jointMatrixProperty = Shader.getPropertyByName("u_jointMatrix"); - private static _blendShapeWeightsProperty = Shader.getPropertyByName("u_blendShapeWeights"); - private static _blendShapeTextureProperty = Shader.getPropertyByName("u_blendShapeTexture"); - private static _blendShapeTextureInfoProperty = Shader.getPropertyByName("u_blendShapeTextureInfo"); private static _maxJoints: number = 0; @@ -44,7 +36,8 @@ export class SkinnedMeshRenderer extends MeshRenderer { /** Whether to use joint texture. Automatically used when the device can't support the maximum number of bones. */ private _useJointTexture: boolean = false; private _skin: Skin; - private _blendShapeWeights: Float32Array; + _blendShapeWeights: Float32Array; + _condensedBlendShapeWeights: Float32Array; /** * The weights of the BlendShapes. @@ -79,34 +72,8 @@ export class SkinnedMeshRenderer extends MeshRenderer { shaderData.setFloatArray(SkinnedMeshRenderer._jointMatrixProperty, this.matrixPalette); } - const blendShapeManager = (this.mesh)._blendShapeManager; - if (blendShapeManager._blendShapeCount > 0) { - shaderData.enableMacro(SkinnedMeshRenderer._blendShapeMacro); - shaderData.enableMacro("OASIS_BLENDSHAPE_COUNT", blendShapeManager._blendShapeCount.toString()); - if (blendShapeManager._useTextureStore()) { - shaderData.enableMacro(SkinnedMeshRenderer._blendShapeTextureMacro); - shaderData.setTexture(SkinnedMeshRenderer._blendShapeTextureProperty, blendShapeManager._dataTexture); - shaderData.setVector3(SkinnedMeshRenderer._blendShapeTextureInfoProperty, blendShapeManager._dataTextureInfo); - } else { - shaderData.disableMacro(SkinnedMeshRenderer._blendShapeTextureMacro); - } - - shaderData.setFloatArray(SkinnedMeshRenderer._blendShapeWeightsProperty, this._blendShapeWeights); - - if (blendShapeManager._useBlendNormal) { - shaderData.enableMacro(SkinnedMeshRenderer._blendShapeNormalMacro); - } else { - shaderData.disableMacro(SkinnedMeshRenderer._blendShapeNormalMacro); - } - if (blendShapeManager._useBlendTangent) { - shaderData.enableMacro(SkinnedMeshRenderer._blendShapeTangentMacro); - } else { - shaderData.disableMacro(SkinnedMeshRenderer._blendShapeTangentMacro); - } - } else { - shaderData.disableMacro(SkinnedMeshRenderer._blendShapeMacro); - shaderData.disableMacro("OASIS_BLENDSHAPE_COUNT"); - } + const mesh = this.mesh; + mesh._blendShapeManager._updateShaderData(shaderData, this); } /** diff --git a/packages/design/package.json b/packages/design/package.json index 68919b6d00..e519651a8b 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -13,6 +13,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.7.0-beta.4" + "@oasis-engine/math": "0.7.0-beta.6" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 4932303682..2a1ce04b40 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "scripts": { "b:types": "tsc" @@ -13,6 +13,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.4" + "@oasis-engine/core": "0.7.0-beta.6" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index 2e44ff4b7c..46b9ca84ce 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "types": "types/index.d.ts", "scripts": { @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.4", - "@oasis-engine/draco": "0.7.0-beta.4", - "@oasis-engine/math": "0.7.0-beta.4", - "@oasis-engine/rhi-webgl": "0.7.0-beta.4" + "@oasis-engine/core": "0.7.0-beta.6", + "@oasis-engine/draco": "0.7.0-beta.6", + "@oasis-engine/math": "0.7.0-beta.6", + "@oasis-engine/rhi-webgl": "0.7.0-beta.6" } } diff --git a/packages/math/package.json b/packages/math/package.json index 463d9d2ebb..30707c9ec6 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index e313ca9ba2..ea346a895f 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "scripts": { "b:types": "tsc" @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.4", - "@oasis-engine/loader": "0.7.0-beta.4", - "@oasis-engine/math": "0.7.0-beta.4", - "@oasis-engine/rhi-webgl": "0.7.0-beta.4" + "@oasis-engine/core": "0.7.0-beta.6", + "@oasis-engine/loader": "0.7.0-beta.6", + "@oasis-engine/math": "0.7.0-beta.6", + "@oasis-engine/rhi-webgl": "0.7.0-beta.6" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index afad790f11..cfd97e4736 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.4", - "oasis-engine": "0.7.0-beta.4" + "@oasis-engine/design": "0.7.0-beta.6", + "oasis-engine": "0.7.0-beta.6" }, "publishConfig": { "access": "public" diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index afb0edbfe3..0aa210d598 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.4", - "oasis-engine": "0.7.0-beta.4" + "@oasis-engine/design": "0.7.0-beta.6", + "oasis-engine": "0.7.0-beta.6" }, "publishConfig": { "access": "public" diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 6ec31dfa66..4d045f6c53 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.7.0-beta.4", + "version": "0.7.0-beta.6", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,10 +14,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.4", - "@oasis-engine/math": "0.7.0-beta.4" + "@oasis-engine/core": "0.7.0-beta.6", + "@oasis-engine/math": "0.7.0-beta.6" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.4" + "@oasis-engine/design": "0.7.0-beta.6" } } diff --git a/packages/rhi-webgl/src/GLPrimitive.ts b/packages/rhi-webgl/src/GLPrimitive.ts index d7eb3aef93..2212723dd3 100644 --- a/packages/rhi-webgl/src/GLPrimitive.ts +++ b/packages/rhi-webgl/src/GLPrimitive.ts @@ -14,7 +14,7 @@ import { WebGLRenderer } from "./WebGLRenderer"; * GL platform primitive. */ export class GLPrimitive implements IPlatformPrimitive { - protected attribLocArray: number[]; + protected attribLocArray: number[] = []; protected readonly _primitive: Mesh; protected readonly canUseInstancedArrays: boolean; @@ -35,8 +35,10 @@ export class GLPrimitive implements IPlatformPrimitive { draw(shaderProgram: any, subMesh: SubMesh): void { const gl = this.gl; const primitive = this._primitive; + // @ts-ignore + const useVao = this._useVao && primitive._enableVAO; - if (this._useVao) { + if (useVao) { if (!this.vao.has(shaderProgram.id)) { this.registerVAO(shaderProgram); } @@ -52,7 +54,7 @@ export class GLPrimitive implements IPlatformPrimitive { if (!_instanceCount) { if (_indexBufferBinding) { - if (this._useVao) { + if (useVao) { gl.drawElements(topology, count, _glIndexType, start * _glIndexByteCount); } else { const { _nativeBuffer } = _indexBufferBinding.buffer; @@ -109,7 +111,7 @@ export class GLPrimitive implements IPlatformPrimitive { // @ts-ignore const vertexBufferBindings = primitive._vertexBufferBindings; - this.attribLocArray = []; + this.attribLocArray.length = 0; const attributeLocation = shaderProgram.attributeLocation; const attributes = primitive._vertexElementMap; @@ -131,8 +133,8 @@ export class GLPrimitive implements IPlatformPrimitive { } gl.enableVertexAttribArray(loc); - const { size, type, normalized } = element._glElementInfo; - gl.vertexAttribPointer(loc, size, type, normalized, stride, element.offset); + const elementInfo = element._glElementInfo; + gl.vertexAttribPointer(loc, elementInfo.size, elementInfo.type, elementInfo.normalized, stride, element.offset); if (this.canUseInstancedArrays) { gl.vertexAttribDivisor(loc, element.instanceStepRate); } From 5e04b33bac1ede6afea1336671549c0566ec977f Mon Sep 17 00:00:00 2001 From: zhuxudong Date: Fri, 10 Jun 2022 16:57:46 +0800 Subject: [PATCH 13/33] refactor: rename (#827) --- packages/core/src/material/BaseMaterial.ts | 13 +++++++- .../core/src/material/BlinnPhongMaterial.ts | 26 +++++---------- packages/core/src/material/PBRBaseMaterial.ts | 33 ++++++++----------- packages/core/src/material/PBRMaterial.ts | 10 +++--- .../core/src/material/PBRSpecularMaterial.ts | 10 +++--- packages/core/src/material/UnlitMaterial.ts | 8 ++--- .../core/src/shaderlib/begin_mobile_frag.glsl | 8 ++--- .../core/src/shaderlib/blendShape_vert.glsl | 4 +-- .../core/src/shaderlib/extra/unlit.fs.glsl | 4 +-- .../src/shaderlib/mobile_blinnphong_frag.glsl | 2 +- .../src/shaderlib/mobile_material_frag.glsl | 10 +++--- packages/core/src/shaderlib/normal_get.glsl | 2 +- packages/core/src/shaderlib/normal_share.glsl | 2 +- packages/core/src/shaderlib/normal_vert.glsl | 2 +- packages/core/src/shaderlib/pbr/pbr_frag.glsl | 8 ++--- .../src/shaderlib/pbr/pbr_frag_define.glsl | 26 +++++++-------- .../core/src/shaderlib/pbr/pbr_helper.glsl | 18 +++++----- .../core/src/shaderlib/skinning_vert.glsl | 2 +- 18 files changed, 91 insertions(+), 97 deletions(-) diff --git a/packages/core/src/material/BaseMaterial.ts b/packages/core/src/material/BaseMaterial.ts index b993f384f8..8f22922e8f 100644 --- a/packages/core/src/material/BaseMaterial.ts +++ b/packages/core/src/material/BaseMaterial.ts @@ -7,8 +7,19 @@ import { RenderQueueType } from "./enums/RenderQueueType"; import { Material } from "./Material"; export class BaseMaterial extends Material { - private static _alphaCutoffMacro: ShaderMacro = Shader.getMacroByName("ALPHA_CUTOFF"); + protected static _baseColorProp = Shader.getPropertyByName("u_baseColor"); + protected static _baseTextureProp = Shader.getPropertyByName("u_baseTexture"); + protected static _baseTextureMacro: ShaderMacro = Shader.getMacroByName("BASETEXTURE"); + protected static _tilingOffsetProp = Shader.getPropertyByName("u_tilingOffset"); + protected static _normalTextureProp = Shader.getPropertyByName("u_normalTexture"); + protected static _normalIntensityProp = Shader.getPropertyByName("u_normalIntensity"); + protected static _normalTextureMacro: ShaderMacro = Shader.getMacroByName("NORMALTEXTURE"); + protected static _emissiveColorProp = Shader.getPropertyByName("u_emissiveColor"); + protected static _emissiveTextureProp = Shader.getPropertyByName("u_emissiveTexture"); + protected static _emissiveTextureMacro: ShaderMacro = Shader.getMacroByName("EMISSIVETEXTURE"); + private static _alphaCutoffProp = Shader.getPropertyByName("u_alphaCutoff"); + private static _alphaCutoffMacro: ShaderMacro = Shader.getMacroByName("ALPHA_CUTOFF"); private _renderFace: RenderFace = RenderFace.Front; private _isTransparent: boolean = false; diff --git a/packages/core/src/material/BlinnPhongMaterial.ts b/packages/core/src/material/BlinnPhongMaterial.ts index 80c423cf92..8b9cb34f62 100644 --- a/packages/core/src/material/BlinnPhongMaterial.ts +++ b/packages/core/src/material/BlinnPhongMaterial.ts @@ -8,27 +8,19 @@ import { BaseMaterial } from "./BaseMaterial"; * Blinn-phong Material. */ export class BlinnPhongMaterial extends BaseMaterial { - private static _diffuseColorProp = Shader.getPropertyByName("u_diffuseColor"); private static _specularColorProp = Shader.getPropertyByName("u_specularColor"); - private static _emissiveColorProp = Shader.getPropertyByName("u_emissiveColor"); - private static _tilingOffsetProp = Shader.getPropertyByName("u_tilingOffset"); private static _shininessProp = Shader.getPropertyByName("u_shininess"); - private static _normalIntensityProp = Shader.getPropertyByName("u_normalIntensity"); - - private static _baseTextureProp = Shader.getPropertyByName("u_diffuseTexture"); private static _specularTextureProp = Shader.getPropertyByName("u_specularTexture"); - private static _emissiveTextureProp = Shader.getPropertyByName("u_emissiveTexture"); - private static _normalTextureProp = Shader.getPropertyByName("u_normalTexture"); /** * Base color. */ get baseColor(): Color { - return this.shaderData.getColor(BlinnPhongMaterial._diffuseColorProp); + return this.shaderData.getColor(BlinnPhongMaterial._baseColorProp); } set baseColor(value: Color) { - const baseColor = this.shaderData.getColor(BlinnPhongMaterial._diffuseColorProp); + const baseColor = this.shaderData.getColor(BlinnPhongMaterial._baseColorProp); if (value !== baseColor) { value.cloneTo(baseColor); } @@ -44,9 +36,9 @@ export class BlinnPhongMaterial extends BaseMaterial { set baseTexture(value: Texture2D) { this.shaderData.setTexture(BlinnPhongMaterial._baseTextureProp, value); if (value) { - this.shaderData.enableMacro("O3_DIFFUSE_TEXTURE"); + this.shaderData.enableMacro(BlinnPhongMaterial._baseTextureMacro); } else { - this.shaderData.disableMacro("O3_DIFFUSE_TEXTURE"); + this.shaderData.disableMacro(BlinnPhongMaterial._baseTextureMacro); } } @@ -104,9 +96,9 @@ export class BlinnPhongMaterial extends BaseMaterial { set emissiveTexture(value: Texture2D) { this.shaderData.setTexture(BlinnPhongMaterial._emissiveTextureProp, value); if (value) { - this.shaderData.enableMacro("O3_EMISSIVE_TEXTURE"); + this.shaderData.enableMacro(BlinnPhongMaterial._emissiveTextureMacro); } else { - this.shaderData.disableMacro("O3_EMISSIVE_TEXTURE"); + this.shaderData.disableMacro(BlinnPhongMaterial._emissiveTextureMacro); } } @@ -120,9 +112,9 @@ export class BlinnPhongMaterial extends BaseMaterial { set normalTexture(value: Texture2D) { this.shaderData.setTexture(BlinnPhongMaterial._normalTextureProp, value); if (value) { - this.shaderData.enableMacro("O3_NORMAL_TEXTURE"); + this.shaderData.enableMacro(BlinnPhongMaterial._normalTextureMacro); } else { - this.shaderData.disableMacro("O3_NORMAL_TEXTURE"); + this.shaderData.disableMacro(BlinnPhongMaterial._normalTextureMacro); } } @@ -170,7 +162,7 @@ export class BlinnPhongMaterial extends BaseMaterial { shaderData.enableMacro("O3_NEED_WORLDPOS"); shaderData.enableMacro("O3_NEED_TILINGOFFSET"); - shaderData.setColor(BlinnPhongMaterial._diffuseColorProp, new Color(1, 1, 1, 1)); + shaderData.setColor(BlinnPhongMaterial._baseColorProp, new Color(1, 1, 1, 1)); shaderData.setColor(BlinnPhongMaterial._specularColorProp, new Color(1, 1, 1, 1)); shaderData.setColor(BlinnPhongMaterial._emissiveColorProp, new Color(0, 0, 0, 1)); shaderData.setVector4(BlinnPhongMaterial._tilingOffsetProp, new Vector4(1, 1, 0, 0)); diff --git a/packages/core/src/material/PBRBaseMaterial.ts b/packages/core/src/material/PBRBaseMaterial.ts index c677160564..0dddcc2d08 100644 --- a/packages/core/src/material/PBRBaseMaterial.ts +++ b/packages/core/src/material/PBRBaseMaterial.ts @@ -10,16 +10,9 @@ import { TextureCoordinate } from "./enums/TextureCoordinate"; * PBR (Physically-Based Rendering) Material. */ export abstract class PBRBaseMaterial extends BaseMaterial { - private static _baseColorProp = Shader.getPropertyByName("u_baseColor"); - private static _emissiveColorProp = Shader.getPropertyByName("u_emissiveColor"); - private static _tilingOffsetProp = Shader.getPropertyByName("u_tilingOffset"); - private static _baseTextureProp = Shader.getPropertyByName("u_baseColorSampler"); - private static _normalTextureProp = Shader.getPropertyByName("u_normalTexture"); - private static _normalTextureIntensityProp = Shader.getPropertyByName("u_normalIntensity"); - private static _occlusionTextureIntensityProp = Shader.getPropertyByName("u_occlusionStrength"); + private static _occlusionTextureIntensityProp = Shader.getPropertyByName("u_occlusionIntensity"); private static _occlusionTextureCoordProp = Shader.getPropertyByName("u_occlusionTextureCoord"); - private static _emissiveTextureProp = Shader.getPropertyByName("u_emissiveSampler"); - private static _occlusionTextureProp = Shader.getPropertyByName("u_occlusionSampler"); + private static _occlusionTextureProp = Shader.getPropertyByName("u_occlusionTexture"); private static _clearCoatProp = Shader.getPropertyByName("u_clearCoat"); private static _clearCoatTextureProp = Shader.getPropertyByName("u_clearCoatTexture"); @@ -51,9 +44,9 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set baseTexture(value: Texture2D) { this.shaderData.setTexture(PBRBaseMaterial._baseTextureProp, value); if (value) { - this.shaderData.enableMacro("HAS_BASECOLORMAP"); + this.shaderData.enableMacro(PBRBaseMaterial._baseTextureMacro); } else { - this.shaderData.disableMacro("HAS_BASECOLORMAP"); + this.shaderData.disableMacro(PBRBaseMaterial._baseTextureMacro); } } @@ -67,9 +60,9 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set normalTexture(value: Texture2D) { this.shaderData.setTexture(PBRBaseMaterial._normalTextureProp, value); if (value) { - this.shaderData.enableMacro("O3_NORMAL_TEXTURE"); + this.shaderData.enableMacro(PBRBaseMaterial._normalTextureMacro); } else { - this.shaderData.disableMacro("O3_NORMAL_TEXTURE"); + this.shaderData.disableMacro(PBRBaseMaterial._normalTextureMacro); } } @@ -77,11 +70,11 @@ export abstract class PBRBaseMaterial extends BaseMaterial { * Normal texture intensity. */ get normalTextureIntensity(): number { - return this.shaderData.getFloat(PBRBaseMaterial._normalTextureIntensityProp); + return this.shaderData.getFloat(PBRBaseMaterial._normalIntensityProp); } set normalTextureIntensity(value: number) { - this.shaderData.setFloat(PBRBaseMaterial._normalTextureIntensityProp, value); + this.shaderData.setFloat(PBRBaseMaterial._normalIntensityProp, value); } /** @@ -108,9 +101,9 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set emissiveTexture(value: Texture2D) { this.shaderData.setTexture(PBRBaseMaterial._emissiveTextureProp, value); if (value) { - this.shaderData.enableMacro("HAS_EMISSIVEMAP"); + this.shaderData.enableMacro(PBRBaseMaterial._emissiveTextureMacro); } else { - this.shaderData.disableMacro("HAS_EMISSIVEMAP"); + this.shaderData.disableMacro(PBRBaseMaterial._emissiveTextureMacro); } } @@ -124,9 +117,9 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set occlusionTexture(value: Texture2D) { this.shaderData.setTexture(PBRBaseMaterial._occlusionTextureProp, value); if (value) { - this.shaderData.enableMacro("HAS_OCCLUSIONMAP"); + this.shaderData.enableMacro("OCCLUSIONTEXTURE"); } else { - this.shaderData.disableMacro("HAS_OCCLUSIONMAP"); + this.shaderData.disableMacro("OCCLUSIONTEXTURE"); } } @@ -267,7 +260,7 @@ export abstract class PBRBaseMaterial extends BaseMaterial { shaderData.setColor(PBRBaseMaterial._emissiveColorProp, new Color(0, 0, 0, 1)); shaderData.setVector4(PBRBaseMaterial._tilingOffsetProp, new Vector4(1, 1, 0, 0)); - shaderData.setFloat(PBRBaseMaterial._normalTextureIntensityProp, 1); + shaderData.setFloat(PBRBaseMaterial._normalIntensityProp, 1); shaderData.setFloat(PBRBaseMaterial._occlusionTextureIntensityProp, 1); shaderData.setFloat(PBRBaseMaterial._occlusionTextureCoordProp, TextureCoordinate.UV0); diff --git a/packages/core/src/material/PBRMaterial.ts b/packages/core/src/material/PBRMaterial.ts index 56666318e8..8ebe15762c 100644 --- a/packages/core/src/material/PBRMaterial.ts +++ b/packages/core/src/material/PBRMaterial.ts @@ -9,7 +9,7 @@ import { PBRBaseMaterial } from "./PBRBaseMaterial"; export class PBRMaterial extends PBRBaseMaterial { private static _metallicProp = Shader.getPropertyByName("u_metal"); private static _roughnessProp = Shader.getPropertyByName("u_roughness"); - private static _metallicRoughnessTextureProp = Shader.getPropertyByName("u_metallicRoughnessSampler"); + private static _roughnessMetallicTextureProp = Shader.getPropertyByName("u_roughnessMetallicTexture"); /** * Metallic, default 1.0. @@ -38,15 +38,15 @@ export class PBRMaterial extends PBRBaseMaterial { * @remarks G channel is roughness, B channel is metallic */ get roughnessMetallicTexture(): Texture2D { - return this.shaderData.getTexture(PBRMaterial._metallicRoughnessTextureProp); + return this.shaderData.getTexture(PBRMaterial._roughnessMetallicTextureProp); } set roughnessMetallicTexture(value: Texture2D) { - this.shaderData.setTexture(PBRMaterial._metallicRoughnessTextureProp, value); + this.shaderData.setTexture(PBRMaterial._roughnessMetallicTextureProp, value); if (value) { - this.shaderData.enableMacro("HAS_METALROUGHNESSMAP"); + this.shaderData.enableMacro("ROUGHNESSMETALLICTEXTURE"); } else { - this.shaderData.disableMacro("HAS_METALROUGHNESSMAP"); + this.shaderData.disableMacro("ROUGHNESSMETALLICTEXTURE"); } } diff --git a/packages/core/src/material/PBRSpecularMaterial.ts b/packages/core/src/material/PBRSpecularMaterial.ts index 6f17babb73..d4b0300fa5 100644 --- a/packages/core/src/material/PBRSpecularMaterial.ts +++ b/packages/core/src/material/PBRSpecularMaterial.ts @@ -1,6 +1,7 @@ import { Color } from "@oasis-engine/math"; import { Engine } from "../Engine"; import { Shader } from "../shader/Shader"; +import { ShaderMacro } from "../shader/ShaderMacro"; import { Texture2D } from "../texture/Texture2D"; import { PBRBaseMaterial } from "./PBRBaseMaterial"; @@ -8,9 +9,10 @@ import { PBRBaseMaterial } from "./PBRBaseMaterial"; * PBR (Specular-Glossiness Workflow) Material. */ export class PBRSpecularMaterial extends PBRBaseMaterial { - private static _specularColorProp = Shader.getPropertyByName("u_specularColor"); + private static _specularColorProp = Shader.getPropertyByName("u_PBRSpecularColor"); private static _glossinessProp = Shader.getPropertyByName("u_glossiness"); - private static _specularGlossinessTextureProp = Shader.getPropertyByName("u_specularGlossinessSampler"); + private static _specularGlossinessTextureProp = Shader.getPropertyByName("u_specularGlossinessTexture"); + private static _specularGlossinessTextureMacro: ShaderMacro = Shader.getMacroByName("SPECULARGLOSSINESSTEXTURE"); /** * Specular color. @@ -48,9 +50,9 @@ export class PBRSpecularMaterial extends PBRBaseMaterial { set specularGlossinessTexture(value: Texture2D) { this.shaderData.setTexture(PBRSpecularMaterial._specularGlossinessTextureProp, value); if (value) { - this.shaderData.enableMacro("HAS_SPECULARGLOSSINESSMAP"); + this.shaderData.enableMacro(PBRSpecularMaterial._specularGlossinessTextureMacro); } else { - this.shaderData.disableMacro("HAS_SPECULARGLOSSINESSMAP"); + this.shaderData.disableMacro(PBRSpecularMaterial._specularGlossinessTextureMacro); } } diff --git a/packages/core/src/material/UnlitMaterial.ts b/packages/core/src/material/UnlitMaterial.ts index 1d5a764be8..c74334033b 100644 --- a/packages/core/src/material/UnlitMaterial.ts +++ b/packages/core/src/material/UnlitMaterial.ts @@ -8,10 +8,6 @@ import { BaseMaterial } from "./BaseMaterial"; * Unlit Material. */ export class UnlitMaterial extends BaseMaterial { - private static _baseColorProp = Shader.getPropertyByName("u_baseColor"); - private static _baseTextureProp = Shader.getPropertyByName("u_baseTexture"); - private static _tilingOffsetProp = Shader.getPropertyByName("u_tilingOffset"); - /** * Base color. */ @@ -36,9 +32,9 @@ export class UnlitMaterial extends BaseMaterial { set baseTexture(value: Texture2D) { this.shaderData.setTexture(UnlitMaterial._baseTextureProp, value); if (value) { - this.shaderData.enableMacro("O3_BASE_TEXTURE"); + this.shaderData.enableMacro(UnlitMaterial._baseTextureMacro); } else { - this.shaderData.disableMacro("O3_BASE_TEXTURE"); + this.shaderData.disableMacro(UnlitMaterial._baseTextureMacro); } } diff --git a/packages/core/src/shaderlib/begin_mobile_frag.glsl b/packages/core/src/shaderlib/begin_mobile_frag.glsl index ba9742a5f9..63c76b54e1 100644 --- a/packages/core/src/shaderlib/begin_mobile_frag.glsl +++ b/packages/core/src/shaderlib/begin_mobile_frag.glsl @@ -1,11 +1,11 @@ vec4 ambient = vec4(0.0); vec4 emission = u_emissiveColor; - vec4 diffuse = u_diffuseColor; + vec4 diffuse = u_baseColor; vec4 specular = u_specularColor; - #ifdef O3_EMISSIVE_TEXTURE + #ifdef EMISSIVETEXTURE vec4 emissiveTextureColor = texture2D(u_emissiveTexture, v_uv); #ifndef OASIS_COLORSPACE_GAMMA emissiveTextureColor = gammaToLinear(emissiveTextureColor); @@ -14,8 +14,8 @@ #endif - #ifdef O3_DIFFUSE_TEXTURE - vec4 diffuseTextureColor = texture2D(u_diffuseTexture, v_uv); + #ifdef BASETEXTURE + vec4 diffuseTextureColor = texture2D(u_baseTexture, v_uv); #ifndef OASIS_COLORSPACE_GAMMA diffuseTextureColor = gammaToLinear(diffuseTextureColor); #endif diff --git a/packages/core/src/shaderlib/blendShape_vert.glsl b/packages/core/src/shaderlib/blendShape_vert.glsl index 56830e882a..d284c4d30c 100644 --- a/packages/core/src/shaderlib/blendShape_vert.glsl +++ b/packages/core/src/shaderlib/blendShape_vert.glsl @@ -12,7 +12,7 @@ normal += getBlendShapeVertexElement(i, vertexElementOffset) * weight; #endif - #if defined( O3_HAS_TANGENT ) && defined(OASIS_BLENDSHAPE_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + #if defined( O3_HAS_TANGENT ) && defined(OASIS_BLENDSHAPE_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) vertexElementOffset += 1; tangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight; #endif @@ -33,7 +33,7 @@ normal += NORMAL_BS3 * u_blendShapeWeights[3]; #endif - #if defined( O3_HAS_TANGENT ) && defined(OASIS_BLENDSHAPE_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + #if defined( O3_HAS_TANGENT ) && defined(OASIS_BLENDSHAPE_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) tangent.xyz += TANGENT_BS0 * u_blendShapeWeights[0]; tangent.xyz += TANGENT_BS1 * u_blendShapeWeights[1]; tangent.xyz += TANGENT_BS2 * u_blendShapeWeights[2]; diff --git a/packages/core/src/shaderlib/extra/unlit.fs.glsl b/packages/core/src/shaderlib/extra/unlit.fs.glsl index 4bb203a846..a354ec5867 100644 --- a/packages/core/src/shaderlib/extra/unlit.fs.glsl +++ b/packages/core/src/shaderlib/extra/unlit.fs.glsl @@ -5,14 +5,14 @@ uniform vec4 u_baseColor; uniform float u_alphaCutoff; -#ifdef O3_BASE_TEXTURE +#ifdef BASETEXTURE uniform sampler2D u_baseTexture; #endif void main() { vec4 baseColor = u_baseColor; - #ifdef O3_BASE_TEXTURE + #ifdef BASETEXTURE vec4 textureColor = texture2D(u_baseTexture, v_uv); #ifndef OASIS_COLORSPACE_GAMMA textureColor = gammaToLinear(textureColor); diff --git a/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl b/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl index 0beae8db71..1b8f2d03dd 100644 --- a/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl +++ b/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl @@ -1,4 +1,4 @@ - #ifdef O3_NORMAL_TEXTURE + #ifdef NORMALTEXTURE mat3 tbn = getTBN(); vec3 N = getNormalByNormalTexture(tbn, u_normalTexture, u_normalIntensity, v_uv); #else diff --git a/packages/core/src/shaderlib/mobile_material_frag.glsl b/packages/core/src/shaderlib/mobile_material_frag.glsl index cfdff13c45..a40333791f 100644 --- a/packages/core/src/shaderlib/mobile_material_frag.glsl +++ b/packages/core/src/shaderlib/mobile_material_frag.glsl @@ -1,22 +1,22 @@ uniform vec4 u_emissiveColor; -uniform vec4 u_diffuseColor; +uniform vec4 u_baseColor; uniform vec4 u_specularColor; uniform float u_shininess; uniform float u_normalIntensity; uniform float u_alphaCutoff; -#ifdef O3_EMISSIVE_TEXTURE +#ifdef EMISSIVETEXTURE uniform sampler2D u_emissiveTexture; #endif -#ifdef O3_DIFFUSE_TEXTURE - uniform sampler2D u_diffuseTexture; +#ifdef BASETEXTURE + uniform sampler2D u_baseTexture; #endif #ifdef O3_SPECULAR_TEXTURE uniform sampler2D u_specularTexture; #endif -#ifdef O3_NORMAL_TEXTURE +#ifdef NORMALTEXTURE uniform sampler2D u_normalTexture; #endif diff --git a/packages/core/src/shaderlib/normal_get.glsl b/packages/core/src/shaderlib/normal_get.glsl index acff61dd3f..e7bf556813 100644 --- a/packages/core/src/shaderlib/normal_get.glsl +++ b/packages/core/src/shaderlib/normal_get.glsl @@ -22,7 +22,7 @@ vec3 getNormalByNormalTexture(mat3 tbn, sampler2D normalTexture, float normalInt } mat3 getTBN(){ - #if defined(O3_HAS_NORMAL) && defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + #if defined(O3_HAS_NORMAL) && defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) mat3 tbn = v_TBN; #else vec3 normal = getNormal(); diff --git a/packages/core/src/shaderlib/normal_share.glsl b/packages/core/src/shaderlib/normal_share.glsl index fa03d27571..4a936679eb 100644 --- a/packages/core/src/shaderlib/normal_share.glsl +++ b/packages/core/src/shaderlib/normal_share.glsl @@ -1,7 +1,7 @@ #ifndef OMIT_NORMAL #ifdef O3_HAS_NORMAL varying vec3 v_normal; - #if defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + #if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) varying mat3 v_TBN; #endif #endif diff --git a/packages/core/src/shaderlib/normal_vert.glsl b/packages/core/src/shaderlib/normal_vert.glsl index 9c44a0b3a6..5bf97c295c 100644 --- a/packages/core/src/shaderlib/normal_vert.glsl +++ b/packages/core/src/shaderlib/normal_vert.glsl @@ -2,7 +2,7 @@ #ifdef O3_HAS_NORMAL v_normal = normalize( mat3(u_normalMat) * normal ); - #if defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + #if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) vec3 normalW = normalize( mat3(u_normalMat) * normal.xyz ); vec3 tangentW = normalize( mat3(u_normalMat) * tangent.xyz ); vec3 bitangentW = cross( normalW, tangentW ) * tangent.w; diff --git a/packages/core/src/shaderlib/pbr/pbr_frag.glsl b/packages/core/src/shaderlib/pbr/pbr_frag.glsl index 8652fdad42..996f110f2f 100644 --- a/packages/core/src/shaderlib/pbr/pbr_frag.glsl +++ b/packages/core/src/shaderlib/pbr/pbr_frag.glsl @@ -37,14 +37,14 @@ reflectedLight.indirectSpecular += radianceAttenuation * radiance * envBRDFAppro // Occlusion -#ifdef HAS_OCCLUSIONMAP +#ifdef OCCLUSIONTEXTURE vec2 aoUV = v_uv; #ifdef O3_HAS_UV1 if(u_occlusionTextureCoord == 1.0){ aoUV = v_uv1; } #endif - float ambientOcclusion = (texture2D(u_occlusionSampler, aoUV).r - 1.0) * u_occlusionStrength + 1.0; + float ambientOcclusion = (texture2D(u_occlusionTexture, aoUV).r - 1.0) * u_occlusionIntensity + 1.0; reflectedLight.indirectDiffuse *= ambientOcclusion; #ifdef O3_USE_SPECULAR_ENV reflectedLight.indirectSpecular *= computeSpecularOcclusion(ambientOcclusion, material.roughness, geometry.dotNV); @@ -54,8 +54,8 @@ reflectedLight.indirectSpecular += radianceAttenuation * radiance * envBRDFAppro // Emissive vec3 emissiveRadiance = u_emissiveColor; -#ifdef HAS_EMISSIVEMAP - vec4 emissiveColor = texture2D(u_emissiveSampler, v_uv); +#ifdef EMISSIVETEXTURE + vec4 emissiveColor = texture2D(u_emissiveTexture, v_uv); #ifndef OASIS_COLORSPACE_GAMMA emissiveColor = gammaToLinear(emissiveColor); #endif diff --git a/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl b/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl index 928735fe78..bc7a29f6c4 100644 --- a/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl +++ b/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl @@ -2,7 +2,7 @@ uniform float u_alphaCutoff; uniform vec4 u_baseColor; uniform float u_metal; uniform float u_roughness; -uniform vec3 u_specularColor; +uniform vec3 u_PBRSpecularColor; uniform float u_glossiness; uniform vec3 u_emissiveColor; @@ -12,33 +12,33 @@ uniform vec3 u_emissiveColor; #endif uniform float u_normalIntensity; -uniform float u_occlusionStrength; +uniform float u_occlusionIntensity; uniform float u_occlusionTextureCoord; // Texture -#ifdef HAS_BASECOLORMAP - uniform sampler2D u_baseColorSampler; +#ifdef BASETEXTURE + uniform sampler2D u_baseTexture; #endif -#ifdef O3_NORMAL_TEXTURE +#ifdef NORMALTEXTURE uniform sampler2D u_normalTexture; #endif -#ifdef HAS_EMISSIVEMAP - uniform sampler2D u_emissiveSampler; +#ifdef EMISSIVETEXTURE + uniform sampler2D u_emissiveTexture; #endif -#ifdef HAS_METALROUGHNESSMAP - uniform sampler2D u_metallicRoughnessSampler; +#ifdef ROUGHNESSMETALLICTEXTURE + uniform sampler2D u_roughnessMetallicTexture; #endif -#ifdef HAS_SPECULARGLOSSINESSMAP - uniform sampler2D u_specularGlossinessSampler; +#ifdef SPECULARGLOSSINESSTEXTURE + uniform sampler2D u_specularGlossinessTexture; #endif -#ifdef HAS_OCCLUSIONMAP - uniform sampler2D u_occlusionSampler; +#ifdef OCCLUSIONTEXTURE + uniform sampler2D u_occlusionTexture; #endif #ifdef HAS_CLEARCOATTEXTURE diff --git a/packages/core/src/shaderlib/pbr/pbr_helper.glsl b/packages/core/src/shaderlib/pbr/pbr_helper.glsl index 8294a21350..f46910c1c4 100644 --- a/packages/core/src/shaderlib/pbr/pbr_helper.glsl +++ b/packages/core/src/shaderlib/pbr/pbr_helper.glsl @@ -21,11 +21,11 @@ void initGeometry(out Geometry geometry){ geometry.position = v_pos; geometry.viewDir = normalize(u_cameraPos - v_pos); - #if defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) + #if defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) mat3 tbn = getTBN(); #endif - #ifdef O3_NORMAL_TEXTURE + #ifdef NORMALTEXTURE geometry.normal = getNormalByNormalTexture(tbn, u_normalTexture, u_normalIntensity, v_uv); #else geometry.normal = getNormal(); @@ -49,12 +49,12 @@ void initMaterial(out Material material, const in Geometry geometry){ vec4 baseColor = u_baseColor; float metal = u_metal; float roughness = u_roughness; - vec3 specularColor = u_specularColor; + vec3 specularColor = u_PBRSpecularColor; float glossiness = u_glossiness; float alphaCutoff = u_alphaCutoff; - #ifdef HAS_BASECOLORMAP - vec4 baseTextureColor = texture2D(u_baseColorSampler, v_uv); + #ifdef BASETEXTURE + vec4 baseTextureColor = texture2D(u_baseTexture, v_uv); #ifndef OASIS_COLORSPACE_GAMMA baseTextureColor = gammaToLinear(baseTextureColor); #endif @@ -72,14 +72,14 @@ void initMaterial(out Material material, const in Geometry geometry){ } #endif - #ifdef HAS_METALROUGHNESSMAP - vec4 metalRoughMapColor = texture2D( u_metallicRoughnessSampler, v_uv ); + #ifdef ROUGHNESSMETALLICTEXTURE + vec4 metalRoughMapColor = texture2D( u_roughnessMetallicTexture, v_uv ); roughness *= metalRoughMapColor.g; metal *= metalRoughMapColor.b; #endif - #ifdef HAS_SPECULARGLOSSINESSMAP - vec4 specularGlossinessColor = texture2D(u_specularGlossinessSampler, v_uv ); + #ifdef SPECULARGLOSSINESSTEXTURE + vec4 specularGlossinessColor = texture2D(u_specularGlossinessTexture, v_uv ); #ifndef OASIS_COLORSPACE_GAMMA specularGlossinessColor = gammaToLinear(specularGlossinessColor); #endif diff --git a/packages/core/src/shaderlib/skinning_vert.glsl b/packages/core/src/shaderlib/skinning_vert.glsl index b0eba9a14e..73d37481da 100644 --- a/packages/core/src/shaderlib/skinning_vert.glsl +++ b/packages/core/src/shaderlib/skinning_vert.glsl @@ -19,7 +19,7 @@ #if defined(O3_HAS_NORMAL) && !defined(OMIT_NORMAL) normal = vec4( skinMatrix * vec4( normal, 0.0 ) ).xyz; - #if defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + #if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) tangent.xyz = vec4( skinMatrix * vec4( tangent.xyz, 0.0 ) ).xyz; #endif From 2327b4662119643760befd3227216d0d59f27c5b Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Fri, 10 Jun 2022 17:07:30 +0800 Subject: [PATCH 14/33] v0.7.0-beta.7 --- lerna.json | 2 +- packages/controls/package.json | 4 ++-- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/framebuffer-picker/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- packages/stats/package.json | 4 ++-- 13 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lerna.json b/lerna.json index 0d197fb15e..1d25f14a61 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "bootstrap": { "hoist": true }, diff --git a/packages/controls/package.json b/packages/controls/package.json index adff935ff3..bae173537f 100644 --- a/packages/controls/package.json +++ b/packages/controls/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/controls", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "scripts": { "b:types": "tsc", @@ -15,6 +15,6 @@ "types/**/*" ], "dependencies": { - "oasis-engine": "0.7.0-beta.6" + "oasis-engine": "0.7.0-beta.7" } } diff --git a/packages/core/package.json b/packages/core/package.json index f10f2df357..dc24d391d2 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.7.0-beta.6" + "@oasis-engine/math": "0.7.0-beta.7" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.6" + "@oasis-engine/design": "0.7.0-beta.7" } } diff --git a/packages/design/package.json b/packages/design/package.json index e519651a8b..5e8250b3db 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -13,6 +13,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.7.0-beta.6" + "@oasis-engine/math": "0.7.0-beta.7" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 2a1ce04b40..8fd5741a1a 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "scripts": { "b:types": "tsc" @@ -13,6 +13,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.6" + "@oasis-engine/core": "0.7.0-beta.7" } } diff --git a/packages/framebuffer-picker/package.json b/packages/framebuffer-picker/package.json index 83315084ee..299b5c99c8 100755 --- a/packages/framebuffer-picker/package.json +++ b/packages/framebuffer-picker/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/framebuffer-picker", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,6 +14,6 @@ "types/**/*" ], "dependencies": { - "oasis-engine": "0.7.0-beta.6" + "oasis-engine": "0.7.0-beta.7" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index 46b9ca84ce..165fe4027d 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "types": "types/index.d.ts", "scripts": { @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.6", - "@oasis-engine/draco": "0.7.0-beta.6", - "@oasis-engine/math": "0.7.0-beta.6", - "@oasis-engine/rhi-webgl": "0.7.0-beta.6" + "@oasis-engine/core": "0.7.0-beta.7", + "@oasis-engine/draco": "0.7.0-beta.7", + "@oasis-engine/math": "0.7.0-beta.7", + "@oasis-engine/rhi-webgl": "0.7.0-beta.7" } } diff --git a/packages/math/package.json b/packages/math/package.json index 30707c9ec6..404408608c 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index ea346a895f..04b1aa8ef5 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "scripts": { "b:types": "tsc" @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.6", - "@oasis-engine/loader": "0.7.0-beta.6", - "@oasis-engine/math": "0.7.0-beta.6", - "@oasis-engine/rhi-webgl": "0.7.0-beta.6" + "@oasis-engine/core": "0.7.0-beta.7", + "@oasis-engine/loader": "0.7.0-beta.7", + "@oasis-engine/math": "0.7.0-beta.7", + "@oasis-engine/rhi-webgl": "0.7.0-beta.7" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index cfd97e4736..b396b25001 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.6", - "oasis-engine": "0.7.0-beta.6" + "@oasis-engine/design": "0.7.0-beta.7", + "oasis-engine": "0.7.0-beta.7" }, "publishConfig": { "access": "public" diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 0aa210d598..8d1d571ecb 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.6", - "oasis-engine": "0.7.0-beta.6" + "@oasis-engine/design": "0.7.0-beta.7", + "oasis-engine": "0.7.0-beta.7" }, "publishConfig": { "access": "public" diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 4d045f6c53..ff8579a328 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,10 +14,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.6", - "@oasis-engine/math": "0.7.0-beta.6" + "@oasis-engine/core": "0.7.0-beta.7", + "@oasis-engine/math": "0.7.0-beta.7" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.6" + "@oasis-engine/design": "0.7.0-beta.7" } } diff --git a/packages/stats/package.json b/packages/stats/package.json index 3db2a14ab2..7776f2a961 100755 --- a/packages/stats/package.json +++ b/packages/stats/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/stats", - "version": "0.7.0-beta.6", + "version": "0.7.0-beta.7", "license": "MIT", "scripts": { "b:types": "tsc" @@ -14,6 +14,6 @@ "types/**/*" ], "dependencies": { - "oasis-engine": "0.7.0-beta.6" + "oasis-engine": "0.7.0-beta.7" } } From 14e41c21aa6372f84982b5a2275c30e27b9599bd Mon Sep 17 00:00:00 2001 From: yangfengzzz Date: Thu, 16 Jun 2022 11:43:49 +0800 Subject: [PATCH 15/33] feat: physics character controller (#818) * feat: add `CharacterController` for physX backend --- packages/core/src/ComponentsManager.ts | 29 ---- .../core/src/physics/CharacterController.ts | 155 ++++++++++++++++++ packages/core/src/physics/Collider.ts | 31 ++-- packages/core/src/physics/DynamicCollider.ts | 2 +- packages/core/src/physics/PhysicsManager.ts | 71 +++++++- .../physics/enums/ControllerCollisionFlag.ts | 11 ++ .../enums/ControllerNonWalkableMode.ts | 9 + packages/core/src/physics/index.ts | 9 +- .../src/physics/shape/CapsuleColliderShape.ts | 2 + .../core/src/physics/shape/ColliderShape.ts | 13 ++ packages/core/src/physics/shape/index.ts | 5 + .../src/physics/ICharacterController.ts | 51 ++++++ packages/design/src/physics/ICollider.ts | 15 -- .../design/src/physics/IDynamicCollider.ts | 14 ++ packages/design/src/physics/IPhysics.ts | 6 + .../design/src/physics/IPhysicsManager.ts | 13 ++ .../design/src/physics/IStaticCollider.ts | 17 +- packages/design/src/physics/index.ts | 1 + .../src/physics/shape/IColliderShape.ts | 12 +- packages/physics-lite/src/LitePhysics.ts | 28 ++-- .../physics-lite/src/LitePhysicsManager.ts | 19 ++- .../src/shape/LiteColliderShape.ts | 7 + .../src/PhysXCharacterController.ts | 130 +++++++++++++++ packages/physics-physx/src/PhysXPhysics.ts | 23 ++- .../physics-physx/src/PhysXPhysicsManager.ts | 47 +++++- .../src/shape/PhysXBoxColliderShape.ts | 14 +- .../src/shape/PhysXCapsuleColliderShape.ts | 25 ++- .../src/shape/PhysXColliderShape.ts | 39 +++-- .../src/shape/PhysXPlaneColliderShape.ts | 3 +- .../src/shape/PhysXSphereColliderShape.ts | 3 +- 30 files changed, 679 insertions(+), 125 deletions(-) create mode 100644 packages/core/src/physics/CharacterController.ts create mode 100644 packages/core/src/physics/enums/ControllerCollisionFlag.ts create mode 100644 packages/core/src/physics/enums/ControllerNonWalkableMode.ts create mode 100644 packages/core/src/physics/shape/index.ts create mode 100644 packages/design/src/physics/ICharacterController.ts create mode 100644 packages/physics-physx/src/PhysXCharacterController.ts diff --git a/packages/core/src/ComponentsManager.ts b/packages/core/src/ComponentsManager.ts index 09a75705b6..7995a2c6e7 100644 --- a/packages/core/src/ComponentsManager.ts +++ b/packages/core/src/ComponentsManager.ts @@ -2,7 +2,6 @@ import { Vector3 } from "@oasis-engine/math"; import { Camera } from "./Camera"; import { Component } from "./Component"; import { DisorderedArray } from "./DisorderedArray"; -import { Collider } from "./physics"; import { Renderer } from "./Renderer"; import { RenderContext } from "./RenderPipeline/RenderContext"; import { Script } from "./Script"; @@ -33,9 +32,6 @@ export class ComponentsManager { // Delay dispose active/inActive Pool private _componentsContainerPool: Component[][] = []; - // Physics - private _colliders: DisorderedArray = new DisorderedArray(); - addRenderer(renderer: Renderer) { renderer._rendererIndex = this._renderers.length; this._renderers.add(renderer); @@ -58,17 +54,6 @@ export class ComponentsManager { script._onStartIndex = -1; } - addCollider(collider: Collider) { - collider._index = this._colliders.length; - this._colliders.add(collider); - } - - removeCollider(collider: Collider): void { - const replaced = this._colliders.deleteByIndex(collider._index); - replaced && (replaced._index = collider._index); - collider._index = -1; - } - addOnUpdateScript(script: Script) { script._onUpdateIndex = this._onUpdateScripts.length; this._onUpdateScripts.add(script); @@ -278,20 +263,6 @@ export class ComponentsManager { } } - callColliderOnUpdate(): void { - const elements = this._colliders._elements; - for (let i = this._colliders.length - 1; i >= 0; --i) { - elements[i]._onUpdate(); - } - } - - callColliderOnLateUpdate(): void { - const elements = this._colliders._elements; - for (let i = this._colliders.length - 1; i >= 0; --i) { - elements[i]._onLateUpdate(); - } - } - getActiveChangedTempList(): Component[] { return this._componentsContainerPool.length ? this._componentsContainerPool.pop() : []; } diff --git a/packages/core/src/physics/CharacterController.ts b/packages/core/src/physics/CharacterController.ts new file mode 100644 index 0000000000..b5c569574d --- /dev/null +++ b/packages/core/src/physics/CharacterController.ts @@ -0,0 +1,155 @@ +import { ICharacterController } from "@oasis-engine/design"; +import { Vector3 } from "@oasis-engine/math"; +import { Entity } from "../Entity"; +import { Collider } from "./Collider"; +import { ControllerNonWalkableMode } from "./enums/ControllerNonWalkableMode"; +import { PhysicsManager } from "./PhysicsManager"; +import { ColliderShape } from "./shape"; + +/** + * The character controllers. + */ +export class CharacterController extends Collider { + /** @internal */ + _index: number = -1; + + private _stepOffset: number = 0; + private _nonWalkableMode: ControllerNonWalkableMode = ControllerNonWalkableMode.PreventClimbing; + private _upDirection = new Vector3(0, 1, 0); + private _slopeLimit: number = 0; + + /** + * The step offset for the controller. + */ + get stepOffset(): number { + return this._stepOffset; + } + + set stepOffset(newValue: number) { + this._stepOffset = newValue; + (this._nativeCollider).setStepOffset(newValue); + } + + /** + * The value of the non-walkable mode. + */ + get nonWalkableMode(): ControllerNonWalkableMode { + return this._nonWalkableMode; + } + + set nonWalkableMode(newValue: ControllerNonWalkableMode) { + this._nonWalkableMode = newValue; + (this._nativeCollider).setNonWalkableMode(newValue); + } + + /** + * The up direction for the controller. + */ + get upDirection(): Vector3 { + return this._upDirection; + } + + set upDirection(newValue: Vector3) { + if (this._upDirection !== newValue) { + newValue.cloneTo(this._upDirection); + } + (this._nativeCollider).setUpDirection(this._upDirection); + } + + /** + * The slope limit for the controller. + */ + get slopeLimit(): number { + return this._slopeLimit; + } + + set slopeLimit(newValue: number) { + this._slopeLimit = newValue; + (this._nativeCollider).setSlopeLimit(newValue); + } + + /** + * @internal + */ + constructor(entity: Entity) { + super(entity); + (this._nativeCollider) = PhysicsManager._nativePhysics.createCharacterController(); + } + + /** + * Moves the character using a "collide-and-slide" algorithm. + * @param disp - Displacement vector + * @param minDist - The minimum travelled distance to consider. + * @param elapsedTime - Time elapsed since last call + * @return flags - The ControllerCollisionFlag + */ + move(disp: Vector3, minDist: number, elapsedTime: number): number { + return (this._nativeCollider).move(disp, minDist, elapsedTime); + } + + /** + * Add collider shape on this controller. + * @param shape - Collider shape + * @override + */ + addShape(shape: ColliderShape): void { + if (this._shapes.length > 0) { + throw "only allow single shape on controller!"; + } + super.addShape(shape); + } + + /** + * Remove all shape attached. + * @override + */ + clearShapes(): void { + if (this._shapes.length > 0) { + super.removeShape(this._shapes[0]); + } + } + + /** + * @internal + * @override + */ + _onUpdate() { + if (this._updateFlag.flag) { + const { transform } = this.entity; + (this._nativeCollider).setWorldPosition(transform.worldPosition); + + const worldScale = transform.lossyWorldScale; + for (let i = 0, n = this.shapes.length; i < n; i++) { + this.shapes[i]._nativeShape.setWorldScale(worldScale); + } + this._updateFlag.flag = false; + } + } + + /** + * @internal + * @override + */ + _onLateUpdate() { + const position = this.entity.transform.worldPosition; + (this._nativeCollider).getWorldPosition(position); + this.entity.transform.worldPosition = position; + this._updateFlag.flag = false; + } + + /** + * @override + * @internal + */ + _onEnable() { + this.engine.physicsManager._addCharacterController(this); + } + + /** + * @override + * @internal + */ + _onDisable() { + this.engine.physicsManager._removeCharacterController(this); + } +} diff --git a/packages/core/src/physics/Collider.ts b/packages/core/src/physics/Collider.ts index 9a2be76a3a..f853ac52ee 100644 --- a/packages/core/src/physics/Collider.ts +++ b/packages/core/src/physics/Collider.ts @@ -1,4 +1,4 @@ -import { ICollider } from "@oasis-engine/design"; +import { ICollider, IStaticCollider } from "@oasis-engine/design"; import { BoolUpdateFlag } from "../BoolUpdateFlag"; import { ignoreClone } from "../clone/CloneManager"; import { Component } from "../Component"; @@ -20,8 +20,7 @@ export class Collider extends Component { _nativeCollider: ICollider; protected _updateFlag: BoolUpdateFlag; - - private _shapes: ColliderShape[] = []; + protected _shapes: ColliderShape[] = []; /** * The shapes of this collider. @@ -48,10 +47,11 @@ export class Collider extends Component { if (oldCollider) { oldCollider.removeShape(shape); } + this._shapes.push(shape); this.engine.physicsManager._addColliderShape(shape); - this._nativeCollider.addShape(shape._nativeShape); shape._collider = this; + this._nativeCollider.addShape(shape._nativeShape); } } @@ -63,9 +63,9 @@ export class Collider extends Component { const index = this._shapes.indexOf(shape); if (index !== -1) { this._shapes.splice(index, 1); - this._nativeCollider.removeShape(shape._nativeShape); this.engine.physicsManager._removeColliderShape(shape); shape._collider = null; + this._nativeCollider.removeShape(shape._nativeShape); } } @@ -76,9 +76,9 @@ export class Collider extends Component { const shapes = this._shapes; for (let i = 0, n = shapes.length; i < n; i++) { const shape = shapes[i]; - this._nativeCollider.removeShape(shape._nativeShape); this.engine.physicsManager._removeColliderShape(shape); shape._destroy(); + this._nativeCollider.removeShape(shape._nativeShape); } shapes.length = 0; } @@ -86,47 +86,48 @@ export class Collider extends Component { /** * @internal */ - _onUpdate() { + _onUpdate(): void { if (this._updateFlag.flag) { const { transform } = this.entity; - this._nativeCollider.setWorldTransform(transform.worldPosition, transform.worldRotationQuaternion); - this._updateFlag.flag = false; + (this._nativeCollider).setWorldTransform( + transform.worldPosition, + transform.worldRotationQuaternion + ); const worldScale = transform.lossyWorldScale; for (let i = 0, n = this.shapes.length; i < n; i++) { this.shapes[i]._nativeShape.setWorldScale(worldScale); } + this._updateFlag.flag = false; } } /** * @internal */ - _onLateUpdate() {} + _onLateUpdate(): void {} /** * @override * @internal */ - _onEnable() { + _onEnable(): void { this.engine.physicsManager._addCollider(this); - this.engine._componentsManager.addCollider(this); } /** * @override * @internal */ - _onDisable() { + _onDisable(): void { this.engine.physicsManager._removeCollider(this); - this.engine._componentsManager.removeCollider(this); } /** * @override * @internal */ - _onDestroy() { + _onDestroy(): void { this.clearShapes(); this._nativeCollider.destroy(); } diff --git a/packages/core/src/physics/DynamicCollider.ts b/packages/core/src/physics/DynamicCollider.ts index 9b9a9dab0d..edced0df51 100644 --- a/packages/core/src/physics/DynamicCollider.ts +++ b/packages/core/src/physics/DynamicCollider.ts @@ -271,7 +271,7 @@ export class DynamicCollider extends Collider { _onLateUpdate(): void { const { transform } = this.entity; const { worldPosition, worldRotationQuaternion } = transform; - this._nativeCollider.getWorldTransform(worldPosition, worldRotationQuaternion); + (this._nativeCollider).getWorldTransform(worldPosition, worldRotationQuaternion); transform.worldPosition = worldPosition; transform.worldRotationQuaternion = worldRotationQuaternion; this._updateFlag.flag = false; diff --git a/packages/core/src/physics/PhysicsManager.ts b/packages/core/src/physics/PhysicsManager.ts index c7cb0660a4..ac86a98d3c 100644 --- a/packages/core/src/physics/PhysicsManager.ts +++ b/packages/core/src/physics/PhysicsManager.ts @@ -1,10 +1,12 @@ -import { IPhysics, IPhysicsManager } from "@oasis-engine/design"; +import { ICharacterController, ICollider, IPhysics, IPhysicsManager } from "@oasis-engine/design"; import { Ray, Vector3 } from "@oasis-engine/math"; +import { DisorderedArray } from "../DisorderedArray"; import { Engine } from "../Engine"; import { Layer } from "../Layer"; +import { CharacterController } from "./CharacterController"; import { Collider } from "./Collider"; import { HitResult } from "./HitResult"; -import { ColliderShape } from "./shape/ColliderShape"; +import { ColliderShape } from "./shape"; /** * A physics manager is a collection of bodies and constraints which can interact. @@ -18,6 +20,8 @@ export class PhysicsManager { private _engine: Engine; private _restTime: number = 0; + private _colliders: DisorderedArray = new DisorderedArray(); + private _gravity: Vector3 = new Vector3(0, -9.81, 0); private _nativePhysicsManager: IPhysicsManager; private _physicalObjectsMap: Record = {}; @@ -126,6 +130,9 @@ export class PhysicsManager { /** The max sum of time step in seconds one frame. */ maxSumTimeStep: number = 1 / 3; + /** + * The gravity of physics scene. + */ get gravity(): Vector3 { return this._gravity; } @@ -277,9 +284,9 @@ export class PhysicsManager { this._restTime = simulateTime - step * fixedTimeStep; for (let i = 0; i < step; i++) { componentsManager.callScriptOnPhysicsUpdate(); - componentsManager.callColliderOnUpdate(); + this._callColliderOnUpdate(); nativePhysicsManager.update(fixedTimeStep); - componentsManager.callColliderOnLateUpdate(); + this._callColliderOnLateUpdate(); } } @@ -309,7 +316,24 @@ export class PhysicsManager { * @internal */ _addCollider(collider: Collider): void { - this._nativePhysicsManager.addCollider(collider._nativeCollider); + if (collider._index === -1) { + collider._index = this._colliders.length; + this._colliders.add(collider); + } + this._nativePhysicsManager.addCollider(collider._nativeCollider); + } + + /** + * Add character controller into the manager. + * @param controller - Character Controller. + * @internal + */ + _addCharacterController(controller: CharacterController): void { + if (controller._index === -1) { + controller._index = this._colliders.length; + this._colliders.add(controller); + } + this._nativePhysicsManager.addCharacterController(controller._nativeCollider); } /** @@ -318,6 +342,41 @@ export class PhysicsManager { * @internal */ _removeCollider(collider: Collider): void { - this._nativePhysicsManager.removeCollider(collider._nativeCollider); + const replaced = this._colliders.deleteByIndex(collider._index); + replaced && (replaced._index = collider._index); + collider._index = -1; + this._nativePhysicsManager.removeCollider(collider._nativeCollider); + } + + /** + * Remove collider. + * @param controller - Character Controller. + * @internal + */ + _removeCharacterController(controller: CharacterController): void { + const replaced = this._colliders.deleteByIndex(controller._index); + replaced && (replaced._index = controller._index); + controller._index = -1; + this._nativePhysicsManager.removeCharacterController(controller._nativeCollider); + } + + /** + * @internal + */ + _callColliderOnUpdate(): void { + const elements = this._colliders._elements; + for (let i = this._colliders.length - 1; i >= 0; --i) { + elements[i]._onUpdate(); + } + } + + /** + * @internal + */ + _callColliderOnLateUpdate(): void { + const elements = this._colliders._elements; + for (let i = this._colliders.length - 1; i >= 0; --i) { + elements[i]._onLateUpdate(); + } } } diff --git a/packages/core/src/physics/enums/ControllerCollisionFlag.ts b/packages/core/src/physics/enums/ControllerCollisionFlag.ts new file mode 100644 index 0000000000..0f783f1c46 --- /dev/null +++ b/packages/core/src/physics/enums/ControllerCollisionFlag.ts @@ -0,0 +1,11 @@ +/** + * The up axis of the collider shape. + */ +export enum ControllerCollisionFlag { + /** Character is colliding to the sides. */ + Sides = 1, + /** Character has collision above. */ + Up = 2, + /** Character has collision below. */ + Down = 4 +} diff --git a/packages/core/src/physics/enums/ControllerNonWalkableMode.ts b/packages/core/src/physics/enums/ControllerNonWalkableMode.ts new file mode 100644 index 0000000000..f05233d1a6 --- /dev/null +++ b/packages/core/src/physics/enums/ControllerNonWalkableMode.ts @@ -0,0 +1,9 @@ +/** + * The up axis of the collider shape. + */ +export enum ControllerNonWalkableMode { + /** Stops character from climbing up non-walkable slopes, but doesn't move it otherwise. */ + PreventClimbing, + /** Stops character from climbing up non-walkable slopes, and forces it to slide down those slopes. */ + PreventClimbingAndForceSliding +} diff --git a/packages/core/src/physics/index.ts b/packages/core/src/physics/index.ts index 66ca44f015..1bfd79ad2d 100644 --- a/packages/core/src/physics/index.ts +++ b/packages/core/src/physics/index.ts @@ -1,14 +1,13 @@ export { HitResult } from "./HitResult"; export { PhysicsMaterialCombineMode } from "./enums/PhysicsMaterialCombineMode"; export { ColliderShapeUpAxis } from "./enums/ColliderShapeUpAxis"; +export { ControllerCollisionFlag } from "./enums/ControllerCollisionFlag"; +export { ControllerNonWalkableMode } from "./enums/ControllerNonWalkableMode"; export { PhysicsManager } from "./PhysicsManager"; export { PhysicsMaterial } from "./PhysicsMaterial"; -export { ColliderShape } from "./shape/ColliderShape"; -export { BoxColliderShape } from "./shape/BoxColliderShape"; -export { SphereColliderShape } from "./shape/SphereColliderShape"; -export { PlaneColliderShape } from "./shape/PlaneColliderShape"; -export { CapsuleColliderShape } from "./shape/CapsuleColliderShape"; +export { CharacterController } from "./CharacterController"; +export * from "./shape"; export { Collider } from "./Collider"; export { StaticCollider } from "./StaticCollider"; diff --git a/packages/core/src/physics/shape/CapsuleColliderShape.ts b/packages/core/src/physics/shape/CapsuleColliderShape.ts index 0fb253d570..2e13de5e78 100644 --- a/packages/core/src/physics/shape/CapsuleColliderShape.ts +++ b/packages/core/src/physics/shape/CapsuleColliderShape.ts @@ -19,6 +19,7 @@ export class CapsuleColliderShape extends ColliderShape { } set radius(value: number) { + this._radius = value; (this._nativeShape).setRadius(value); } @@ -30,6 +31,7 @@ export class CapsuleColliderShape extends ColliderShape { } set height(value: number) { + this._height = value; (this._nativeShape).setHeight(value); } diff --git a/packages/core/src/physics/shape/ColliderShape.ts b/packages/core/src/physics/shape/ColliderShape.ts index b449bf1d45..9425f9b14a 100644 --- a/packages/core/src/physics/shape/ColliderShape.ts +++ b/packages/core/src/physics/shape/ColliderShape.ts @@ -19,6 +19,7 @@ export abstract class ColliderShape { protected _material: PhysicsMaterial; protected _isTrigger: boolean = false; protected _isSceneQuery: boolean = true; + private _contactOffset: number = 0; /** * Collider owner of this shape. @@ -34,6 +35,18 @@ export abstract class ColliderShape { return this._id; } + /** + * Contact offset for this shape. + */ + get contactOffset() { + return this._contactOffset; + } + + set contactOffset(value: number) { + this._contactOffset = value; + this._nativeShape.setContactOffset(value); + } + /** * Physical material. */ diff --git a/packages/core/src/physics/shape/index.ts b/packages/core/src/physics/shape/index.ts new file mode 100644 index 0000000000..4517e2ae74 --- /dev/null +++ b/packages/core/src/physics/shape/index.ts @@ -0,0 +1,5 @@ +export { ColliderShape } from "./ColliderShape"; +export { BoxColliderShape } from "./BoxColliderShape"; +export { SphereColliderShape } from "./SphereColliderShape"; +export { PlaneColliderShape } from "./PlaneColliderShape"; +export { CapsuleColliderShape } from "./CapsuleColliderShape"; diff --git a/packages/design/src/physics/ICharacterController.ts b/packages/design/src/physics/ICharacterController.ts new file mode 100644 index 0000000000..4f57c199c6 --- /dev/null +++ b/packages/design/src/physics/ICharacterController.ts @@ -0,0 +1,51 @@ +import { Vector3 } from "@oasis-engine/math"; +import { ICollider } from "./ICollider"; + +/** + * Base class for character controllers. + */ +export interface ICharacterController extends ICollider { + /** + * Moves the character using a "collide-and-slide" algorithm. + * @param disp Displacement vector + * @param minDist The minimum travelled distance to consider. + * @param elapsedTime Time elapsed since last call + */ + move(disp: Vector3, minDist: number, elapsedTime: number): number; + + /** + * Sets controller's world position. + * @param position The new (center) position for the controller. + */ + setWorldPosition(position: Vector3): boolean; + + /** + * Retrieve the world position of the controller. + * @param position The controller's center position + */ + getWorldPosition(position: Vector3): void; + + /** + * The step height. + * @param offset The new step offset for the controller. + */ + setStepOffset(offset: number): void; + + /** + * Sets the non-walkable mode for the CCT. + * @param flag The new value of the non-walkable mode. + */ + setNonWalkableMode(flag: number): void; + + /** + * Sets the 'up' direction. + * @param up The up direction for the controller. + */ + setUpDirection(up: Vector3): void; + + /** + * Sets the slope limit. + * @param slopeLimit The slope limit for the controller. + */ + setSlopeLimit(slopeLimit: number): void; +} diff --git a/packages/design/src/physics/ICollider.ts b/packages/design/src/physics/ICollider.ts index 76fc1424e7..f9ed026dc4 100644 --- a/packages/design/src/physics/ICollider.ts +++ b/packages/design/src/physics/ICollider.ts @@ -1,24 +1,9 @@ import { IColliderShape } from "./shape"; -import { Quaternion, Vector3 } from "@oasis-engine/math"; /** * Interface of physics collider. */ export interface ICollider { - /** - * Set global transform of collider. - * @param position - The global position - * @param rotation - The global rotation - */ - setWorldTransform(position: Vector3, rotation: Quaternion): void; - - /** - * Get global transform of collider. - * @param outPosition - The global position - * @param outRotation - The global rotation - */ - getWorldTransform(outPosition: Vector3, outRotation: Quaternion): void; - /** * Add collider shape on collider. * @param shape - The collider shape attached diff --git a/packages/design/src/physics/IDynamicCollider.ts b/packages/design/src/physics/IDynamicCollider.ts index 0b6b158b80..b5107ea3e0 100644 --- a/packages/design/src/physics/IDynamicCollider.ts +++ b/packages/design/src/physics/IDynamicCollider.ts @@ -5,6 +5,20 @@ import { ICollider } from "./ICollider"; * Interface of physics dynamic collider. */ export interface IDynamicCollider extends ICollider { + /** + * Set global transform of collider. + * @param position - The global position + * @param rotation - The global rotation + */ + setWorldTransform(position: Vector3, rotation: Quaternion): void; + + /** + * Get global transform of collider. + * @param outPosition - The global position + * @param outRotation - The global rotation + */ + getWorldTransform(outPosition: Vector3, outRotation: Quaternion): void; + /** * Sets the linear damping coefficient. * @param value - Linear damping coefficient. diff --git a/packages/design/src/physics/IPhysics.ts b/packages/design/src/physics/IPhysics.ts index a93afa5b55..d5badf7399 100644 --- a/packages/design/src/physics/IPhysics.ts +++ b/packages/design/src/physics/IPhysics.ts @@ -4,6 +4,7 @@ import { IBoxColliderShape, ISphereColliderShape, ICapsuleColliderShape, IPlaneC import { IDynamicCollider } from "./IDynamicCollider"; import { IStaticCollider } from "./IStaticCollider"; import { Quaternion, Vector3 } from "@oasis-engine/math"; +import { ICharacterController } from "./ICharacterController"; /** * The interface of physics creation. @@ -41,6 +42,11 @@ export interface IPhysics { */ createStaticCollider(position: Vector3, rotation: Quaternion): IStaticCollider; + /** + * Create character controller. + */ + createCharacterController(): ICharacterController; + /** * Create physics material. * @param staticFriction - Static friction diff --git a/packages/design/src/physics/IPhysicsManager.ts b/packages/design/src/physics/IPhysicsManager.ts index 64f0efde85..1f52c33e83 100644 --- a/packages/design/src/physics/IPhysicsManager.ts +++ b/packages/design/src/physics/IPhysicsManager.ts @@ -1,4 +1,5 @@ import { Ray, Vector3 } from "@oasis-engine/math"; +import { ICharacterController } from "./ICharacterController"; import { ICollider } from "./ICollider"; import { IColliderShape } from "./shape"; @@ -36,6 +37,18 @@ export interface IPhysicsManager { */ removeCollider(collider: ICollider): void; + /** + * Add ICharacterController into the manager. + * @param characterController The Character Controller. + */ + addCharacterController(characterController: ICharacterController): void; + + /** + * Remove ICharacterController. + * @param characterController The Character Controller. + */ + removeCharacterController(characterController: ICharacterController): void; + /** * Call on every frame to update pose of objects. * @param elapsedTime - Step time of update. diff --git a/packages/design/src/physics/IStaticCollider.ts b/packages/design/src/physics/IStaticCollider.ts index ff33545c23..19f1eff1ea 100644 --- a/packages/design/src/physics/IStaticCollider.ts +++ b/packages/design/src/physics/IStaticCollider.ts @@ -1,6 +1,21 @@ +import { Quaternion, Vector3 } from "@oasis-engine/math"; import { ICollider } from "./ICollider"; /** * Interface of physics static collider. */ -export interface IStaticCollider extends ICollider {} +export interface IStaticCollider extends ICollider { + /** + * Set global transform of collider. + * @param position - The global position + * @param rotation - The global rotation + */ + setWorldTransform(position: Vector3, rotation: Quaternion): void; + + /** + * Get global transform of collider. + * @param outPosition - The global position + * @param outRotation - The global rotation + */ + getWorldTransform(outPosition: Vector3, outRotation: Quaternion): void; +} diff --git a/packages/design/src/physics/index.ts b/packages/design/src/physics/index.ts index 8ae6974596..b73c672b12 100644 --- a/packages/design/src/physics/index.ts +++ b/packages/design/src/physics/index.ts @@ -4,4 +4,5 @@ export type { ICollider } from "./ICollider"; export type { IStaticCollider } from "./IStaticCollider"; export type { IDynamicCollider } from "./IDynamicCollider"; export type { IPhysicsMaterial } from "./IPhysicsMaterial"; +export type { ICharacterController } from "./ICharacterController"; export * from "./shape/index"; diff --git a/packages/design/src/physics/shape/IColliderShape.ts b/packages/design/src/physics/shape/IColliderShape.ts index 48d7bf5667..516c72aaad 100644 --- a/packages/design/src/physics/shape/IColliderShape.ts +++ b/packages/design/src/physics/shape/IColliderShape.ts @@ -5,12 +5,6 @@ import { IPhysicsMaterial } from "../IPhysicsMaterial"; * Interface for physics collider shape. */ export interface IColliderShape { - /** - * Set unique id of the collider shape. - * @param id - The unique index - */ - setUniqueID(id: number): void; - /** * Set local position. * @param position - The local position @@ -23,6 +17,12 @@ export interface IColliderShape { */ setWorldScale(scale: Vector3): void; + /** + * Sets the contact offset. + * @param offset - contact offset + */ + setContactOffset(offset: number): void; + /** * Set physics material on shape. * @param material - The physics material diff --git a/packages/physics-lite/src/LitePhysics.ts b/packages/physics-lite/src/LitePhysics.ts index 6ff494a6c6..858037c8ef 100644 --- a/packages/physics-lite/src/LitePhysics.ts +++ b/packages/physics-lite/src/LitePhysics.ts @@ -1,22 +1,23 @@ import { - IPhysics, - IPhysicsMaterial, - IPhysicsManager, IBoxColliderShape, - ISphereColliderShape, ICapsuleColliderShape, + ICharacterController, IDynamicCollider, - IStaticCollider, - IPlaneColliderShape + IPhysics, + IPhysicsManager, + IPhysicsMaterial, + IPlaneColliderShape, + ISphereColliderShape, + IStaticCollider } from "@oasis-engine/design"; -import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; import { Quaternion, Vector3 } from "oasis-engine"; -import { LiteStaticCollider } from "./LiteStaticCollider"; +import { LiteDynamicCollider } from "./LiteDynamicCollider"; +import { LitePhysicsManager } from "./LitePhysicsManager"; import { LitePhysicsMaterial } from "./LitePhysicsMaterial"; +import { LiteStaticCollider } from "./LiteStaticCollider"; import { LiteBoxColliderShape } from "./shape/LiteBoxColliderShape"; -import { LitePhysicsManager } from "./LitePhysicsManager"; import { LiteSphereColliderShape } from "./shape/LiteSphereColliderShape"; -import { LiteDynamicCollider } from "./LiteDynamicCollider"; +import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; @StaticInterfaceImplement() export class LitePhysics { @@ -55,6 +56,13 @@ export class LitePhysics { return new LiteDynamicCollider(position, rotation); } + /** + * {@inheritDoc IPhysics.createCharacterController } + */ + static createCharacterController(): ICharacterController { + throw "Physics-lite don't support createCharacterController. Use Physics-PhysX instead!"; + } + /** * {@inheritDoc IPhysics.createPhysicsMaterial } */ diff --git a/packages/physics-lite/src/LitePhysicsManager.ts b/packages/physics-lite/src/LitePhysicsManager.ts index 6e749ae381..ff7b2ffc6b 100644 --- a/packages/physics-lite/src/LitePhysicsManager.ts +++ b/packages/physics-lite/src/LitePhysicsManager.ts @@ -1,4 +1,4 @@ -import { IPhysicsManager } from "@oasis-engine/design"; +import { ICharacterController, IPhysicsManager } from "@oasis-engine/design"; import { BoundingBox, BoundingSphere, Ray, Vector3, CollisionUtil } from "oasis-engine"; import { LiteCollider } from "./LiteCollider"; import { LiteHitResult } from "./LiteHitResult"; @@ -6,6 +6,7 @@ import { LiteBoxColliderShape } from "./shape/LiteBoxColliderShape"; import { LiteSphereColliderShape } from "./shape/LiteSphereColliderShape"; import { LiteColliderShape } from "./shape/LiteColliderShape"; import { DisorderedArray } from "./DisorderedArray"; +import { IColliderShape } from "@oasis-engine/design/src"; /** * A manager is a collection of bodies and constraints which can interact. @@ -153,7 +154,21 @@ export class LitePhysicsManager implements IPhysicsManager { } /** - * Calculate the boundingbox in world space from boxCollider. + * {@inheritDoc IPhysicsManager.addCharacterController } + */ + addCharacterController(characterController: ICharacterController): void { + throw "Physics-lite don't support addCharacterController. Use Physics-PhysX instead!"; + } + + /** + * {@inheritDoc IPhysicsManager.removeCharacterController } + */ + removeCharacterController(characterController: ICharacterController): void { + throw "Physics-lite don't support removeCharacterController. Use Physics-PhysX instead!"; + } + + /** + * Calculate the bounding box in world space from boxCollider. * @param boxCollider - The boxCollider to calculate * @param out - The calculated boundingBox */ diff --git a/packages/physics-lite/src/shape/LiteColliderShape.ts b/packages/physics-lite/src/shape/LiteColliderShape.ts index 42d4a7b961..39ffb4f2b6 100644 --- a/packages/physics-lite/src/shape/LiteColliderShape.ts +++ b/packages/physics-lite/src/shape/LiteColliderShape.ts @@ -40,6 +40,13 @@ export abstract class LiteColliderShape implements IColliderShape { */ abstract setWorldScale(scale: Vector3): void; + /** + * {@inheritDoc IColliderShape.setContactOffset } + */ + setContactOffset(offset: number): void { + throw "Physics-lite don't support setContactOffset. Use Physics-PhysX instead!"; + } + /** * {@inheritDoc IColliderShape.setMaterial } */ diff --git a/packages/physics-physx/src/PhysXCharacterController.ts b/packages/physics-physx/src/PhysXCharacterController.ts new file mode 100644 index 0000000000..30e69337e6 --- /dev/null +++ b/packages/physics-physx/src/PhysXCharacterController.ts @@ -0,0 +1,130 @@ +import { ICharacterController } from "@oasis-engine/design"; +import { Vector3 } from "oasis-engine"; +import { PhysXPhysics } from "./PhysXPhysics"; +import { PhysXPhysicsManager } from "./PhysXPhysicsManager"; +import { PhysXBoxColliderShape } from "./shape/PhysXBoxColliderShape"; +import { PhysXCapsuleColliderShape } from "./shape/PhysXCapsuleColliderShape"; +import { PhysXColliderShape } from "./shape/PhysXColliderShape"; + +/** + * Base class for character controllers. + */ +export class PhysXCharacterController implements ICharacterController { + /** @internal */ + _id: number; + /** @internal */ + _pxController: any; + /** @internal */ + _pxManager: PhysXPhysicsManager; + /** @internal */ + _shape: PhysXColliderShape; + /** + * {@inheritDoc ICharacterController.move } + */ + move(disp: Vector3, minDist: number, elapsedTime: number): number { + return this._pxController.move(disp, minDist, elapsedTime); + } + + /** + * {@inheritDoc ICharacterController.setWorldPosition } + */ + setWorldPosition(position: Vector3): boolean { + return this._pxController.setPosition(position); + } + + /** + * {@inheritDoc ICharacterController.getWorldPosition } + */ + getWorldPosition(position: Vector3): void { + position.setValue( + this._pxController.getPosition().x, + this._pxController.getPosition().y, + this._pxController.getPosition().z + ); + } + + /** + * {@inheritDoc ICharacterController.setStepOffset } + */ + setStepOffset(offset: number): void { + this._pxController.setStepOffset(offset); + } + + /** + * {@inheritDoc ICharacterController.setNonWalkableMode } + */ + setNonWalkableMode(flag: number): void { + this._pxController.setNonWalkableMode(flag); + } + + /** + * {@inheritDoc ICharacterController.setUpDirection } + */ + setUpDirection(up: Vector3): void { + this._pxController.setUpDirection(up); + } + + /** + * {@inheritDoc ICharacterController.setSlopeLimit } + */ + setSlopeLimit(slopeLimit: number): void { + this._pxController.setSlopeLimit(slopeLimit); + } + + /** + * {@inheritDoc ICharacterController.addShape } + */ + addShape(shape: PhysXColliderShape): void { + this._pxManager && this._createPXController(this._pxManager, shape); + this._shape = shape; + shape._controllers.add(this); + } + + /** + * {@inheritDoc ICharacterController.removeShape } + */ + removeShape(shape: PhysXColliderShape): void { + this._destroyPXController(); + this._shape = null; + shape._controllers.delete(this); + } + + /** + * {@inheritDoc ICharacterController.destroy } + */ + destroy(): void { + this._destroyPXController(); + } + + /** + * @internal + */ + _createPXController(pxManager: PhysXPhysicsManager, shape: PhysXColliderShape): void { + let desc: any; + if (shape instanceof PhysXBoxColliderShape) { + desc = new PhysXPhysics._physX.PxBoxControllerDesc(); + desc.halfHeight = shape._halfSize.x; + desc.halfSideExtent = shape._halfSize.y; + desc.halfForwardExtent = shape._halfSize.z; + } else if (shape instanceof PhysXCapsuleColliderShape) { + desc = new PhysXPhysics._physX.PxCapsuleControllerDesc(); + desc.radius = shape._radius; + desc.height = shape._halfHeight * 2; + desc.climbingMode = 1; // constraint mode + } else { + throw "unsupported shape type"; + } + + desc.setMaterial(shape._pxMaterials[0]); + + this._pxController = pxManager._getControllerManager().createController(desc); + } + + /** + * @internal + */ + _destroyPXController(): void { + this._pxController.release(); + this._pxController = null; + } +} diff --git a/packages/physics-physx/src/PhysXPhysics.ts b/packages/physics-physx/src/PhysXPhysics.ts index 4afdf49bf6..f5042a6e8c 100644 --- a/packages/physics-physx/src/PhysXPhysics.ts +++ b/packages/physics-physx/src/PhysXPhysics.ts @@ -1,6 +1,7 @@ import { IBoxColliderShape, ICapsuleColliderShape, + ICharacterController, IDynamicCollider, IPhysics, IPhysicsManager, @@ -9,17 +10,18 @@ import { ISphereColliderShape, IStaticCollider } from "@oasis-engine/design"; -import { PhysXPhysicsMaterial } from "./PhysXPhysicsMaterial"; +import { Quaternion, Vector3 } from "oasis-engine"; +import { PhysXRuntimeMode } from "./enum/PhysXRuntimeMode"; +import { PhysXCharacterController } from "./PhysXCharacterController"; +import { PhysXDynamicCollider } from "./PhysXDynamicCollider"; import { PhysXPhysicsManager } from "./PhysXPhysicsManager"; +import { PhysXPhysicsMaterial } from "./PhysXPhysicsMaterial"; +import { PhysXStaticCollider } from "./PhysXStaticCollider"; import { PhysXBoxColliderShape } from "./shape/PhysXBoxColliderShape"; -import { PhysXSphereColliderShape } from "./shape/PhysXSphereColliderShape"; import { PhysXCapsuleColliderShape } from "./shape/PhysXCapsuleColliderShape"; -import { PhysXDynamicCollider } from "./PhysXDynamicCollider"; -import { PhysXStaticCollider } from "./PhysXStaticCollider"; -import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; -import { Quaternion, Vector3 } from "oasis-engine"; import { PhysXPlaneColliderShape } from "./shape/PhysXPlaneColliderShape"; -import { PhysXRuntimeMode } from "./enum/PhysXRuntimeMode"; +import { PhysXSphereColliderShape } from "./shape/PhysXSphereColliderShape"; +import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; /** * PhysX object creation. @@ -127,6 +129,13 @@ export class PhysXPhysics { return new PhysXDynamicCollider(position, rotation); } + /** + * {@inheritDoc IPhysics.createCharacterController } + */ + static createCharacterController(): ICharacterController { + return new PhysXCharacterController(); + } + /** * {@inheritDoc IPhysics.createPhysicsMaterial } */ diff --git a/packages/physics-physx/src/PhysXPhysicsManager.ts b/packages/physics-physx/src/PhysXPhysicsManager.ts index 795d0f8cd9..e26790a957 100644 --- a/packages/physics-physx/src/PhysXPhysicsManager.ts +++ b/packages/physics-physx/src/PhysXPhysicsManager.ts @@ -1,14 +1,18 @@ -import { PhysXPhysics } from "./PhysXPhysics"; -import { Ray, Vector3 } from "oasis-engine"; import { IPhysicsManager } from "@oasis-engine/design"; -import { PhysXCollider } from "./PhysXCollider"; +import { Ray, Vector3 } from "oasis-engine"; import { DisorderedArray } from "./DisorderedArray"; +import { PhysXCharacterController } from "./PhysXCharacterController"; +import { PhysXCollider } from "./PhysXCollider"; +import { PhysXPhysics } from "./PhysXPhysics"; import { PhysXColliderShape } from "./shape/PhysXColliderShape"; /** * A manager is a collection of bodies and constraints which can interact. */ export class PhysXPhysicsManager implements IPhysicsManager { + /** @internal */ + _pxControllerManager: any = null; + private static _tempPosition: Vector3 = new Vector3(); private static _tempNormal: Vector3 = new Vector3(); private static _pxRaycastHit: any; @@ -143,6 +147,32 @@ export class PhysXPhysicsManager implements IPhysicsManager { this._pxScene.removeActor(collider._pxActor, true); } + /** + * {@inheritDoc IPhysicsManager.addCharacterController } + */ + addCharacterController(characterController: PhysXCharacterController): void { + const lastPXManager = characterController._pxManager; + const shape = characterController._shape; + if (shape) { + if (lastPXManager !== this) { + lastPXManager && characterController._destroyPXController(); + characterController._createPXController(this, shape); + } + this._pxScene.addController(characterController._pxController); + } + characterController._pxManager = this; + } + + /** + * {@inheritDoc IPhysicsManager.removeCharacterController } + */ + removeCharacterController(characterController: PhysXCharacterController): void { + if (characterController._shape) { + this._pxScene.removeController(characterController._pxController); + } + characterController._pxManager = null; + } + /** * {@inheritDoc IPhysicsManager.update } */ @@ -181,6 +211,17 @@ export class PhysXPhysicsManager implements IPhysicsManager { return result; } + /** + * @internal + */ + _getControllerManager(): any { + let pxControllerManager = this._pxControllerManager; + if (pxControllerManager === null) { + this._pxControllerManager = pxControllerManager = this._pxScene.createControllerManager(); + } + return pxControllerManager; + } + private _simulate(elapsedTime: number): void { this._pxScene.simulate(elapsedTime, true); } diff --git a/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts b/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts index dc2de23575..1bd13f9378 100644 --- a/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts @@ -9,7 +9,8 @@ import { PhysXColliderShape } from "./PhysXColliderShape"; */ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxColliderShape { private static _tempHalfExtents = new Vector3(); - private _halfSize: Vector3 = new Vector3(); + /** @internal */ + _halfSize: Vector3 = new Vector3(); /** * Init Box Shape and alloc PhysX objects. @@ -27,9 +28,8 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol this._halfSize.y * this._scale.y, this._halfSize.z * this._scale.z ); - this._allocShape(material); + this._initialize(material, uniqueID); this._setLocalPose(); - this.setUniqueID(uniqueID); } /** @@ -40,6 +40,14 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol Vector3.multiply(this._halfSize, this._scale, PhysXBoxColliderShape._tempHalfExtents); this._pxGeometry.halfExtents = PhysXBoxColliderShape._tempHalfExtents; this._pxShape.setGeometry(this._pxGeometry); + + const controllers = this._controllers; + for (let i = 0, n = controllers.length; i < n; i++) { + const pxController = controllers.get(i)._pxController; + pxController.setHalfHeight(this._halfSize.x); + pxController.setHalfSideExtent(this._halfSize.y); + pxController.setHalfForwardExtent(this._halfSize.z); + } } /** diff --git a/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts b/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts index 36598a11f2..9402d50292 100644 --- a/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts @@ -1,15 +1,17 @@ -import { PhysXPhysics } from "../PhysXPhysics"; import { ICapsuleColliderShape } from "@oasis-engine/design"; -import { PhysXColliderShape } from "./PhysXColliderShape"; -import { PhysXPhysicsMaterial } from "../PhysXPhysicsMaterial"; import { Vector3 } from "oasis-engine"; +import { PhysXPhysics } from "../PhysXPhysics"; +import { PhysXPhysicsMaterial } from "../PhysXPhysicsMaterial"; +import { PhysXColliderShape } from "./PhysXColliderShape"; /** * Capsule collider shape in PhysX. */ export class PhysXCapsuleColliderShape extends PhysXColliderShape implements ICapsuleColliderShape { - private _radius: number; - private _halfHeight: number; + /** @internal */ + _radius: number; + /** @internal */ + _halfHeight: number; private _upAxis: ColliderShapeUpAxis = ColliderShapeUpAxis.Y; /** @@ -26,9 +28,8 @@ export class PhysXCapsuleColliderShape extends PhysXColliderShape implements ICa this._halfHeight = height * 0.5; this._pxGeometry = new PhysXPhysics._physX.PxCapsuleGeometry(this._radius, this._halfHeight); - this._allocShape(material); + this._initialize(material, uniqueID); this._setLocalPose(); - this.setUniqueID(uniqueID); } /** @@ -48,6 +49,11 @@ export class PhysXCapsuleColliderShape extends PhysXColliderShape implements ICa break; } this._pxShape.setGeometry(this._pxGeometry); + + const controllers = this._controllers; + for (let i = 0, n = controllers.length; i < n; i++) { + controllers.get(i)._pxController.setRadius(value); + } } /** @@ -67,6 +73,11 @@ export class PhysXCapsuleColliderShape extends PhysXColliderShape implements ICa break; } this._pxShape.setGeometry(this._pxGeometry); + + const controllers = this._controllers; + for (let i = 0, n = controllers.length; i < n; i++) { + controllers.get(i)._pxController.setHeight(value); + } } /** diff --git a/packages/physics-physx/src/shape/PhysXColliderShape.ts b/packages/physics-physx/src/shape/PhysXColliderShape.ts index 025bfeca81..a398772bc8 100644 --- a/packages/physics-physx/src/shape/PhysXColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXColliderShape.ts @@ -1,7 +1,9 @@ import { IColliderShape } from "@oasis-engine/design"; import { Quaternion, Vector3 } from "oasis-engine"; -import { PhysXPhysicsMaterial } from "../PhysXPhysicsMaterial"; +import { DisorderedArray } from "../DisorderedArray"; +import { PhysXCharacterController } from "../PhysXCharacterController"; import { PhysXPhysics } from "../PhysXPhysics"; +import { PhysXPhysicsMaterial } from "../PhysXPhysicsMaterial"; /** * Flags which affect the behavior of Shapes. @@ -24,19 +26,26 @@ export abstract class PhysXColliderShape implements IColliderShape { translation: new Vector3(), rotation: null }; + + /** @internal */ + _controllers: DisorderedArray = new DisorderedArray(); + protected _position: Vector3 = new Vector3(); protected _rotation: Quaternion = new Quaternion(); protected _scale: Vector3 = new Vector3(1, 1, 1); private _shapeFlags: ShapeFlag = ShapeFlag.SCENE_QUERY_SHAPE | ShapeFlag.SIMULATION_SHAPE; - private _pxMaterials: any[] = new Array(1); + /** @internal */ + _pxMaterials: any[] = new Array(1); /** @internal */ _pxShape: any; /** @internal */ _pxGeometry: any; /** @internal */ _id: number; + /** @internal */ + _contactOffset: number = 0; /** * {@inheritDoc IColliderShape.setPosition } @@ -54,19 +63,24 @@ export abstract class PhysXColliderShape implements IColliderShape { abstract setWorldScale(scale: Vector3): void; /** - * {@inheritDoc IColliderShape.setMaterial } + * {@inheritDoc IColliderShape.setContactOffset } */ - setMaterial(value: PhysXPhysicsMaterial): void { - this._pxMaterials[0] = value._pxMaterial; - this._pxShape.setMaterials(this._pxMaterials); + setContactOffset(offset: number): void { + this._contactOffset = offset; + this._pxShape.setContactOffset(offset); + + const controllers = this._controllers; + for (let i = 0, n = controllers.length; i < n; i++) { + controllers.get(i)._pxController.setContactOffset(offset); + } } /** - * {@inheritDoc IColliderShape.setUniqueID } + * {@inheritDoc IColliderShape.setMaterial } */ - setUniqueID(index: number): void { - this._id = index; - this._pxShape.setQueryFilterData(new PhysXPhysics._physX.PxFilterData(index, 0, 0, 0)); + setMaterial(value: PhysXPhysicsMaterial): void { + this._pxMaterials[0] = value._pxMaterial; + this._pxShape.setMaterials(this._pxMaterials); } /** @@ -108,13 +122,16 @@ export abstract class PhysXColliderShape implements IColliderShape { this._pxShape.setLocalPose(transform); } - protected _allocShape(material: PhysXPhysicsMaterial): void { + protected _initialize(material: PhysXPhysicsMaterial, id: number): void { + this._id = id; + this._pxMaterials[0] = material._pxMaterial; this._pxShape = PhysXPhysics._pxPhysics.createShape( this._pxGeometry, material._pxMaterial, false, new PhysXPhysics._physX.PxShapeFlags(this._shapeFlags) ); + this._pxShape.setQueryFilterData(new PhysXPhysics._physX.PxFilterData(id, 0, 0, 0)); } private _modifyFlag(flag: ShapeFlag, value: boolean): void { diff --git a/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts b/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts index 2cef1000fd..bfcead098e 100644 --- a/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts @@ -18,9 +18,8 @@ export class PhysXPlaneColliderShape extends PhysXColliderShape implements IPlan this._rotation.setValue(0, 0, PhysXColliderShape.halfSqrt, PhysXColliderShape.halfSqrt); this._pxGeometry = new PhysXPhysics._physX.PxPlaneGeometry(); - this._allocShape(material); + this._initialize(material, uniqueID); this._setLocalPose(); - this.setUniqueID(uniqueID); } /** diff --git a/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts b/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts index 91b3ace091..054f0f563c 100644 --- a/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts @@ -23,9 +23,8 @@ export class PhysXSphereColliderShape extends PhysXColliderShape implements ISph this._radius = radius; this._pxGeometry = new PhysXPhysics._physX.PxSphereGeometry(this._radius * this._maxScale); - this._allocShape(material); + this._initialize(material, uniqueID); this._setLocalPose(); - this.setUniqueID(uniqueID); } /** From 107e1577941286ace4c51e5f39e101f4e8ae7f4d Mon Sep 17 00:00:00 2001 From: AZhan Date: Thu, 16 Jun 2022 16:04:47 +0800 Subject: [PATCH 16/33] optimization camera code (#830) refactor: optimization camera code --- packages/core/src/Camera.ts | 49 ++----------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index baf066289b..cdf5364315 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -36,52 +36,6 @@ export class Camera extends Component { private static _inverseProjectionMatrixProperty = Shader.getPropertyByName("u_projInvMat"); private static _cameraPositionProperty = Shader.getPropertyByName("u_cameraPos"); - /** - * Compute the inverse of the rotation translation matrix. - * @param rotation - The rotation used to calculate matrix - * @param translation - The translation used to calculate matrix - * @param out - The calculated matrix - */ - private static _rotationTranslationInv(rotation: Quaternion, translation: Vector3, out: Matrix) { - const oe = out.elements; - const { x, y, z, w } = rotation; - let x2 = x + x; - let y2 = y + y; - let z2 = z + z; - - let xx = x * x2; - let xy = x * y2; - let xz = x * z2; - let yy = y * y2; - let yz = y * z2; - let zz = z * z2; - let wx = w * x2; - let wy = w * y2; - let wz = w * z2; - - oe[0] = 1 - (yy + zz); - oe[1] = xy + wz; - oe[2] = xz - wy; - oe[3] = 0; - - oe[4] = xy - wz; - oe[5] = 1 - (xx + zz); - oe[6] = yz + wx; - oe[7] = 0; - - oe[8] = xz + wy; - oe[9] = yz - wx; - oe[10] = 1 - (xx + yy); - oe[11] = 0; - - oe[12] = translation.x; - oe[13] = translation.y; - oe[14] = translation.z; - oe[15] = 1; - - out.invert(); - } - /** Shader data. */ readonly shaderData: ShaderData = new ShaderData(ShaderDataGroup.Camera); @@ -241,11 +195,12 @@ export class Camera extends Component { if (this._isViewMatrixDirty.flag) { this._isViewMatrixDirty.flag = false; // Ignore scale. - Camera._rotationTranslationInv( + Matrix.rotationTranslation( this._transform.worldRotationQuaternion, this._transform.worldPosition, this._viewMatrix ); + this._viewMatrix.invert(); } return this._viewMatrix; } From 0e26e2ca7c0796f4e7b0b47431ff31b9d422656f Mon Sep 17 00:00:00 2001 From: ChenMo Date: Tue, 28 Jun 2022 11:18:30 +0800 Subject: [PATCH 17/33] Refactor `cloneTo` to `copyFrom` for math library and rename `setValue` to `set` (#844) * feat: refactor `cloneTo` to `copyFrom` for math library * feat: rename `setValue` to `set` for math library --- .../src/2d/dynamic-atlas/DynamicTextAtlas.ts | 2 +- packages/core/src/2d/sprite/Sprite.ts | 40 ++-- packages/core/src/2d/sprite/SpriteMask.ts | 3 +- packages/core/src/2d/sprite/SpriteRenderer.ts | 11 +- packages/core/src/2d/text/TextRenderer.ts | 4 +- packages/core/src/Background.ts | 24 +- packages/core/src/Camera.ts | 8 +- .../src/RenderPipeline/BasicRenderPipeline.ts | 4 +- packages/core/src/Transform.ts | 64 +++--- packages/core/src/animation/AnimationCurve.ts | 3 +- .../animation/internal/AnimationCurveOwner.ts | 12 +- packages/core/src/env-probe/CubeProbe.ts | 28 +-- .../core/src/input/pointer/PointerManager.ts | 12 +- packages/core/src/lighting/AmbientLight.ts | 2 +- .../core/src/material/BlinnPhongMaterial.ts | 8 +- packages/core/src/material/PBRBaseMaterial.ts | 6 +- .../core/src/material/PBRSpecularMaterial.ts | 2 +- packages/core/src/material/UnlitMaterial.ts | 4 +- packages/core/src/mesh/BlendShapeManager.ts | 6 +- packages/core/src/mesh/MeshRenderer.ts | 4 +- packages/core/src/mesh/PrimitiveMesh.ts | 28 +-- packages/core/src/mesh/SkinnedMeshRenderer.ts | 2 +- .../core/src/physics/CharacterController.ts | 24 +- packages/core/src/physics/DynamicCollider.ts | 8 +- packages/core/src/physics/PhysicsManager.ts | 10 +- .../src/physics/shape/BoxColliderShape.ts | 2 +- .../core/src/physics/shape/ColliderShape.ts | 4 +- .../src/physics/shape/PlaneColliderShape.ts | 10 +- packages/core/src/shader/ShaderData.ts | 2 +- packages/core/src/shader/state/BlendState.ts | 2 +- packages/core/src/trail/TrailRenderer.ts | 4 +- packages/loader/src/EnvLoader.ts | 2 +- packages/loader/src/HDRLoader.ts | 10 +- packages/loader/src/SpriteAtlasLoader.ts | 18 +- .../gltf/extensions/KHR_lights_punctual.ts | 2 +- .../loader/src/gltf/parser/EntityParser.ts | 2 +- packages/loader/src/gltf/parser/MeshParser.ts | 10 +- packages/loader/src/gltf/parser/SkinParser.ts | 2 +- packages/math/src/BoundingBox.ts | 63 ++--- packages/math/src/BoundingFrustum.ts | 65 +++--- packages/math/src/BoundingSphere.ts | 21 +- packages/math/src/CollisionUtil.ts | 4 +- packages/math/src/Color.ts | 34 ++- packages/math/src/IClone.ts | 10 +- packages/math/src/ICopy.ts | 10 + packages/math/src/Matrix.ts | 215 +++++++++--------- packages/math/src/Matrix3x3.ts | 189 +++++++-------- packages/math/src/Plane.ts | 21 +- packages/math/src/Quaternion.ts | 114 +++++----- packages/math/src/Ray.ts | 4 +- packages/math/src/Rect.ts | 23 +- packages/math/src/SphericalHarmonics3.ts | 58 ++--- packages/math/src/Vector2.ts | 74 +++--- packages/math/src/Vector3.ts | 110 +++++---- packages/math/src/Vector4.ts | 90 ++++---- packages/physics-lite/src/LiteCollider.ts | 4 +- .../physics-lite/src/LitePhysicsManager.ts | 19 +- packages/physics-lite/src/LiteTransform.ts | 30 +-- .../src/shape/LiteBoxColliderShape.ts | 8 +- .../src/shape/LiteColliderShape.ts | 4 +- .../src/PhysXCharacterController.ts | 6 +- packages/physics-physx/src/PhysXCollider.ts | 4 +- .../physics-physx/src/PhysXDynamicCollider.ts | 8 +- .../physics-physx/src/PhysXPhysicsManager.ts | 4 +- .../src/shape/PhysXBoxColliderShape.ts | 6 +- .../src/shape/PhysXCapsuleColliderShape.ts | 8 +- .../src/shape/PhysXColliderShape.ts | 2 +- .../src/shape/PhysXPlaneColliderShape.ts | 10 +- .../src/shape/PhysXSphereColliderShape.ts | 2 +- packages/rhi-webgl/src/WebCanvas.ts | 4 +- packages/rhi-webgl/src/WebGLRenderer.ts | 4 +- 71 files changed, 836 insertions(+), 781 deletions(-) create mode 100644 packages/math/src/ICopy.ts diff --git a/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts b/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts index 2c89a13c37..89d91ee39b 100644 --- a/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts +++ b/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts @@ -65,7 +65,7 @@ export class DynamicTextAtlas { const { _width, _height } = this; const region = DynamicTextAtlas._region; - region.setValue(this._curX / _width, this._curY / _height, width / _width, height / _height); + region.set(this._curX / _width, this._curY / _height, width / _width, height / _height); // destroy origin texture. sprite.texture && sprite.texture.destroy(); diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index e32f826833..d9075392e3 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -85,7 +85,7 @@ export class Sprite extends RefObject { set atlasRegion(value: Rect) { const x = MathUtil.clamp(value.x, 0, 1); const y = MathUtil.clamp(value.y, 0, 1); - this._atlasRegion.setValue(x, y, MathUtil.clamp(value.width, 0, 1 - x), MathUtil.clamp(value.height, 0, 1 - y)); + this._atlasRegion.set(x, y, MathUtil.clamp(value.width, 0, 1 - x), MathUtil.clamp(value.height, 0, 1 - y)); this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); } @@ -99,7 +99,7 @@ export class Sprite extends RefObject { set atlasRegionOffset(value: Vector4) { const x = MathUtil.clamp(value.x, 0, 1); const y = MathUtil.clamp(value.y, 0, 1); - this._atlasRegionOffset.setValue(x, y, MathUtil.clamp(value.z, 0, 1 - x), MathUtil.clamp(value.w, 0, 1 - y)); + this._atlasRegionOffset.set(x, y, MathUtil.clamp(value.z, 0, 1 - x), MathUtil.clamp(value.w, 0, 1 - y)); this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); } @@ -114,7 +114,7 @@ export class Sprite extends RefObject { const pivot = this._pivot; const { x, y } = value; if (pivot === value || pivot.x !== x || pivot.y !== y) { - pivot.setValue(x, y); + pivot.set(x, y); this._setDirtyFlagTrue(DirtyFlag.positions); } } @@ -130,7 +130,7 @@ export class Sprite extends RefObject { const region = this._region; const x = MathUtil.clamp(value.x, 0, 1); const y = MathUtil.clamp(value.y, 0, 1); - region.setValue(x, y, MathUtil.clamp(value.width, 0, 1 - x), MathUtil.clamp(value.height, 0, 1 - y)); + region.set(x, y, MathUtil.clamp(value.width, 0, 1 - x), MathUtil.clamp(value.height, 0, 1 - y)); this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); } @@ -171,8 +171,8 @@ export class Sprite extends RefObject { this._texture = texture; this._pixelsPerUnit = pixelsPerUnit; - region && region.cloneTo(this._region); - pivot && pivot.cloneTo(this._pivot); + region && this._region.copyFrom(region); + pivot && this._pivot.copyFrom(pivot); this._triangles = Sprite._rectangleTriangles; } @@ -192,8 +192,8 @@ export class Sprite extends RefObject { ); cloneSprite._assetID = this._assetID; cloneSprite._atlasRotated = this._atlasRotated; - this._atlasRegion.cloneTo(cloneSprite._atlasRegion); - this._atlasRegionOffset.cloneTo(cloneSprite._atlasRegionOffset); + cloneSprite._atlasRegion.copyFrom(this._atlasRegion); + cloneSprite._atlasRegionOffset.copyFrom(this._atlasRegionOffset); return cloneSprite; } @@ -237,21 +237,21 @@ export class Sprite extends RefObject { // Assign values ​​to _positions const positions = this._positions; // Top-left. - positions[0].setValue(left, top); + positions[0].set(left, top); // Top-right. - positions[1].setValue(right, top); + positions[1].set(right, top); // Bottom-right. - positions[2].setValue(right, bottom); + positions[2].set(right, bottom); // Bottom-left. - positions[3].setValue(left, bottom); + positions[3].set(left, bottom); // Update bounds. - bounds.min.setValue(left, bottom, 0); - bounds.max.setValue(right, top, 0); + bounds.min.set(left, bottom, 0); + bounds.max.set(right, top, 0); } else { // Update bounds. - bounds.min.setValue(0, 0, 0); - bounds.max.setValue(0, 0, 0); + bounds.min.set(0, 0, 0); + bounds.max.set(0, 0, 0); } } @@ -278,13 +278,13 @@ export class Sprite extends RefObject { const right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; const bottom = atlasRegionH + atlasRegionY - Math.max(regionY - offsetBottom, 0) * realHeight; // Top-left. - uv[0].setValue(left, top); + uv[0].set(left, top); // Top-right. - uv[1].setValue(right, top); + uv[1].set(right, top); // Bottom-right. - uv[2].setValue(right, bottom); + uv[2].set(right, bottom); // Bottom-left. - uv[3].setValue(left, bottom); + uv[3].set(left, bottom); } this._setDirtyFlagFalse(DirtyFlag.all); } diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 23ce3d2c79..4ca887862b 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -8,7 +8,6 @@ import { Renderer } from "../../Renderer"; import { SpriteMaskElement } from "../../RenderPipeline/SpriteMaskElement"; import { Shader } from "../../shader/Shader"; import { ShaderProperty } from "../../shader/ShaderProperty"; -import { UpdateFlag } from "../../UpdateFlag"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { Sprite } from "./Sprite"; @@ -119,7 +118,7 @@ export class SpriteMask extends Renderer implements ICustomClone { for (let i = 0, n = positions.length; i < n; i++) { const curVertexPos = localPositions[i]; - localVertexPos.setValue(curVertexPos.x, curVertexPos.y, 0); + localVertexPos.set(curVertexPos.x, curVertexPos.y, 0); Vector3.transformToVec3(localVertexPos, worldMatrix, positions[i]); } diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index f916ac5993..d3d4aff53a 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -8,7 +8,6 @@ import { Renderer } from "../../Renderer"; import { CompareFunction } from "../../shader/enums/CompareFunction"; import { Shader } from "../../shader/Shader"; import { ShaderProperty } from "../../shader/ShaderProperty"; -import { UpdateFlag } from "../../UpdateFlag"; import { SpriteMaskInteraction } from "../enums/SpriteMaskInteraction"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { Sprite } from "./Sprite"; @@ -19,7 +18,7 @@ import { Sprite } from "./Sprite"; export class SpriteRenderer extends Renderer implements ICustomClone { /** @internal */ static _textureProperty: ShaderProperty = Shader.getPropertyByName("u_spriteTexture"); - + private static _tempVec3: Vector3 = new Vector3(); /** @internal temp solution. */ @@ -80,7 +79,7 @@ export class SpriteRenderer extends Renderer implements ICustomClone { set color(value: Color) { if (this._color !== value) { - value.cloneTo(this._color); + this._color.copyFrom(value); } } @@ -173,7 +172,7 @@ export class SpriteRenderer extends Renderer implements ICustomClone { for (let i = 0, n = _positions.length; i < n; i++) { const curVertexPos = localPositions[i]; - localVertexPos.setValue(flipX ? -curVertexPos.x : curVertexPos.x, flipY ? -curVertexPos.y : curVertexPos.y, 0); + localVertexPos.set(flipX ? -curVertexPos.x : curVertexPos.x, flipY ? -curVertexPos.y : curVertexPos.y, 0); Vector3.transformToVec3(localVertexPos, worldMatrix, _positions[i]); } @@ -264,8 +263,8 @@ export class SpriteRenderer extends Renderer implements ICustomClone { BoundingBox.transform(localBounds, worldMatrix, worldBounds); } } else { - worldBounds.min.setValue(0, 0, 0); - worldBounds.max.setValue(0, 0, 0); + worldBounds.min.set(0, 0, 0); + worldBounds.max.set(0, 0, 0); } } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index f356e10609..c292ac3ae3 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -75,7 +75,7 @@ export class TextRenderer extends Renderer { set color(value: Color) { if (this._color !== value) { - value.cloneTo(this._color); + this._color.copyFrom(value); } } @@ -446,7 +446,7 @@ export class TextRenderer extends Renderer { const { _positions } = this; for (let i = 0, n = _positions.length; i < n; i++) { const curVertexPos = localPositions[i]; - localVertexPos.setValue(curVertexPos.x, curVertexPos.y, 0); + localVertexPos.set(curVertexPos.x, curVertexPos.y, 0); Vector3.transformToVec3(localVertexPos, worldMatrix, _positions[i]); } } diff --git a/packages/core/src/Background.ts b/packages/core/src/Background.ts index c6916f5b45..04a3c9eae2 100644 --- a/packages/core/src/Background.ts +++ b/packages/core/src/Background.ts @@ -92,24 +92,24 @@ export class Background { switch (this._textureFillMode) { case BackgroundTextureFillMode.Fill: - positions[0].setValue(-1, -1, 1); - positions[1].setValue(1, -1, 1); - positions[2].setValue(-1, 1, 1); - positions[3].setValue(1, 1, 1); + positions[0].set(-1, -1, 1); + positions[1].set(1, -1, 1); + positions[2].set(-1, 1, 1); + positions[3].set(1, 1, 1); break; case BackgroundTextureFillMode.AspectFitWidth: const fitWidthScale = (this._texture.height * width) / this.texture.width / height; - positions[0].setValue(-1, -fitWidthScale, 1); - positions[1].setValue(1, -fitWidthScale, 1); - positions[2].setValue(-1, fitWidthScale, 1); - positions[3].setValue(1, fitWidthScale, 1); + positions[0].set(-1, -fitWidthScale, 1); + positions[1].set(1, -fitWidthScale, 1); + positions[2].set(-1, fitWidthScale, 1); + positions[3].set(1, fitWidthScale, 1); break; case BackgroundTextureFillMode.AspectFitHeight: const fitHeightScale = (this._texture.width * height) / this.texture.height / width; - positions[0].setValue(-fitHeightScale, -1, 1); - positions[1].setValue(fitHeightScale, -1, 1); - positions[2].setValue(-fitHeightScale, 1, 1); - positions[3].setValue(fitHeightScale, 1, 1); + positions[0].set(-fitHeightScale, -1, 1); + positions[1].set(fitHeightScale, -1, 1); + positions[2].set(-fitHeightScale, 1, 1); + positions[3].set(fitHeightScale, 1, 1); break; } _backgroundTextureMesh.setPositions(positions); diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index cdf5364315..0b680020ab 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -1,4 +1,4 @@ -import { BoundingFrustum, MathUtil, Matrix, Quaternion, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; +import { BoundingFrustum, MathUtil, Matrix, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; import { Logger } from "./base"; import { BoolUpdateFlag } from "./BoolUpdateFlag"; import { deepClone, ignoreClone } from "./clone/CloneManager"; @@ -159,7 +159,7 @@ export class Camera extends Component { set viewport(value: Vector4) { if (value !== this._viewport) { - value.cloneTo(this._viewport); + this._viewport.copyFrom(value); } this._projMatChange(); } @@ -313,7 +313,7 @@ export class Camera extends Component { Vector3.transformToVec4(cameraPoint, this.projectionMatrix, viewportPoint); const w = viewportPoint.w; - out.setValue((viewportPoint.x / w + 1.0) * 0.5, (1.0 - viewportPoint.y / w) * 0.5, -cameraPoint.z); + out.set((viewportPoint.x / w + 1.0) * 0.5, (1.0 - viewportPoint.y / w) * 0.5, -cameraPoint.z); return out; } @@ -494,7 +494,7 @@ export class Camera extends Component { // Depth is a normalized value, 0 is nearPlane, 1 is farClipPlane. // Transform to clipping space matrix const clipPoint = MathTemp.tempVec3; - clipPoint.setValue(x * 2 - 1, 1 - y * 2, z * 2 - 1); + clipPoint.set(x * 2 - 1, 1 - y * 2, z * 2 - 1); Vector3.transformCoordinate(clipPoint, invViewProjMat, out); return out; } diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 16b4c98b80..ad87cb5eb2 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -224,7 +224,7 @@ export class BasicRenderPipeline { (this._lastCanvasSize.x !== canvas.width || this._lastCanvasSize.y !== canvas.height) && background._textureFillMode !== BackgroundTextureFillMode.Fill ) { - this._lastCanvasSize.setValue(canvas.width, canvas.height); + this._lastCanvasSize.set(canvas.width, canvas.height); background._resizeBackgroundTexture(); } @@ -255,7 +255,7 @@ export class BasicRenderPipeline { ShaderMacroCollection.unionCollection(camera._globalShaderMacro, shaderData._macroCollection, compileMacros); const { viewMatrix, projectionMatrix } = camera; - viewMatrix.cloneTo(_matrix); + _matrix.copyFrom(viewMatrix); const e = _matrix.elements; e[12] = e[13] = e[14] = 0; Matrix.multiply(projectionMatrix, _matrix, _matrix); diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index 23cc1ee580..eb1732740b 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -3,7 +3,6 @@ import { BoolUpdateFlag } from "./BoolUpdateFlag"; import { deepClone, ignoreClone } from "./clone/CloneManager"; import { Component } from "./Component"; import { Entity } from "./Entity"; -import { UpdateFlag } from "./UpdateFlag"; import { UpdateFlagManager } from "./UpdateFlagManager"; /** @@ -19,7 +18,6 @@ export class Transform extends Component { private static _tempMat32: Matrix3x3 = new Matrix3x3(); private static _tempMat41: Matrix = new Matrix(); private static _tempMat42: Matrix = new Matrix(); - private static _tempMat43: Matrix = new Matrix(); @deepClone private _position: Vector3 = new Vector3(); @@ -59,7 +57,7 @@ export class Transform extends Component { set position(value: Vector3) { if (this._position !== value) { - value.cloneTo(this._position); + this._position.copyFrom(value); } } @@ -74,7 +72,7 @@ export class Transform extends Component { if (this._getParentTransform()) { this.worldMatrix.getTranslation(worldPosition); } else { - this._position.cloneTo(worldPosition); + worldPosition.copyFrom(this._position); } //@ts-ignore worldPosition._onValueChanged = this._onWorldPositionChanged; @@ -86,7 +84,7 @@ export class Transform extends Component { set worldPosition(value: Vector3) { if (this._worldPosition !== value) { - value.cloneTo(this._worldPosition); + this._worldPosition.copyFrom(value); } } @@ -111,7 +109,7 @@ export class Transform extends Component { set rotation(value: Vector3) { if (this._rotation !== value) { - value.cloneTo(this._rotation); + this._rotation.copyFrom(value); } } @@ -135,7 +133,7 @@ export class Transform extends Component { set worldRotation(value: Vector3) { if (this._worldRotation !== value) { - value.cloneTo(this._worldRotation); + this._worldRotation.copyFrom(value); } } @@ -163,7 +161,7 @@ export class Transform extends Component { set rotationQuaternion(value: Quaternion) { if (this._rotationQuaternion !== value) { if (value.normalized) { - value.cloneTo(this._rotationQuaternion); + this._rotationQuaternion.copyFrom(value); } else { Quaternion.normalize(value, this._rotationQuaternion); } @@ -184,7 +182,7 @@ export class Transform extends Component { if (parent != null) { Quaternion.multiply(parent.worldRotationQuaternion, this.rotationQuaternion, worldRotationQuaternion); } else { - this.rotationQuaternion.cloneTo(worldRotationQuaternion); + worldRotationQuaternion.copyFrom(this.rotationQuaternion); } //@ts-ignore worldRotationQuaternion._onValueChanged = this._onWorldRotationQuaternionChanged; @@ -196,7 +194,7 @@ export class Transform extends Component { set worldRotationQuaternion(value: Quaternion) { if (this._worldRotationQuaternion !== value) { if (value.normalized) { - value.cloneTo(this._worldRotationQuaternion); + this._worldRotationQuaternion.copyFrom(value); } else { Quaternion.normalize(value, this._worldRotationQuaternion); } @@ -213,7 +211,7 @@ export class Transform extends Component { set scale(value: Vector3) { if (this._scale !== value) { - value.cloneTo(this._scale); + this._scale.copyFrom(value); } } @@ -227,9 +225,9 @@ export class Transform extends Component { if (this._getParentTransform()) { const scaleMat = this._getScaleMatrix(); const e = scaleMat.elements; - this._lossyWorldScale.setValue(e[0], e[4], e[8]); + this._lossyWorldScale.set(e[0], e[4], e[8]); } else { - this._scale.cloneTo(this._lossyWorldScale); + this._lossyWorldScale.copyFrom(this._scale); } this._setDirtyFlagFalse(TransformFlag.WorldScale); } @@ -250,7 +248,7 @@ export class Transform extends Component { set localMatrix(value: Matrix) { if (this._localMatrix !== value) { - value.cloneTo(this._localMatrix); + this._localMatrix.copyFrom(value); } this._localMatrix.decompose(this._position, this._rotationQuaternion, this._scale); @@ -270,7 +268,7 @@ export class Transform extends Component { if (parent) { Matrix.multiply(parent.worldMatrix, this.localMatrix, this._worldMatrix); } else { - this.localMatrix.cloneTo(this._worldMatrix); + this._worldMatrix.copyFrom(this.localMatrix); } this._setDirtyFlagFalse(TransformFlag.WorldMatrix); } @@ -279,14 +277,14 @@ export class Transform extends Component { set worldMatrix(value: Matrix) { if (this._worldMatrix !== value) { - value.cloneTo(this._worldMatrix); + this._worldMatrix.copyFrom(value); } const parent = this._getParentTransform(); if (parent) { Matrix.invert(parent.worldMatrix, Transform._tempMat42); Matrix.multiply(value, Transform._tempMat42, this._localMatrix); } else { - value.cloneTo(this._localMatrix); + this._localMatrix.copyFrom(value); } this.localMatrix = this._localMatrix; this._setDirtyFlagFalse(TransformFlag.WorldMatrix); @@ -329,7 +327,7 @@ export class Transform extends Component { * @param z - Z coordinate */ setPosition(x: number, y: number, z: number): void { - this._position.setValue(x, y, z); + this._position.set(x, y, z); } /** @@ -340,7 +338,7 @@ export class Transform extends Component { * @param z - The angle of rotation around the Z axis */ setRotation(x: number, y: number, z: number): void { - this._rotation.setValue(x, y, z); + this._rotation.set(x, y, z); } /** @@ -351,7 +349,7 @@ export class Transform extends Component { * @param w - W component of quaternion */ setRotationQuaternion(x: number, y: number, z: number, w: number): void { - this._rotationQuaternion.setValue(x, y, z, w); + this._rotationQuaternion.set(x, y, z, w); } /** @@ -361,7 +359,7 @@ export class Transform extends Component { * @param z - Scaling along Z axis */ setScale(x: number, y: number, z: number): void { - this._scale.setValue(x, y, z); + this._scale.set(x, y, z); } /** @@ -371,7 +369,7 @@ export class Transform extends Component { * @param z - Z coordinate */ setWorldPosition(x: number, y: number, z: number): void { - this._worldPosition.setValue(x, y, z); + this._worldPosition.set(x, y, z); } /** @@ -381,7 +379,7 @@ export class Transform extends Component { * @param z - The angle of rotation around the Z axis */ setWorldRotation(x: number, y: number, z: number): void { - this._worldRotation.setValue(x, y, z); + this._worldRotation.set(x, y, z); } /** @@ -392,7 +390,7 @@ export class Transform extends Component { * @param w - W component of quaternion */ setWorldRotationQuaternion(x: number, y: number, z: number, w: number): void { - this._worldRotationQuaternion.setValue(x, y, z, w); + this._worldRotationQuaternion.set(x, y, z, w); } /** @@ -402,7 +400,7 @@ export class Transform extends Component { */ getWorldForward(forward: Vector3): Vector3 { const e = this.worldMatrix.elements; - forward.setValue(-e[8], -e[9], -e[10]); + forward.set(-e[8], -e[9], -e[10]); return forward.normalize(); } @@ -413,7 +411,7 @@ export class Transform extends Component { */ getWorldRight(right: Vector3): Vector3 { const e = this.worldMatrix.elements; - right.setValue(e[0], e[1], e[2]); + right.set(e[0], e[1], e[2]); return right.normalize(); } @@ -424,11 +422,11 @@ export class Transform extends Component { */ getWorldUp(up: Vector3): Vector3 { const e = this.worldMatrix.elements; - up.setValue(e[4], e[5], e[6]); + up.set(e[4], e[5], e[6]); return up.normalize(); } - /** + /** * Translate in the direction and distance of the translation. * @param translation - Direction and distance of translation * @param relativeToLocal - Is relative to the local coordinate system @@ -452,7 +450,7 @@ export class Transform extends Component { ): void { if (typeof translationOrX === "number") { const translate = Transform._tempVec30; - translate.setValue(translationOrX, relativeToLocalOrY, z); + translate.set(translationOrX, relativeToLocalOrY, z); this._translate(translate, relativeToLocal); } else { this._translate(translationOrX, relativeToLocalOrY); @@ -518,7 +516,7 @@ export class Transform extends Component { if (worldUp) { Vector3.cross(worldUp, zAxis, xAxis); } else { - xAxis.setValue(zAxis.z, 0, -zAxis.x); + xAxis.set(zAxis.z, 0, -zAxis.x); } axisLen = xAxis.length(); if (axisLen <= MathUtil.zeroTolerance) { @@ -685,7 +683,7 @@ export class Transform extends Component { const invRotationMat = Transform._tempMat30; const worldRotScaMat = Transform._tempMat31; const scaMat = Transform._tempMat32; - worldRotScaMat.setValueByMatrix(this.worldMatrix); + worldRotScaMat.copyFromMatrix(this.worldMatrix); Quaternion.invert(this.worldRotationQuaternion, invRotation); Matrix3x3.rotationQuaternion(invRotation, invRotationMat); Matrix3x3.multiply(invRotationMat, worldRotScaMat, scaMat); @@ -750,7 +748,7 @@ export class Transform extends Component { Matrix.invert(parent.worldMatrix, Transform._tempMat41); Vector3.transformCoordinate(worldPosition, Transform._tempMat41, this._position); } else { - worldPosition.cloneTo(this._position); + this._position.copyFrom(worldPosition); } this._setDirtyFlagFalse(TransformFlag.WorldPosition); } @@ -786,7 +784,7 @@ export class Transform extends Component { Quaternion.invert(parent.worldRotationQuaternion, invParentQuaternion); Quaternion.multiply(invParentQuaternion, worldRotationQuaternion, this._rotationQuaternion); } else { - worldRotationQuaternion.cloneTo(this._rotationQuaternion); + this._rotationQuaternion.copyFrom(worldRotationQuaternion); } this._setDirtyFlagFalse(TransformFlag.WorldQuat); } diff --git a/packages/core/src/animation/AnimationCurve.ts b/packages/core/src/animation/AnimationCurve.ts index 0007244b8d..029e9aaee6 100644 --- a/packages/core/src/animation/AnimationCurve.ts +++ b/packages/core/src/animation/AnimationCurve.ts @@ -1,4 +1,3 @@ -import { IClone } from "@oasis-engine/design"; import { Quaternion, Vector2, Vector3, Vector4 } from "@oasis-engine/math"; import { InterpolableValueType } from "./enums/InterpolableValueType"; import { InterpolationType } from "./enums/InterpolationType"; @@ -242,7 +241,7 @@ export class AnimationCurve { case InterpolableValueType.Vector3: case InterpolableValueType.Vector4: case InterpolableValueType.Quaternion: - (keys[frameIndex].value as IClone).cloneTo(out); + (out).copyFrom(keys[frameIndex].value); return out; } } diff --git a/packages/core/src/animation/internal/AnimationCurveOwner.ts b/packages/core/src/animation/internal/AnimationCurveOwner.ts index 11ef24a3b7..d6e142f516 100644 --- a/packages/core/src/animation/internal/AnimationCurveOwner.ts +++ b/packages/core/src/animation/internal/AnimationCurveOwner.ts @@ -54,13 +54,13 @@ export class AnimationCurveOwner { saveDefaultValue(): void { switch (this.property) { case AnimationProperty.Position: - this.target.transform.position.cloneTo(this.defaultValue); + (this.defaultValue).copyFrom(this.target.transform.position); break; case AnimationProperty.Rotation: - this.target.transform.rotationQuaternion.cloneTo(this.defaultValue); + (this.defaultValue).copyFrom(this.target.transform.rotationQuaternion); break; case AnimationProperty.Scale: - this.target.transform.scale.cloneTo(this.defaultValue); + (this.defaultValue).copyFrom(this.target.transform.scale); break; case AnimationProperty.BlendShapeWeights: const { blendShapeWeights } = this.component; @@ -75,13 +75,13 @@ export class AnimationCurveOwner { saveFixedPoseValue(): void { switch (this.property) { case AnimationProperty.Position: - this.target.transform.position.cloneTo(this.fixedPoseValue); + (this.fixedPoseValue).copyFrom(this.target.transform.position); break; case AnimationProperty.Rotation: - this.target.transform.rotationQuaternion.cloneTo(this.fixedPoseValue); + (this.fixedPoseValue).copyFrom(this.target.transform.rotationQuaternion); break; case AnimationProperty.Scale: - this.target.transform.scale.cloneTo(this.fixedPoseValue); + (this.fixedPoseValue).copyFrom(this.target.transform.scale); break; case AnimationProperty.BlendShapeWeights: const { blendShapeWeights } = this.component; diff --git a/packages/core/src/env-probe/CubeProbe.ts b/packages/core/src/env-probe/CubeProbe.ts index 9ddb552b28..c1e936a73c 100644 --- a/packages/core/src/env-probe/CubeProbe.ts +++ b/packages/core/src/env-probe/CubeProbe.ts @@ -47,7 +47,7 @@ export class CubeProbe extends Probe { * Store original camera parameters. */ private _storeCamera(camera: Camera) { - camera.viewMatrix.cloneTo(this.oriViewMatrix); + this.oriViewMatrix.copyFrom(camera.viewMatrix); this._oriFieldOfView = camera.fieldOfView; } @@ -55,7 +55,7 @@ export class CubeProbe extends Probe { * Restore camera parameters. */ private _restoreCamera(camera: Camera) { - this.oriViewMatrix.cloneTo(camera.viewMatrix); + camera.viewMatrix.copyFrom(this.oriViewMatrix); camera.fieldOfView = this._oriFieldOfView; } @@ -66,33 +66,33 @@ export class CubeProbe extends Probe { switch (faceIndex) { // positive_x case 0: - cacheUp.setValue(0, -1, 0); - cacheDir.setValue(1, 0, 0); + cacheUp.set(0, -1, 0); + cacheDir.set(1, 0, 0); break; // negative_x case 1: - cacheUp.setValue(0, -1, 0); - cacheDir.setValue(-1, 0, 0); + cacheUp.set(0, -1, 0); + cacheDir.set(-1, 0, 0); break; // positive_y case 2: - cacheUp.setValue(0, 0, 1); - cacheDir.setValue(0, 1, 0); + cacheUp.set(0, 0, 1); + cacheDir.set(0, 1, 0); break; // negative_y case 3: - cacheUp.setValue(0, 0, -1); - cacheDir.setValue(0, -1, 0); + cacheUp.set(0, 0, -1); + cacheDir.set(0, -1, 0); break; // positive_z case 4: - cacheUp.setValue(0, -1, 0); - cacheDir.setValue(0, 0, 1); + cacheUp.set(0, -1, 0); + cacheDir.set(0, 0, 1); break; // negative_z case 5: - cacheUp.setValue(0, -1, 0); - cacheDir.setValue(0, 0, -1); + cacheUp.set(0, -1, 0); + cacheDir.set(0, 0, -1); break; } diff --git a/packages/core/src/input/pointer/PointerManager.ts b/packages/core/src/input/pointer/PointerManager.ts index 5fef1f00dc..4ce88b4dc0 100644 --- a/packages/core/src/input/pointer/PointerManager.ts +++ b/packages/core/src/input/pointer/PointerManager.ts @@ -142,7 +142,7 @@ export class PointerManager { } pointer._uniqueID = pointerId; pointer._needUpdate = true; - pointer.position.setValue(x, y); + pointer.position.set(x, y); pointer.phase = phase; pointers.splice(i, 0, pointer); } @@ -154,7 +154,7 @@ export class PointerManager { private _updatePointer(pointerIndex: number, x: number, y: number, phase: PointerPhase): void { const updatedPointer = this._pointers[pointerIndex]; - updatedPointer.position.setValue(x, y); + updatedPointer.position.set(x, y); updatedPointer._needUpdate = true; updatedPointer.phase = phase; } @@ -209,14 +209,14 @@ export class PointerManager { if (activePointerCount === 0) { // Get the pointer coordinates when leaving, and use it to correctly dispatch the click event. const lastNativeEvent = nativeEvents[nativeEventsLen - 1]; - currentPosition.setValue(lastNativeEvent.offsetX * pixelRatioWidth, lastNativeEvent.offsetY * pixelRatioHeight); + currentPosition.set(lastNativeEvent.offsetX * pixelRatioWidth, lastNativeEvent.offsetY * pixelRatioHeight); } else { - currentPosition.setValue(0, 0); + currentPosition.set(0, 0); for (let i = 0; i < pointerCount; i++) { const pointer = pointers[i]; const { position } = pointer; if (pointer._needUpdate) { - position.setValue(position.x * pixelRatioWidth, position.y * pixelRatioHeight); + position.set(position.x * pixelRatioWidth, position.y * pixelRatioHeight); pointer._needUpdate = false; } currentPosition.add(position); @@ -240,7 +240,7 @@ export class PointerManager { } const { x: vpX, y: vpY, z: vpW, w: vpH } = camera.viewport; if (x >= vpX && y >= vpY && x - vpX <= vpW && y - vpY <= vpH) { - point.setValue((x - vpX) / vpW, (y - vpY) / vpH); + point.set((x - vpX) / vpW, (y - vpY) / vpH); // TODO: Only check which colliders have listened to the input. if (this._engine.physicsManager.raycast(camera.viewportPointToRay(point, ray), hitResult)) { return hitResult.entity; diff --git a/packages/core/src/lighting/AmbientLight.ts b/packages/core/src/lighting/AmbientLight.ts index 8d2b6cc8ef..d6ab55236a 100644 --- a/packages/core/src/lighting/AmbientLight.ts +++ b/packages/core/src/lighting/AmbientLight.ts @@ -79,7 +79,7 @@ export class AmbientLight { set diffuseSolidColor(value: Color) { if (value !== this._diffuseSolidColor) { - value.cloneTo(this._diffuseSolidColor); + this._diffuseSolidColor.copyFrom(value); } } diff --git a/packages/core/src/material/BlinnPhongMaterial.ts b/packages/core/src/material/BlinnPhongMaterial.ts index 8b9cb34f62..9f82d3df11 100644 --- a/packages/core/src/material/BlinnPhongMaterial.ts +++ b/packages/core/src/material/BlinnPhongMaterial.ts @@ -22,7 +22,7 @@ export class BlinnPhongMaterial extends BaseMaterial { set baseColor(value: Color) { const baseColor = this.shaderData.getColor(BlinnPhongMaterial._baseColorProp); if (value !== baseColor) { - value.cloneTo(baseColor); + baseColor.copyFrom(value); } } @@ -52,7 +52,7 @@ export class BlinnPhongMaterial extends BaseMaterial { set specularColor(value: Color) { const specularColor = this.shaderData.getColor(BlinnPhongMaterial._specularColorProp); if (value !== specularColor) { - value.cloneTo(specularColor); + specularColor.copyFrom(value); } } @@ -82,7 +82,7 @@ export class BlinnPhongMaterial extends BaseMaterial { set emissiveColor(value: Color) { const emissiveColor = this.shaderData.getColor(BlinnPhongMaterial._emissiveColorProp); if (value !== emissiveColor) { - value.cloneTo(emissiveColor); + emissiveColor.copyFrom(value); } } @@ -150,7 +150,7 @@ export class BlinnPhongMaterial extends BaseMaterial { set tilingOffset(value: Vector4) { const tilingOffset = this.shaderData.getVector4(BlinnPhongMaterial._tilingOffsetProp); if (value !== tilingOffset) { - value.cloneTo(tilingOffset); + tilingOffset.copyFrom(value); } } diff --git a/packages/core/src/material/PBRBaseMaterial.ts b/packages/core/src/material/PBRBaseMaterial.ts index 0dddcc2d08..7888cf012e 100644 --- a/packages/core/src/material/PBRBaseMaterial.ts +++ b/packages/core/src/material/PBRBaseMaterial.ts @@ -30,7 +30,7 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set baseColor(value: Color) { const baseColor = this.shaderData.getColor(PBRBaseMaterial._baseColorProp); if (value !== baseColor) { - value.cloneTo(baseColor); + baseColor.copyFrom(value); } } @@ -87,7 +87,7 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set emissiveColor(value: Color) { const emissiveColor = this.shaderData.getColor(PBRBaseMaterial._emissiveColorProp); if (value !== emissiveColor) { - value.cloneTo(emissiveColor); + emissiveColor.copyFrom(value); } } @@ -159,7 +159,7 @@ export abstract class PBRBaseMaterial extends BaseMaterial { set tilingOffset(value: Vector4) { const tilingOffset = this.shaderData.getVector4(PBRBaseMaterial._tilingOffsetProp); if (value !== tilingOffset) { - value.cloneTo(tilingOffset); + tilingOffset.copyFrom(value); } } diff --git a/packages/core/src/material/PBRSpecularMaterial.ts b/packages/core/src/material/PBRSpecularMaterial.ts index d4b0300fa5..16790a3e87 100644 --- a/packages/core/src/material/PBRSpecularMaterial.ts +++ b/packages/core/src/material/PBRSpecularMaterial.ts @@ -24,7 +24,7 @@ export class PBRSpecularMaterial extends PBRBaseMaterial { set specularColor(value: Color) { const specularColor = this.shaderData.getColor(PBRSpecularMaterial._specularColorProp); if (value !== specularColor) { - value.cloneTo(specularColor); + specularColor.copyFrom(value); } } diff --git a/packages/core/src/material/UnlitMaterial.ts b/packages/core/src/material/UnlitMaterial.ts index c74334033b..ec02b5dd2d 100644 --- a/packages/core/src/material/UnlitMaterial.ts +++ b/packages/core/src/material/UnlitMaterial.ts @@ -18,7 +18,7 @@ export class UnlitMaterial extends BaseMaterial { set baseColor(value: Color) { const baseColor = this.shaderData.getColor(UnlitMaterial._baseColorProp); if (value !== baseColor) { - value.cloneTo(baseColor); + baseColor.copyFrom(value); } } @@ -48,7 +48,7 @@ export class UnlitMaterial extends BaseMaterial { set tilingOffset(value: Vector4) { const tilingOffset = this.shaderData.getVector4(UnlitMaterial._tilingOffsetProp); if (value !== tilingOffset) { - value.cloneTo(tilingOffset); + tilingOffset.copyFrom(value); } } diff --git a/packages/core/src/mesh/BlendShapeManager.ts b/packages/core/src/mesh/BlendShapeManager.ts index c21e2bf2c1..13a145fc60 100644 --- a/packages/core/src/mesh/BlendShapeManager.ts +++ b/packages/core/src/mesh/BlendShapeManager.ts @@ -223,7 +223,7 @@ export class BlendShapeManager { } else { this._createVertexBuffers(vertexCount, noLongerAccessible); } - this._lastCreateHostInfo.setValue(this._blendShapeCount, +this._useBlendNormal, +this._useBlendTangent); + this._lastCreateHostInfo.set(this._blendShapeCount, +this._useBlendNormal, +this._useBlendTangent); } if (this._needUpdateData()) { if (useTexture) { @@ -319,7 +319,7 @@ export class BlendShapeManager { this._vertices = new Float32Array(blendShapeCount * textureWidth * textureHeight * 4); this._vertexTexture = blendShapeDataTexture; - this._dataTextureInfo.setValue(vertexPixelStride, textureWidth, textureHeight); + this._dataTextureInfo.set(vertexPixelStride, textureWidth, textureHeight); } /** @@ -353,7 +353,7 @@ export class BlendShapeManager { let storeInfo = storeInfos[i]; storeInfo || (storeInfos[i] = storeInfo = new Vector2()); - storeInfo.setValue(bufferIndex + 1, indexInBuffer * blendShapeByteStride); // BlendShape buffer is start from 1 + storeInfo.set(bufferIndex + 1, indexInBuffer * blendShapeByteStride); // BlendShape buffer is start from 1 const { deltaPositions } = endFrame; for (let j = 0; j < vertexCount; j++) { diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index fce3566518..ae439b8834 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -138,8 +138,8 @@ export class MeshRenderer extends Renderer implements ICustomClone { const worldMatrix = this._entity.transform.worldMatrix; BoundingBox.transform(localBounds, worldMatrix, worldBounds); } else { - worldBounds.min.setValue(0, 0, 0); - worldBounds.max.setValue(0, 0, 0); + worldBounds.min.set(0, 0, 0); + worldBounds.max.set(0, 0, 0); } } } diff --git a/packages/core/src/mesh/PrimitiveMesh.ts b/packages/core/src/mesh/PrimitiveMesh.ts index d972bdae3b..e373ebaca5 100644 --- a/packages/core/src/mesh/PrimitiveMesh.ts +++ b/packages/core/src/mesh/PrimitiveMesh.ts @@ -77,8 +77,8 @@ export class PrimitiveMesh { } const { bounds } = mesh; - bounds.min.setValue(-radius, -radius, -radius); - bounds.max.setValue(radius, radius, radius); + bounds.min.set(-radius, -radius, -radius); + bounds.max.set(radius, radius, radius); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; @@ -206,8 +206,8 @@ export class PrimitiveMesh { indices[30] = 20, indices[31] = 22, indices[32] = 23, indices[33] = 22, indices[34] = 20, indices[35] = 21; const { bounds } = mesh; - bounds.min.setValue(-halfWidth, -halfHeight, -halfDepth); - bounds.max.setValue(halfWidth, halfHeight, halfDepth); + bounds.min.set(-halfWidth, -halfHeight, -halfDepth); + bounds.max.set(halfWidth, halfHeight, halfDepth); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; @@ -283,8 +283,8 @@ export class PrimitiveMesh { } const { bounds } = mesh; - bounds.min.setValue(-halfWidth, 0, -halfHeight); - bounds.max.setValue(halfWidth, 0, halfHeight); + bounds.min.set(-halfWidth, 0, -halfHeight); + bounds.max.set(halfWidth, 0, halfHeight); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; @@ -448,8 +448,8 @@ export class PrimitiveMesh { const { bounds } = mesh; const radiusMax = Math.max(radiusTop, radiusBottom); - bounds.min.setValue(-radiusMax, -halfHeight, -radiusMax); - bounds.max.setValue(radiusMax, halfHeight, radiusMax); + bounds.min.set(-radiusMax, -halfHeight, -radiusMax); + bounds.max.set(radiusMax, halfHeight, radiusMax); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; @@ -535,8 +535,8 @@ export class PrimitiveMesh { const { bounds } = mesh; const outerRadius = radius + tubeRadius; - bounds.min.setValue(-outerRadius, -outerRadius, -tubeRadius); - bounds.max.setValue(outerRadius, outerRadius, tubeRadius); + bounds.min.set(-outerRadius, -outerRadius, -tubeRadius); + bounds.max.set(outerRadius, outerRadius, tubeRadius); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; @@ -665,8 +665,8 @@ export class PrimitiveMesh { } const { bounds } = mesh; - bounds.min.setValue(-radius, -halfHeight, -radius); - bounds.max.setValue(radius, halfHeight, radius); + bounds.min.set(-radius, -halfHeight, -radius); + bounds.max.set(radius, halfHeight, radius); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; @@ -786,8 +786,8 @@ export class PrimitiveMesh { ); const { bounds } = mesh; - bounds.min.setValue(-radius, -radius - halfHeight, -radius); - bounds.max.setValue(radius, radius + halfHeight, radius); + bounds.min.set(-radius, -radius - halfHeight, -radius); + bounds.max.set(radius, radius + halfHeight, radius); PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible); return mesh; diff --git a/packages/core/src/mesh/SkinnedMeshRenderer.ts b/packages/core/src/mesh/SkinnedMeshRenderer.ts index 3954ec95a8..cce31dee0c 100644 --- a/packages/core/src/mesh/SkinnedMeshRenderer.ts +++ b/packages/core/src/mesh/SkinnedMeshRenderer.ts @@ -160,7 +160,7 @@ export class SkinnedMeshRenderer extends MeshRenderer { if (joints[i]) { Matrix.multiply(joints[i].transform.worldMatrix, ibms[i], mat); } else { - ibms[i].cloneTo(mat); + mat.copyFrom(ibms[i]); } Matrix.multiply(worldToLocal, mat, mat); matrixPalette.set(mat.elements, i * 16); diff --git a/packages/core/src/physics/CharacterController.ts b/packages/core/src/physics/CharacterController.ts index b5c569574d..c1fa67fe31 100644 --- a/packages/core/src/physics/CharacterController.ts +++ b/packages/core/src/physics/CharacterController.ts @@ -25,9 +25,9 @@ export class CharacterController extends Collider { return this._stepOffset; } - set stepOffset(newValue: number) { - this._stepOffset = newValue; - (this._nativeCollider).setStepOffset(newValue); + set stepOffset(value: number) { + this._stepOffset = value; + (this._nativeCollider).setStepOffset(value); } /** @@ -37,9 +37,9 @@ export class CharacterController extends Collider { return this._nonWalkableMode; } - set nonWalkableMode(newValue: ControllerNonWalkableMode) { - this._nonWalkableMode = newValue; - (this._nativeCollider).setNonWalkableMode(newValue); + set nonWalkableMode(value: ControllerNonWalkableMode) { + this._nonWalkableMode = value; + (this._nativeCollider).setNonWalkableMode(value); } /** @@ -49,9 +49,9 @@ export class CharacterController extends Collider { return this._upDirection; } - set upDirection(newValue: Vector3) { - if (this._upDirection !== newValue) { - newValue.cloneTo(this._upDirection); + set upDirection(value: Vector3) { + if (this._upDirection !== value) { + this._upDirection.copyFrom(value); } (this._nativeCollider).setUpDirection(this._upDirection); } @@ -63,9 +63,9 @@ export class CharacterController extends Collider { return this._slopeLimit; } - set slopeLimit(newValue: number) { - this._slopeLimit = newValue; - (this._nativeCollider).setSlopeLimit(newValue); + set slopeLimit(value: number) { + this._slopeLimit = value; + (this._nativeCollider).setSlopeLimit(value); } /** diff --git a/packages/core/src/physics/DynamicCollider.ts b/packages/core/src/physics/DynamicCollider.ts index edced0df51..0ed76387e7 100644 --- a/packages/core/src/physics/DynamicCollider.ts +++ b/packages/core/src/physics/DynamicCollider.ts @@ -56,7 +56,7 @@ export class DynamicCollider extends Collider { set linearVelocity(value: Vector3) { if (this._linearVelocity !== value) { - value.cloneTo(this._linearVelocity); + this._linearVelocity.copyFrom(value); } (this._nativeCollider).setLinearVelocity(this._linearVelocity); } @@ -70,7 +70,7 @@ export class DynamicCollider extends Collider { set angularVelocity(value: Vector3) { if (this._angularVelocity !== value) { - value.cloneTo(this._angularVelocity); + this._angularVelocity.copyFrom(value); } (this._nativeCollider).setAngularVelocity(this._angularVelocity); } @@ -96,7 +96,7 @@ export class DynamicCollider extends Collider { set centerOfMass(value: Vector3) { if (this._centerOfMass !== value) { - value.cloneTo(this._centerOfMass); + this._centerOfMass.copyFrom(value); } (this._nativeCollider).setCenterOfMass(this._centerOfMass); } @@ -110,7 +110,7 @@ export class DynamicCollider extends Collider { set inertiaTensor(value: Vector3) { if (this._inertiaTensor !== value) { - value.cloneTo(this._inertiaTensor); + this._inertiaTensor.copyFrom(value); } (this._nativeCollider).setInertiaTensor(this._inertiaTensor); } diff --git a/packages/core/src/physics/PhysicsManager.ts b/packages/core/src/physics/PhysicsManager.ts index ac86a98d3c..caf90e98a4 100644 --- a/packages/core/src/physics/PhysicsManager.ts +++ b/packages/core/src/physics/PhysicsManager.ts @@ -140,7 +140,7 @@ export class PhysicsManager { set gravity(value: Vector3) { const gravity = this._gravity; if (gravity !== value) { - value.cloneTo(gravity); + gravity.copyFrom(value); } this._nativePhysicsManager.setGravity(gravity); } @@ -250,8 +250,8 @@ export class PhysicsManager { const result = this._nativePhysicsManager.raycast(ray, distance, (idx, distance, position, normal) => { hitResult.entity = this._physicalObjectsMap[idx]._collider.entity; hitResult.distance = distance; - normal.cloneTo(hitResult.normal); - position.cloneTo(hitResult.point); + hitResult.normal.copyFrom(normal); + hitResult.point.copyFrom(position); }); if (result) { @@ -260,8 +260,8 @@ export class PhysicsManager { } else { hitResult.entity = null; hitResult.distance = 0; - hitResult.point.setValue(0, 0, 0); - hitResult.normal.setValue(0, 0, 0); + hitResult.point.set(0, 0, 0); + hitResult.normal.set(0, 0, 0); return false; } } diff --git a/packages/core/src/physics/shape/BoxColliderShape.ts b/packages/core/src/physics/shape/BoxColliderShape.ts index 31e00c743b..c8a150562e 100644 --- a/packages/core/src/physics/shape/BoxColliderShape.ts +++ b/packages/core/src/physics/shape/BoxColliderShape.ts @@ -17,7 +17,7 @@ export class BoxColliderShape extends ColliderShape { set size(value: Vector3) { if (this._size != value) { - value.cloneTo(this._size); + this._size.copyFrom(value); } (this._nativeShape).setSize(value); } diff --git a/packages/core/src/physics/shape/ColliderShape.ts b/packages/core/src/physics/shape/ColliderShape.ts index 9425f9b14a..4b0f59c6b2 100644 --- a/packages/core/src/physics/shape/ColliderShape.ts +++ b/packages/core/src/physics/shape/ColliderShape.ts @@ -68,7 +68,7 @@ export abstract class ColliderShape { set position(value: Vector3) { if (this._position !== value) { - value.cloneTo(this._position); + this._position.copyFrom(value); } this._nativeShape.setPosition(value); } @@ -97,7 +97,7 @@ export abstract class ColliderShape { * @param z - The z component of the vector, default 0 */ setPosition(x: number, y: number, z: number): void { - this._position.setValue(x, y, z); + this._position.set(x, y, z); this._nativeShape.setPosition(this._position); } diff --git a/packages/core/src/physics/shape/PlaneColliderShape.ts b/packages/core/src/physics/shape/PlaneColliderShape.ts index 77f62a613d..34bcef3b2d 100644 --- a/packages/core/src/physics/shape/PlaneColliderShape.ts +++ b/packages/core/src/physics/shape/PlaneColliderShape.ts @@ -1,7 +1,7 @@ -import { ColliderShape } from "./ColliderShape"; -import { PhysicsManager } from "../PhysicsManager"; -import { Vector3 } from "@oasis-engine/math"; import { IPlaneColliderShape } from "@oasis-engine/design"; +import { Vector3 } from "@oasis-engine/math"; +import { PhysicsManager } from "../PhysicsManager"; +import { ColliderShape } from "./ColliderShape"; /** * Physical collider shape plane. @@ -18,7 +18,7 @@ export class PlaneColliderShape extends ColliderShape { set rotation(value: Vector3) { if (this._rotation != value) { - value.cloneTo(this._rotation); + this._rotation.copyFrom(value); } (this._nativeShape).setRotation(value); } @@ -38,7 +38,7 @@ export class PlaneColliderShape extends ColliderShape { * @param z - Radian of roll */ setRotation(x: number, y: number, z: number): void { - this._rotation.setValue(x, y, z); + this._rotation.set(x, y, z); (this._nativeShape).setRotation(this._rotation); } } diff --git a/packages/core/src/shader/ShaderData.ts b/packages/core/src/shader/ShaderData.ts index f9ddc6ad42..efde547859 100644 --- a/packages/core/src/shader/ShaderData.ts +++ b/packages/core/src/shader/ShaderData.ts @@ -586,7 +586,7 @@ export class ShaderData implements IRefObject, IClone { } else { const targetProperty = targetProperties[k]; if (targetProperty) { - property.cloneTo(targetProperty); + targetProperty.copyFrom(property); } else { targetProperties[k] = property.clone(); } diff --git a/packages/core/src/shader/state/BlendState.ts b/packages/core/src/shader/state/BlendState.ts index a5be507302..34c58d2daa 100644 --- a/packages/core/src/shader/state/BlendState.ts +++ b/packages/core/src/shader/state/BlendState.ts @@ -143,7 +143,7 @@ export class BlendState { const blendColor = this.blendColor; if (!Color.equals(lastState.blendColor, blendColor)) { gl.blendColor(blendColor.r, blendColor.g, blendColor.b, blendColor.a); - blendColor.cloneTo(lastState.blendColor); + lastState.blendColor.copyFrom(blendColor); } } diff --git a/packages/core/src/trail/TrailRenderer.ts b/packages/core/src/trail/TrailRenderer.ts index 2f68868748..ecf98f23c1 100644 --- a/packages/core/src/trail/TrailRenderer.ts +++ b/packages/core/src/trail/TrailRenderer.ts @@ -76,7 +76,7 @@ export class TrailRenderer extends MeshRenderer { this._pointStates[newIdx] = this._pointStates[i]; // Move point - this._points[i].cloneTo(this._points[newIdx]); + this._points[newIdx].copyFrom(this._points[i]); } } this._curPointNum -= mov; @@ -95,7 +95,7 @@ export class TrailRenderer extends MeshRenderer { if (appendNewPoint) { this._pointStates[this._curPointNum] = this._lifetime; - this.entity.transform.worldPosition.cloneTo(this._points[this._curPointNum]); + this._points[this._curPointNum].copyFrom(this.entity.transform.worldPosition); this._curPointNum++; } diff --git a/packages/loader/src/EnvLoader.ts b/packages/loader/src/EnvLoader.ts index 823a79a3d8..e1352bc172 100644 --- a/packages/loader/src/EnvLoader.ts +++ b/packages/loader/src/EnvLoader.ts @@ -47,7 +47,7 @@ class EnvLoader extends Loader { const sh = new SphericalHarmonics3(); ambientLight.diffuseMode = DiffuseMode.SphericalHarmonics; - sh.setValueByArray(shArray); + sh.copyFromArray(shArray); ambientLight.diffuseSphericalHarmonics = sh; ambientLight.specularTexture = texture; ambientLight.specularTextureDecodeRGBM = true; diff --git a/packages/loader/src/HDRLoader.ts b/packages/loader/src/HDRLoader.ts index 16ce64004c..97630533ac 100644 --- a/packages/loader/src/HDRLoader.ts +++ b/packages/loader/src/HDRLoader.ts @@ -114,12 +114,12 @@ class HDRLoader extends Loader { ): Uint8ClampedArray { const textureArray = new Uint8ClampedArray(texSize * texSize * 4); const rotDX1 = this._tempVector3 - .setValue(0, 0, 0) + .set(0, 0, 0) .add(faceData[1]) .subtract(faceData[0]) .scale(1 / texSize); const rotDX2 = this._temp2Vector3 - .setValue(0, 0, 0) + .set(0, 0, 0) .add(faceData[3]) .subtract(faceData[2]) .scale(1 / texSize); @@ -128,11 +128,11 @@ class HDRLoader extends Loader { let fy = 0; for (let y = 0; y < texSize; y++) { - let xv1 = this._temp3Vector3.setValue(0, 0, 0).add(faceData[0]); - let xv2 = this._temp4Vector3.setValue(0, 0, 0).add(faceData[2]); + let xv1 = this._temp3Vector3.set(0, 0, 0).add(faceData[0]); + let xv2 = this._temp4Vector3.set(0, 0, 0).add(faceData[2]); for (let x = 0; x < texSize; x++) { - const v = this._temp5Vector3.setValue(0, 0, 0).add(xv2).subtract(xv1).scale(fy).add(xv1); + const v = this._temp5Vector3.set(0, 0, 0).add(xv2).subtract(xv1).scale(fy).add(xv1); v.normalize(); const color = this._calcProjectionSpherical(v, pixels, inputWidth, inputHeight); diff --git a/packages/loader/src/SpriteAtlasLoader.ts b/packages/loader/src/SpriteAtlasLoader.ts index b42812d415..31502fdc4c 100644 --- a/packages/loader/src/SpriteAtlasLoader.ts +++ b/packages/loader/src/SpriteAtlasLoader.ts @@ -1,13 +1,7 @@ import { - resourceLoader, - Loader, AssetPromise, - AssetType, - LoadItem, - ResourceManager, - Texture2D, - Sprite, - SpriteAtlas + AssetType, Loader, LoadItem, resourceLoader, ResourceManager, Sprite, + SpriteAtlas, Texture2D } from "@oasis-engine/core"; import { AtlasConfig } from "@oasis-engine/core/types/2d/atlas/types"; import { Rect, Vector2 } from "@oasis-engine/math"; @@ -55,12 +49,12 @@ class SpriteAtlasLoader extends Loader { const sprite = new Sprite( engine, texture, - region ? tempRect.setValue(region.x, region.y, region.w, region.h) : undefined, - pivot ? tempVect2.setValue(pivot.x, pivot.y) : undefined, + region ? tempRect.set(region.x, region.y, region.w, region.h) : undefined, + pivot ? tempVect2.set(pivot.x, pivot.y) : undefined, atlasSprite.pixelsPerUnit || undefined, atlasSprite.name ); - sprite.atlasRegion.setValue( + sprite.atlasRegion.set( atlasRegion.x * sourceWidthReciprocal, atlasRegion.y * sourceHeightReciprocal, atlasRegion.w * sourceWidthReciprocal, @@ -77,7 +71,7 @@ class SpriteAtlasLoader extends Loader { originalWReciprocal = 1 / (offsetLeft + atlasRegion.w + offsetRight); originalHReciprocal = 1 / (offsetTop + atlasRegion.h + offsetBottom); } - sprite.atlasRegionOffset.setValue( + sprite.atlasRegionOffset.set( offsetLeft * originalWReciprocal, offsetTop * originalHReciprocal, offsetRight * originalWReciprocal, diff --git a/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts b/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts index 9c35e21442..aeb35cd735 100644 --- a/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts +++ b/packages/loader/src/gltf/extensions/KHR_lights_punctual.ts @@ -19,7 +19,7 @@ class KHR_lights_punctual extends ExtensionParser { } if (color) { - light.color.setValue(color[0], color[1], color[2], 1); + light.color.set(color[0], color[1], color[2], 1); } light.intensity = intensity; diff --git a/packages/loader/src/gltf/parser/EntityParser.ts b/packages/loader/src/gltf/parser/EntityParser.ts index 03cab24668..a140f47da6 100644 --- a/packages/loader/src/gltf/parser/EntityParser.ts +++ b/packages/loader/src/gltf/parser/EntityParser.ts @@ -23,7 +23,7 @@ export class EntityParser extends Parser { const { transform } = entity; if (matrix) { const localMatrix = transform.localMatrix; - localMatrix.setValueByArray(matrix); + localMatrix.copyFromArray(matrix); transform.localMatrix = localMatrix; } else { if (translation) { diff --git a/packages/loader/src/gltf/parser/MeshParser.ts b/packages/loader/src/gltf/parser/MeshParser.ts index 0a6cc77425..70afe53176 100644 --- a/packages/loader/src/gltf/parser/MeshParser.ts +++ b/packages/loader/src/gltf/parser/MeshParser.ts @@ -121,19 +121,19 @@ export class MeshParser extends Parser { const { bounds } = mesh; vertexCount = accessor.count; if (accessor.min && accessor.max) { - bounds.min.setValueByArray(accessor.min); - bounds.max.setValueByArray(accessor.max); + bounds.min.copyFromArray(accessor.min); + bounds.max.copyFromArray(accessor.max); } else { const position = MeshParser._tempVector3; const { min, max } = bounds; - min.setValue(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); - max.setValue(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); + min.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); + max.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); const stride = positionBuffer.length / vertexCount; for (let j = 0; j < vertexCount; j++) { const offset = j * stride; - position.setValueByArray(positionBuffer, offset); + position.copyFromArray(positionBuffer, offset); Vector3.min(min, position, min); Vector3.max(max, position, max); } diff --git a/packages/loader/src/gltf/parser/SkinParser.ts b/packages/loader/src/gltf/parser/SkinParser.ts index a0f15a536d..18062811b4 100644 --- a/packages/loader/src/gltf/parser/SkinParser.ts +++ b/packages/loader/src/gltf/parser/SkinParser.ts @@ -25,7 +25,7 @@ export class SkinParser extends Parser { const buffer = GLTFUtil.getAccessorData(gltf, accessor, buffers); for (let i = 0; i < jointCount; i++) { const inverseBindMatrix = new Matrix(); - inverseBindMatrix.setValueByArray(buffer, i * 16); + inverseBindMatrix.copyFromArray(buffer, i * 16); skin.inverseBindMatrices[i] = inverseBindMatrix; } diff --git a/packages/math/src/BoundingBox.ts b/packages/math/src/BoundingBox.ts index d991cbb8bc..f84094d57c 100644 --- a/packages/math/src/BoundingBox.ts +++ b/packages/math/src/BoundingBox.ts @@ -1,12 +1,13 @@ -import { IClone } from "./IClone"; import { BoundingSphere } from "./BoundingSphere"; +import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { Matrix } from "./Matrix"; import { Vector3 } from "./Vector3"; /** * Axis Aligned Bound Box (AABB). */ -export class BoundingBox implements IClone { +export class BoundingBox implements IClone, ICopy { private static _tempVec30: Vector3 = new Vector3(); private static _tempVec31: Vector3 = new Vector3(); @@ -108,27 +109,8 @@ export class BoundingBox implements IClone { * @param max - The maximum point of the box */ constructor(min: Vector3 = null, max: Vector3 = null) { - min && min.cloneTo(this.min); - max && max.cloneTo(this.max); - } - - /** - * Creates a clone of this box. - * @returns A clone of this box - */ - clone(): BoundingBox { - return new BoundingBox(this.min, this.max); - } - - /** - * Clones this box to the specified box. - * @param out - The specified box - * @returns The specified box - */ - cloneTo(out: BoundingBox): BoundingBox { - this.min.cloneTo(out.min); - this.max.cloneTo(out.max); - return out; + min && this.min.copyFrom(min); + max && this.max.copyFrom(max); } /** @@ -175,14 +157,14 @@ export class BoundingBox implements IClone { } } - out[0].setValue(minX, maxY, maxZ); - out[1].setValue(maxX, maxY, maxZ); - out[2].setValue(maxX, minY, maxZ); - out[3].setValue(minX, minY, maxZ); - out[4].setValue(minX, maxY, minZ); - out[5].setValue(maxX, maxY, minZ); - out[6].setValue(maxX, minY, minZ); - out[7].setValue(minX, minY, minZ); + out[0].set(minX, maxY, maxZ); + out[1].set(maxX, maxY, maxZ); + out[2].set(maxX, minY, maxZ); + out[3].set(minX, minY, maxZ); + out[4].set(minX, maxY, minZ); + out[5].set(maxX, maxY, minZ); + out[6].set(maxX, minY, minZ); + out[7].set(minX, minY, minZ); return out; } @@ -196,4 +178,23 @@ export class BoundingBox implements IClone { BoundingBox.transform(this, matrix, this); return this; } + + /** + * Creates a clone of this box. + * @returns A clone of this box + */ + clone(): BoundingBox { + return new BoundingBox(this.min, this.max); + } + + /** + * Copy this bounding box from the specified box. + * @param source - The specified box + * @returns This bounding box + */ + copyFrom(source: BoundingBox): BoundingBox { + this.min.copyFrom(source.min); + this.max.copyFrom(source.max); + return this; + } } diff --git a/packages/math/src/BoundingFrustum.ts b/packages/math/src/BoundingFrustum.ts index a9e3392697..6ae4c81e69 100644 --- a/packages/math/src/BoundingFrustum.ts +++ b/packages/math/src/BoundingFrustum.ts @@ -3,13 +3,14 @@ import { BoundingSphere } from "./BoundingSphere"; import { CollisionUtil } from "./CollisionUtil"; import { ContainmentType } from "./enums/ContainmentType"; import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { Matrix } from "./Matrix"; import { Plane } from "./Plane"; /** * A bounding frustum. */ -export class BoundingFrustum implements IClone { +export class BoundingFrustum implements IClone, ICopy { /** The near plane of this frustum. */ public near: Plane; /** The far plane of this frustum. */ @@ -38,31 +39,6 @@ export class BoundingFrustum implements IClone { matrix && this.calculateFromMatrix(matrix); } - /** - * Creates a clone of this frustum. - * @returns A clone of this frustum - */ - clone(): BoundingFrustum { - const bf = new BoundingFrustum(); - this.cloneTo(bf); - return bf; - } - - /** - * Clones this frustum to the specified frustum. - * @param out - The specified frustum - * @returns The specified frustum - */ - cloneTo(out: BoundingFrustum): BoundingFrustum { - this.near.cloneTo(out.near); - this.far.cloneTo(out.far); - this.left.cloneTo(out.left); - this.right.cloneTo(out.right); - this.top.cloneTo(out.top); - this.bottom.cloneTo(out.bottom); - return out; - } - /** * Get the plane by the given index. * 0: near @@ -118,38 +94,38 @@ export class BoundingFrustum implements IClone { // near const nearNormal = this.near.normal; - nearNormal.setValue(-m14 - m13, -m24 - m23, -m34 - m33); + nearNormal.set(-m14 - m13, -m24 - m23, -m34 - m33); this.near.distance = -m44 - m43; this.near.normalize(); // far const farNormal = this.far.normal; - farNormal.setValue(m13 - m14, m23 - m24, m33 - m34); + farNormal.set(m13 - m14, m23 - m24, m33 - m34); this.far.distance = m43 - m44; this.far.normalize(); // left const leftNormal = this.left.normal; - leftNormal.setValue(-m14 - m11, -m24 - m21, -m34 - m31); + leftNormal.set(-m14 - m11, -m24 - m21, -m34 - m31); this.left.distance = -m44 - m41; this.left.normalize(); // right const rightNormal = this.right.normal; - rightNormal.setValue(m11 - m14, m21 - m24, m31 - m34); + rightNormal.set(m11 - m14, m21 - m24, m31 - m34); this.right.distance = m41 - m44; this.right.normalize(); // top const topNormal = this.top.normal; - topNormal.setValue(m12 - m14, m22 - m24, m32 - m34); + topNormal.set(m12 - m14, m22 - m24, m32 - m34); this.top.distance = m42 - m44; this.top.normalize(); // bottom const bottomNormal = this.bottom.normal; - bottomNormal.setValue(-m14 - m12, -m24 - m22, -m34 - m32); + bottomNormal.set(-m14 - m12, -m24 - m22, -m34 - m32); this.bottom.distance = -m44 - m42; this.bottom.normalize(); } @@ -171,4 +147,29 @@ export class BoundingFrustum implements IClone { public intersectsSphere(sphere: BoundingSphere): boolean { return CollisionUtil.frustumContainsSphere(this, sphere) !== ContainmentType.Disjoint; } + + /** + * Creates a clone of this frustum. + * @returns A clone of this frustum + */ + clone(): BoundingFrustum { + const out = new BoundingFrustum(); + out.copyFrom(this); + return out; + } + + /** + * Copy this frustum from the specified frustum. + * @param source - The specified frustum + * @returns This frustum + */ + copyFrom(source: BoundingFrustum): BoundingFrustum { + this.near.copyFrom(source.near); + this.far.copyFrom(source.far); + this.left.copyFrom(source.left); + this.right.copyFrom(source.right); + this.top.copyFrom(source.top); + this.bottom.copyFrom(source.bottom); + return this; + } } diff --git a/packages/math/src/BoundingSphere.ts b/packages/math/src/BoundingSphere.ts index 0db173ff03..adbac5bb1f 100644 --- a/packages/math/src/BoundingSphere.ts +++ b/packages/math/src/BoundingSphere.ts @@ -1,11 +1,12 @@ -import { IClone } from "./IClone"; import { BoundingBox } from "./BoundingBox"; +import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { Vector3 } from "./Vector3"; /** * A bounding sphere. * */ -export class BoundingSphere implements IClone { +export class BoundingSphere implements IClone, ICopy { private static _tempVec30: Vector3 = new Vector3(); /** @@ -66,7 +67,7 @@ export class BoundingSphere implements IClone { * @param radius - The radius of the sphere */ constructor(center: Vector3 = null, radius: number = 0) { - center && center.cloneTo(this.center); + center && this.center.copyFrom(center); this.radius = radius; } @@ -79,13 +80,13 @@ export class BoundingSphere implements IClone { } /** - * Clones this sphere to the specified sphere. - * @param out - The specified sphere - * @returns The specified sphere + * Copy this sphere from the specified sphere. + * @param source - The specified sphere + * @returns This sphere */ - cloneTo(out: BoundingSphere): BoundingSphere { - this.center.cloneTo(out.center); - out.radius = this.radius; - return out; + copyFrom(source: BoundingSphere): BoundingSphere { + this.center.copyFrom(source.center); + this.radius = source.radius; + return this; } } diff --git a/packages/math/src/CollisionUtil.ts b/packages/math/src/CollisionUtil.ts index 31bd7662f5..350ee14520 100644 --- a/packages/math/src/CollisionUtil.ts +++ b/packages/math/src/CollisionUtil.ts @@ -299,7 +299,7 @@ export class CollisionUtil { const min = box.min; const closestPoint = CollisionUtil._tempVec30; - closestPoint.setValue( + closestPoint.set( Math.max(min.x, Math.min(center.x, max.x)), Math.max(min.y, Math.min(center.y, max.y)), Math.max(min.z, Math.min(center.z, max.z)) @@ -323,7 +323,7 @@ export class CollisionUtil { const plane = frustum.getPlane(i); const normal = plane.normal; - back.setValue(normal.x >= 0 ? min.x : max.x, normal.y >= 0 ? min.y : max.y, normal.z >= 0 ? min.z : max.z); + back.set(normal.x >= 0 ? min.x : max.x, normal.y >= 0 ? min.y : max.y, normal.z >= 0 ? min.z : max.z); if (Vector3.dot(plane.normal, back) > -plane.distance) { return false; } diff --git a/packages/math/src/Color.ts b/packages/math/src/Color.ts index fe0e959326..e8f9eaeeba 100644 --- a/packages/math/src/Color.ts +++ b/packages/math/src/Color.ts @@ -1,10 +1,11 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; /** * Describes a color in the from of RGBA (in order: R, G, B, A). */ -export class Color implements IClone { +export class Color implements IClone, ICopy { /** * Modify a value from the gamma space to the linear space. * @param value - The value in gamma space @@ -113,7 +114,7 @@ export class Color implements IClone { * @param a - The alpha component of the color * @returns This color. */ - setValue(r: number, g: number, b: number, a: number): Color { + set(r: number, g: number, b: number, a: number): Color { this.r = r; this.g = g; this.b = b; @@ -159,16 +160,16 @@ export class Color implements IClone { } /** - * Clones this color to the specified color. - * @param out - The specified color - * @returns The specified color + * Copy from color like object. + * @param source - Color like object. + * @returns This vector */ - cloneTo(out: Color): Color { - out.r = this.r; - out.g = this.g; - out.b = this.b; - out.a = this.a; - return out; + copyFrom(source: ColorLike): Color { + this.r = source.r; + this.g = source.g; + this.b = source.b; + this.a = source.a; + return this; } /** @@ -195,3 +196,14 @@ export class Color implements IClone { return out; } } + +interface ColorLike { + /** {@inheritDoc Color.r} */ + r: number; + /** {@inheritDoc Color.g} */ + g: number; + /** {@inheritDoc Color.b} */ + b: number; + /** {@inheritDoc Color.a} */ + a: number; +} diff --git a/packages/math/src/IClone.ts b/packages/math/src/IClone.ts index 88bf04a002..0f8ada8af8 100644 --- a/packages/math/src/IClone.ts +++ b/packages/math/src/IClone.ts @@ -1,16 +1,10 @@ /** * Clone interface. */ -export interface IClone { +export interface IClone { /** * Clone and return object. * @returns Clone object */ - clone(): Object; - - /** - * Clone to the target object. - * @param target - Target object - */ - cloneTo(target: Object): Object; + clone(): T; } diff --git a/packages/math/src/ICopy.ts b/packages/math/src/ICopy.ts new file mode 100644 index 0000000000..ac0f210c5e --- /dev/null +++ b/packages/math/src/ICopy.ts @@ -0,0 +1,10 @@ +/** + * Copy interface. + */ +export interface ICopy { + /** + * Copy from source object. + * @returns This object + */ + copyFrom(source: S): T; +} diff --git a/packages/math/src/Matrix.ts b/packages/math/src/Matrix.ts index a76f5cd732..223176a709 100644 --- a/packages/math/src/Matrix.ts +++ b/packages/math/src/Matrix.ts @@ -1,4 +1,5 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; import { Matrix3x3 } from "./Matrix3x3"; import { Quaternion } from "./Quaternion"; @@ -7,7 +8,7 @@ import { Vector3 } from "./Vector3"; /** * Represents a 4x4 mathematical matrix. */ -export class Matrix implements IClone { +export class Matrix implements IClone, ICopy { private static readonly _tempVec30: Vector3 = new Vector3(); private static readonly _tempVec31: Vector3 = new Vector3(); private static readonly _tempVec32: Vector3 = new Vector3(); @@ -846,7 +847,7 @@ export class Matrix implements IClone { * @param m44 - column 4, row 4 * @returns This matrix */ - setValue( + set( m11: number, m12: number, m13: number, @@ -889,105 +890,6 @@ export class Matrix implements IClone { return this; } - /** - * Set the value of this matrix by an array. - * @param array - The array - * @param offset - The start offset of the array - * @returns This matrix - */ - setValueByArray(array: ArrayLike, offset: number = 0): Matrix { - const srce = this.elements; - for (let i = 0; i < 16; i++) { - srce[i] = array[i + offset]; - } - return this; - } - - /** - * Clone the value of this matrix to an array. - * @param out - The array - * @param outOffset - The start offset of the array - */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { - const e = this.elements; - - out[outOffset] = e[0]; - out[outOffset + 1] = e[1]; - out[outOffset + 2] = e[2]; - out[outOffset + 3] = e[3]; - out[outOffset + 4] = e[4]; - out[outOffset + 5] = e[5]; - out[outOffset + 6] = e[6]; - out[outOffset + 7] = e[7]; - out[outOffset + 8] = e[8]; - out[outOffset + 9] = e[9]; - out[outOffset + 10] = e[10]; - out[outOffset + 11] = e[11]; - out[outOffset + 12] = e[12]; - out[outOffset + 13] = e[13]; - out[outOffset + 14] = e[14]; - out[outOffset + 15] = e[15]; - } - - /** - * Creates a clone of this matrix. - * @returns A clone of this matrix - */ - clone(): Matrix { - const e = this.elements; - let ret = new Matrix( - e[0], - e[1], - e[2], - e[3], - e[4], - e[5], - e[6], - e[7], - e[8], - e[9], - e[10], - e[11], - e[12], - e[13], - e[14], - e[15] - ); - return ret; - } - - /** - * Clones this matrix to the specified matrix. - * @param out - The specified matrix - * @returns The specified matrix - */ - cloneTo(out: Matrix): Matrix { - const e = this.elements; - const oe = out.elements; - - oe[0] = e[0]; - oe[1] = e[1]; - oe[2] = e[2]; - oe[3] = e[3]; - - oe[4] = e[4]; - oe[5] = e[5]; - oe[6] = e[6]; - oe[7] = e[7]; - - oe[8] = e[8]; - oe[9] = e[9]; - oe[10] = e[10]; - oe[11] = e[11]; - - oe[12] = e[12]; - oe[13] = e[13]; - oe[14] = e[14]; - oe[15] = e[15]; - - return out; - } - /** * Determines the product of this matrix and the specified matrix. * @param right - The specified matrix @@ -1064,7 +966,7 @@ export class Matrix implements IClone { const m32 = e[9]; const m33 = e[10]; const m34 = e[11]; - translation.setValue(e[12], e[13], e[14]); + translation.set(e[12], e[13], e[14]); const xs = Math.sign(m11 * m12 * m13 * m14) < 0 ? -1 : 1; const ys = Math.sign(m21 * m22 * m23 * m24) < 0 ? -1 : 1; @@ -1073,7 +975,7 @@ export class Matrix implements IClone { const sx = xs * Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13); const sy = ys * Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23); const sz = zs * Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33); - scale.setValue(sx, sy, sz); + scale.set(sx, sy, sz); if ( Math.abs(sx) < MathUtil.zeroTolerance || @@ -1158,7 +1060,11 @@ export class Matrix implements IClone { m32 = e[9], m33 = e[10]; - out.setValue(Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13), Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23), Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33)); + out.set( + Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13), + Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23), + Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33) + ); return out; } @@ -1170,7 +1076,7 @@ export class Matrix implements IClone { */ getTranslation(out: Vector3): Vector3 { const e = this.elements; - out.setValue(e[12], e[13], e[14]); + out.set(e[12], e[13], e[14]); return out; } @@ -1252,4 +1158,103 @@ export class Matrix implements IClone { Matrix.transpose(this, this); return this; } + + /** + * Creates a clone of this matrix. + * @returns A clone of this matrix + */ + clone(): Matrix { + const e = this.elements; + let ret = new Matrix( + e[0], + e[1], + e[2], + e[3], + e[4], + e[5], + e[6], + e[7], + e[8], + e[9], + e[10], + e[11], + e[12], + e[13], + e[14], + e[15] + ); + return ret; + } + + /** + * Copy this matrix from the specified matrix. + * @param source - The specified matrix + * @returns This matrix + */ + copyFrom(source: Matrix): Matrix { + const e = this.elements; + const se = source.elements; + + e[0] = se[0]; + e[1] = se[1]; + e[2] = se[2]; + e[3] = se[3]; + + e[4] = se[4]; + e[5] = se[5]; + e[6] = se[6]; + e[7] = se[7]; + + e[8] = se[8]; + e[9] = se[9]; + e[10] = se[10]; + e[11] = se[11]; + + e[12] = se[12]; + e[13] = se[13]; + e[14] = se[14]; + e[15] = se[15]; + + return this; + } + + /** + * Copy the value of this matrix from an array. + * @param array - The array + * @param offset - The start offset of the array + * @returns This matrix + */ + copyFromArray(array: ArrayLike, offset: number = 0): Matrix { + const srce = this.elements; + for (let i = 0; i < 16; i++) { + srce[i] = array[i + offset]; + } + return this; + } + + /** + * Copy the value of this matrix to an array. + * @param out - The array + * @param outOffset - The start offset of the array + */ + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0): void { + const e = this.elements; + + out[outOffset] = e[0]; + out[outOffset + 1] = e[1]; + out[outOffset + 2] = e[2]; + out[outOffset + 3] = e[3]; + out[outOffset + 4] = e[4]; + out[outOffset + 5] = e[5]; + out[outOffset + 6] = e[6]; + out[outOffset + 7] = e[7]; + out[outOffset + 8] = e[8]; + out[outOffset + 9] = e[9]; + out[outOffset + 10] = e[10]; + out[outOffset + 11] = e[11]; + out[outOffset + 12] = e[12]; + out[outOffset + 13] = e[13]; + out[outOffset + 14] = e[14]; + out[outOffset + 15] = e[15]; + } } diff --git a/packages/math/src/Matrix3x3.ts b/packages/math/src/Matrix3x3.ts index 6219c344c7..cf98b16327 100644 --- a/packages/math/src/Matrix3x3.ts +++ b/packages/math/src/Matrix3x3.ts @@ -1,4 +1,5 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; import { Matrix } from "./Matrix"; import { Quaternion } from "./Quaternion"; @@ -7,7 +8,7 @@ import { Vector2 } from "./Vector2"; /** * Represents a 3x3 mathematical matrix. */ -export class Matrix3x3 implements IClone { +export class Matrix3x3 implements IClone, ICopy { /** * Determines the sum of two matrices. * @param left - The first matrix to add @@ -515,7 +516,7 @@ export class Matrix3x3 implements IClone { * @param m33 * @returns This matrix */ - setValue( + set( m11: number, m12: number, m13: number, @@ -543,98 +544,6 @@ export class Matrix3x3 implements IClone { return this; } - /** - * Set the value of this matrix by an array. - * @param array - The array - * @param offset - The start offset of the array - * @returns This matrix - */ - setValueByArray(array: ArrayLike, offset: number = 0): Matrix3x3 { - const srce = this.elements; - for (let i = 0; i < 12; i++) { - srce[i] = array[i + offset]; - } - return this; - } - - /** - * Set the value of this 3x3 matrix by the specified 4x4 matrix. - * upper-left principle - * @param a - The specified 4x4 matrix - * @returns This 3x3 matrix - */ - setValueByMatrix(a: Matrix): Matrix3x3 { - const ae = a.elements; - const e = this.elements; - - e[0] = ae[0]; - e[1] = ae[1]; - e[2] = ae[2]; - - e[3] = ae[4]; - e[4] = ae[5]; - e[5] = ae[6]; - - e[6] = ae[8]; - e[7] = ae[9]; - e[8] = ae[10]; - - return this; - } - - /** - * Clone the value of this matrix to an array. - * @param out - The array - * @param outOffset - The start offset of the array - */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { - const e = this.elements; - - out[outOffset] = e[0]; - out[outOffset + 1] = e[1]; - out[outOffset + 2] = e[2]; - out[outOffset + 3] = e[3]; - out[outOffset + 4] = e[4]; - out[outOffset + 5] = e[5]; - out[outOffset + 6] = e[6]; - out[outOffset + 7] = e[7]; - out[outOffset + 8] = e[8]; - } - - /** - * Creates a clone of this matrix. - * @returns A clone of this matrix - */ - clone(): Matrix3x3 { - const e = this.elements; - let ret = new Matrix3x3(e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8]); - return ret; - } - - /** - * Clones this matrix to the specified matrix. - * @param out - The specified matrix - * @returns The specified matrix - */ - cloneTo(out: Matrix3x3): Matrix3x3 { - const e = this.elements; - const oe = out.elements; - - oe[0] = e[0]; - oe[1] = e[1]; - oe[2] = e[2]; - - oe[3] = e[3]; - oe[4] = e[4]; - oe[5] = e[5]; - - oe[6] = e[6]; - oe[7] = e[7]; - oe[8] = e[8]; - - return out; - } - /** * Determines the sum of this matrix and the specified matrix. * @param right - The specified matrix @@ -758,4 +667,96 @@ export class Matrix3x3 implements IClone { Matrix3x3.transpose(this, this); return this; } + + /** + * Creates a clone of this matrix. + * @returns A clone of this matrix + */ + clone(): Matrix3x3 { + const e = this.elements; + let ret = new Matrix3x3(e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8]); + return ret; + } + + /** + * Copy this matrix from the specified matrix. + * @param source - The specified matrix + * @returns This matrix + */ + copyFrom(source: Matrix3x3): Matrix3x3 { + const e = this.elements; + const se = source.elements; + + e[0] = se[0]; + e[1] = se[1]; + e[2] = se[2]; + + e[3] = se[3]; + e[4] = se[4]; + e[5] = se[5]; + + e[6] = se[6]; + e[7] = se[7]; + e[8] = se[8]; + + return this; + } + + /** + * Copy the value of this matrix from an array. + * @param array - The array + * @param offset - The start offset of the array + * @returns This matrix + */ + copyFromArray(array: ArrayLike, offset: number = 0): Matrix3x3 { + const srce = this.elements; + for (let i = 0; i < 12; i++) { + srce[i] = array[i + offset]; + } + return this; + } + + /** + * Copy the value of this matrix to an array. + * @param out - The array + * @param outOffset - The start offset of the array + */ + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0): void { + const e = this.elements; + + out[outOffset] = e[0]; + out[outOffset + 1] = e[1]; + out[outOffset + 2] = e[2]; + out[outOffset + 3] = e[3]; + out[outOffset + 4] = e[4]; + out[outOffset + 5] = e[5]; + out[outOffset + 6] = e[6]; + out[outOffset + 7] = e[7]; + out[outOffset + 8] = e[8]; + } + + /** + * Copy the value of this 3x3 matrix from the specified 4x4 matrix. + * upper-left principle + * @param source - The specified 4x4 matrix + * @returns This 3x3 matrix + */ + copyFromMatrix(source: Matrix): Matrix3x3 { + const ae = source.elements; + const e = this.elements; + + e[0] = ae[0]; + e[1] = ae[1]; + e[2] = ae[2]; + + e[3] = ae[4]; + e[4] = ae[5]; + e[5] = ae[6]; + + e[6] = ae[8]; + e[7] = ae[9]; + e[8] = ae[10]; + + return this; + } } diff --git a/packages/math/src/Plane.ts b/packages/math/src/Plane.ts index 4657a61911..56dc3db361 100644 --- a/packages/math/src/Plane.ts +++ b/packages/math/src/Plane.ts @@ -1,10 +1,11 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { Vector3 } from "./Vector3"; /** * Represents a plane in three dimensional space. */ -export class Plane implements IClone { +export class Plane implements IClone, ICopy { /** * Normalize the normal vector of the specified plane. * @param p - The specified plane @@ -63,7 +64,7 @@ export class Plane implements IClone { * @param distance - The distance of the plane along its normal to the origin */ constructor(normal: Vector3 = null, distance: number = 0) { - normal && normal.cloneTo(this.normal); + normal && this.normal.copyFrom(normal); this.distance = distance; } @@ -82,18 +83,18 @@ export class Plane implements IClone { */ clone(): Plane { const out = new Plane(); - this.cloneTo(out); + out.copyFrom(this); return out; } /** - * Clones this plane to the specified plane. - * @param out - The specified plane - * @returns The specified plane + * Copy this plane from the specified plane. + * @param source - The specified plane + * @returns This plane */ - cloneTo(out: Plane): Plane { - this.normal.cloneTo(out.normal); - out.distance = this.distance; - return out; + copyFrom(source: Plane): Plane { + this.normal.copyFrom(source.normal); + this.distance = source.distance; + return this; } } diff --git a/packages/math/src/Quaternion.ts b/packages/math/src/Quaternion.ts index 26f76138a4..e2986db438 100644 --- a/packages/math/src/Quaternion.ts +++ b/packages/math/src/Quaternion.ts @@ -1,4 +1,5 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; import { Matrix3x3 } from "./Matrix3x3"; import { Vector3 } from "./Vector3"; @@ -6,7 +7,7 @@ import { Vector3 } from "./Vector3"; /** * Represents a four dimensional mathematical quaternion. */ -export class Quaternion implements IClone { +export class Quaternion implements IClone, ICopy { /** @internal */ static readonly _tempVector3 = new Vector3(); /** @internal */ @@ -522,7 +523,7 @@ export class Quaternion implements IClone { * @param w - The w component of the quaternion * @returns This quaternion */ - setValue(x: number, y: number, z: number, w: number): Quaternion { + set(x: number, y: number, z: number, w: number): Quaternion { this._x = x; this._y = y; this._z = z; @@ -531,21 +532,6 @@ export class Quaternion implements IClone { return this; } - /** - * Set the value of this quaternion by an array. - * @param array - The array - * @param offset - The start offset of the array - * @returns This quaternion - */ - setValueByArray(array: ArrayLike, offset: number = 0): Quaternion { - this._x = array[offset]; - this._y = array[offset + 1]; - this._z = array[offset + 2]; - this._w = array[offset + 3]; - this._onValueChanged && this._onValueChanged(); - return this; - } - /** * Transforms this quaternion into its conjugated version. * @returns This quaternion @@ -649,40 +635,6 @@ export class Quaternion implements IClone { return out; } - /** - * Clone the value of this quaternion to an array. - * @param out - The array - * @param outOffset - The start offset of the array - */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { - out[outOffset] = this._x; - out[outOffset + 1] = this._y; - out[outOffset + 2] = this._z; - out[outOffset + 3] = this._w; - } - - /** - * Creates a clone of this quaternion. - * @returns A clone of this quaternion - */ - clone(): Quaternion { - return new Quaternion(this._x, this._y, this._z, this._w); - } - - /** - * Clones this quaternion to the specified quaternion. - * @param out - The specified quaternion - * @returns The specified quaternion - */ - cloneTo(out: Quaternion): Quaternion { - out._x = this._x; - out._y = this._y; - out._z = this._z; - out._w = this._w; - out._onValueChanged && out._onValueChanged(); - return out; - } - /** * Calculate this quaternion rotate around X axis. * @param rad - The rotation angle in radians @@ -775,6 +727,55 @@ export class Quaternion implements IClone { return this; } + /** + * Creates a clone of this quaternion. + * @returns A clone of this quaternion + */ + clone(): Quaternion { + return new Quaternion(this._x, this._y, this._z, this._w); + } + + /** + * Copy this quaternion from the specified quaternion. + * @param source - The specified quaternion + * @returns This quaternion + */ + copyFrom(source: QuaternionLike): Quaternion { + this._x = source.x; + this._y = source.y; + this._z = source.z; + this._w = source.w; + this._onValueChanged && this._onValueChanged(); + return this; + } + + /** + * Copy the value of this quaternion from an array. + * @param array - The array + * @param offset - The start offset of the array + * @returns This quaternion + */ + copyFromArray(array: ArrayLike, offset: number = 0): Quaternion { + this._x = array[offset]; + this._y = array[offset + 1]; + this._z = array[offset + 2]; + this._w = array[offset + 3]; + this._onValueChanged && this._onValueChanged(); + return this; + } + + /** + * Copy the value of this quaternion to an array. + * @param out - The array + * @param outOffset - The start offset of the array + */ + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { + out[outOffset] = this._x; + out[outOffset + 1] = this._y; + out[outOffset + 2] = this._z; + out[outOffset + 3] = this._w; + } + private _toYawPitchRoll(out: Vector3): Vector3 { const { _x, _y, _z, _w } = this; const xx = _x * _x; @@ -798,3 +799,14 @@ export class Quaternion implements IClone { return out; } } + +interface QuaternionLike { + /** {@inheritDoc Quaternion.x} */ + x: number; + /** {@inheritDoc Quaternion.y} */ + y: number; + /** {@inheritDoc Quaternion.z} */ + z: number; + /** {@inheritDoc Quaternion.w} */ + w: number; +} diff --git a/packages/math/src/Ray.ts b/packages/math/src/Ray.ts index 6a6caf0318..80ba2e2f64 100644 --- a/packages/math/src/Ray.ts +++ b/packages/math/src/Ray.ts @@ -19,8 +19,8 @@ export class Ray { * @param direction - The direction vector */ constructor(origin: Vector3 = null, direction: Vector3 = null) { - origin && origin.cloneTo(this.origin); - direction && direction.cloneTo(this.direction); + origin && this.origin.copyFrom(origin); + direction && this.direction.copyFrom(direction); } /** diff --git a/packages/math/src/Rect.ts b/packages/math/src/Rect.ts index af371ebcf7..b10aeb832b 100644 --- a/packages/math/src/Rect.ts +++ b/packages/math/src/Rect.ts @@ -1,7 +1,8 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; // A 2d rectangle defined by x and y position, width and height. -export class Rect implements IClone { +export class Rect implements IClone, ICopy { /** The x coordinate of the rectangle. */ public x: number; /** The y coordinate of the rectangle. */ @@ -33,7 +34,7 @@ export class Rect implements IClone { * @param height - The height of the rectangle, measured from the y position * @returns This rectangle */ - setValue(x: number, y: number, width: number, height: number): Rect { + set(x: number, y: number, width: number, height: number): Rect { this.x = x; this.y = y; this.width = width; @@ -50,15 +51,15 @@ export class Rect implements IClone { } /** - * Clones this rect to the specified rect. - * @param out - The specified rect - * @returns The specified rect + * Copy this rect from the specified rect. + * @param source - The specified rect + * @returns This rect */ - cloneTo(out: Rect): Rect { - out.x = this.x; - out.y = this.y; - out.width = this.width; - out.height = this.height; - return out; + copyFrom(source: Rect): Rect { + this.x = source.x; + this.y = source.y; + this.width = source.width; + this.height = source.height; + return this; } } diff --git a/packages/math/src/SphericalHarmonics3.ts b/packages/math/src/SphericalHarmonics3.ts index 177de80d1e..741837cd09 100644 --- a/packages/math/src/SphericalHarmonics3.ts +++ b/packages/math/src/SphericalHarmonics3.ts @@ -1,5 +1,6 @@ -import { IClone } from "./IClone"; import { Color } from "./Color"; +import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { Vector3 } from "./Vector3"; /** @@ -9,7 +10,9 @@ import { Vector3 } from "./Vector3"; * http://www.ppsloan.org/publications/StupidSH36.pdf * https://google.github.io/filament/Filament.md.html#annex/sphericalharmonics */ -export class SphericalHarmonics3 implements IClone { +export class SphericalHarmonics3 + implements IClone, ICopy +{ /** The coefficients of SphericalHarmonics3. */ coefficients: Float32Array = new Float32Array(27); @@ -125,7 +128,7 @@ export class SphericalHarmonics3 implements IClone { g += coe[13] * bv4 + coe[16] * bv5 + coe[19] * bv6 + coe[22] * bv7 + coe[25] * bv8; b += coe[14] * bv4 + coe[17] * bv5 + coe[20] * bv6 + coe[23] * bv7 + coe[26] * bv8; - out.setValue(r, g, b, 1.0); + out.set(r, g, b, 1.0); return out; } @@ -148,11 +151,31 @@ export class SphericalHarmonics3 implements IClone { } /** - * Set the value of this spherical harmonics by an array. + * Creates a clone of this SphericalHarmonics3. + * @returns A clone of this SphericalHarmonics3 + */ + clone(): SphericalHarmonics3 { + const sh = new SphericalHarmonics3(); + sh.copyFrom(this); + return sh; + } + + /** + * Copy this SphericalHarmonics3 from the specified SphericalHarmonics3. + * @param source - The specified SphericalHarmonics3 + * @returns This SphericalHarmonics3 + */ + copyFrom(source: SphericalHarmonics3): SphericalHarmonics3 { + source.copyToArray(this.coefficients); + return this; + } + + /** + * Copy the value of this spherical harmonics from an array. * @param array - The array * @param offset - The start offset of the array */ - setValueByArray(array: ArrayLike, offset: number = 0): void { + copyFromArray(array: ArrayLike, offset: number = 0): void { const s = this.coefficients; (s[0] = array[offset]), (s[1] = array[1 + offset]), (s[2] = array[2 + offset]); @@ -167,11 +190,11 @@ export class SphericalHarmonics3 implements IClone { } /** - * Clone the value of this spherical harmonics to an array. + * Copy the value of this spherical harmonics to an array. * @param out - The array * @param outOffset - The start offset of the array */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0): void { + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0): void { const s = this.coefficients; (out[0 + outOffset] = s[0]), (out[1 + outOffset] = s[1]), (out[2 + outOffset] = s[2]); @@ -186,25 +209,4 @@ export class SphericalHarmonics3 implements IClone { (out[21 + outOffset] = s[21]), (out[22 + outOffset] = s[22]), (out[23 + outOffset] = s[23]); (out[24 + outOffset] = s[24]), (out[25 + outOffset] = s[25]), (out[26 + outOffset] = s[26]); } - - /** - * Creates a clone of this SphericalHarmonics3. - * @returns A clone of this SphericalHarmonics3 - */ - clone(): SphericalHarmonics3 { - const v = new SphericalHarmonics3(); - this.cloneTo(v); - - return v; - } - - /** - * Clones this SphericalHarmonics3 to the specified SphericalHarmonics3. - * @param out - The specified SphericalHarmonics3 - * @returns The specified SphericalHarmonics3 - */ - cloneTo(out: SphericalHarmonics3): SphericalHarmonics3 { - this.toArray(out.coefficients); - return out; - } } diff --git a/packages/math/src/Vector2.ts b/packages/math/src/Vector2.ts index 42f68f234e..da8a1d2f3c 100644 --- a/packages/math/src/Vector2.ts +++ b/packages/math/src/Vector2.ts @@ -1,10 +1,11 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; /** * Describes a 2D-vector. */ -export class Vector2 implements IClone { +export class Vector2 implements IClone, ICopy { /** @internal */ static readonly _zero = new Vector2(0.0, 0.0); /** @internal */ @@ -226,26 +227,13 @@ export class Vector2 implements IClone { * @param y - The y component of the vector * @returns This vector */ - setValue(x: number, y: number): Vector2 { + set(x: number, y: number): Vector2 { this._x = x; this._y = y; this._onValueChanged && this._onValueChanged(); return this; } - /** - * Set the value of this vector by an array. - * @param array - The array - * @param offset - The start offset of the array - * @returns This vector - */ - setValueByArray(array: ArrayLike, offset: number = 0): Vector2 { - this._x = array[offset]; - this._y = array[offset + 1]; - this._onValueChanged && this._onValueChanged(); - return this; - } - /** * Determines the sum of this vector and the specified vector. * @param right - The specified vector @@ -344,16 +332,6 @@ export class Vector2 implements IClone { return this; } - /** - * Clone the value of this vector to an array. - * @param out - The array - * @param outOffset - The start offset of the array - */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { - out[outOffset] = this._x; - out[outOffset + 1] = this._y; - } - /** * Creates a clone of this vector. * @returns A clone of this vector @@ -363,14 +341,44 @@ export class Vector2 implements IClone { } /** - * Clones this vector to the specified vector. - * @param out - The specified vector - * @returns The specified vector + * Copy from vector2 like object. + * @param source - Vector2 like object + * @returns This vector */ - cloneTo(out: Vector2): Vector2 { - out._x = this._x; - out._y = this._y; - out._onValueChanged && out._onValueChanged(); - return out; + copyFrom(source: Vector2Like): Vector2 { + this._x = source.x; + this._y = source.y; + this._onValueChanged && this._onValueChanged(); + return this; + } + + /** + * Copy the value of this vector from an array. + * @param array - The array + * @param offset - The start offset of the array + * @returns This vector + */ + copyFromArray(array: ArrayLike, offset: number = 0): Vector2 { + this._x = array[offset]; + this._y = array[offset + 1]; + this._onValueChanged && this._onValueChanged(); + return this; } + + /** + * Copy the value of this vector to an array. + * @param out - The array + * @param outOffset - The start offset of the array + */ + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { + out[outOffset] = this._x; + out[outOffset + 1] = this._y; + } +} + +interface Vector2Like { + /** {@inheritDoc Vector2.x} */ + x: number; + /** {@inheritDoc Vector2.y} */ + y: number; } diff --git a/packages/math/src/Vector3.ts b/packages/math/src/Vector3.ts index c4cdcce4ec..b41ff454bb 100644 --- a/packages/math/src/Vector3.ts +++ b/packages/math/src/Vector3.ts @@ -1,4 +1,5 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; import { Matrix } from "./Matrix"; import { Quaternion } from "./Quaternion"; @@ -7,7 +8,7 @@ import { Vector4 } from "./Vector4"; /** * Describes a 3D-vector. */ -export class Vector3 implements IClone { +export class Vector3 implements IClone, ICopy { /** @internal */ static readonly _zero = new Vector3(0.0, 0.0, 0.0); /** @internal */ @@ -89,7 +90,7 @@ export class Vector3 implements IClone { const by = right._y; const bz = right._z; - out.setValue(ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx); + out.set(ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx); } /** @@ -193,7 +194,7 @@ export class Vector3 implements IClone { let len = Math.sqrt(_x * _x + _y * _y + _z * _z); if (len > MathUtil.zeroTolerance) { len = 1 / len; - out.setValue(_x * len, _y * len, _z * len); + out.set(_x * len, _y * len, _z * len); } } @@ -375,7 +376,7 @@ export class Vector3 implements IClone { * @param z - The z component of the vector * @returns This vector */ - setValue(x: number, y: number, z: number): Vector3 { + set(x: number, y: number, z: number): Vector3 { this._x = x; this._y = y; this._z = z; @@ -383,20 +384,6 @@ export class Vector3 implements IClone { return this; } - /** - * Set the value of this vector by an array. - * @param array - The array - * @param offset - The start offset of the array - * @returns This vector - */ - setValueByArray(array: ArrayLike, offset: number = 0): Vector3 { - this._x = array[offset]; - this._y = array[offset + 1]; - this._z = array[offset + 2]; - this._onValueChanged && this._onValueChanged(); - return this; - } - /** * Determines the sum of this vector and the specified vector. * @param right - The specified vector @@ -501,38 +488,6 @@ export class Vector3 implements IClone { return this; } - /** - * Clone the value of this vector to an array. - * @param out - The array - * @param outOffset - The start offset of the array - */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { - out[outOffset] = this._x; - out[outOffset + 1] = this._y; - out[outOffset + 2] = this._z; - } - - /** - * Creates a clone of this vector. - * @returns A clone of this vector - */ - clone(): Vector3 { - return new Vector3(this._x, this._y, this._z); - } - - /** - * Clones this vector to the specified vector. - * @param out - The specified vector - * @returns The specified vector - */ - cloneTo(out: Vector3): Vector3 { - out._x = this._x; - out._y = this._y; - out._z = this._z; - out._onValueChanged && out._onValueChanged(); - return out; - } - /** * This vector performs a normal transformation using the given 4x4 matrix. * @remarks @@ -584,4 +539,59 @@ export class Vector3 implements IClone { Vector3.transformByQuat(this, quaternion, this); return this; } + + /** + * Creates a clone of this vector. + * @returns A clone of this vector + */ + clone(): Vector3 { + return new Vector3(this._x, this._y, this._z); + } + + /** + * Copy from vector3 like object. + * @param source - Vector3 like object. + * @returns This vector + */ + copyFrom(source: Vector3Like): Vector3 { + this._x = source.x; + this._y = source.y; + this._z = source.z; + this._onValueChanged && this._onValueChanged(); + return this; + } + + /** + * Copy the value of this vector from an array. + * @param array - The array + * @param offset - The start offset of the array + * @returns This vector + */ + copyFromArray(array: ArrayLike, offset: number = 0): Vector3 { + this._x = array[offset]; + this._y = array[offset + 1]; + this._z = array[offset + 2]; + this._onValueChanged && this._onValueChanged(); + return this; + } + + /** + * Copy the value of this vector to an array. + * @param out - The array + * @param outOffset - The start offset of the array + */ + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { + out[outOffset] = this._x; + out[outOffset + 1] = this._y; + out[outOffset + 2] = this._z; + } +} + +interface Vector3Like { + /** {@inheritDoc Vector3.x} */ + x: number; + /** {@inheritDoc Vector3.y} */ + y: number; + /** {@inheritDoc Vector3.z} */ + z: number; } diff --git a/packages/math/src/Vector4.ts b/packages/math/src/Vector4.ts index 842938d727..cf749bd887 100644 --- a/packages/math/src/Vector4.ts +++ b/packages/math/src/Vector4.ts @@ -1,4 +1,5 @@ import { IClone } from "./IClone"; +import { ICopy } from "./ICopy"; import { MathUtil } from "./MathUtil"; import { Matrix } from "./Matrix"; import { Quaternion } from "./Quaternion"; @@ -6,7 +7,7 @@ import { Quaternion } from "./Quaternion"; /** * Describes a 4D-vector. */ -export class Vector4 implements IClone { +export class Vector4 implements IClone, ICopy { /** @internal */ static readonly _zero = new Vector4(0.0, 0.0, 0.0, 0.0); /** @internal */ @@ -334,7 +335,7 @@ export class Vector4 implements IClone { * @param w - The w component of the vector * @returns This vector */ - setValue(x: number, y: number, z: number, w: number): Vector4 { + set(x: number, y: number, z: number, w: number): Vector4 { this._x = x; this._y = y; this._z = z; @@ -343,21 +344,6 @@ export class Vector4 implements IClone { return this; } - /** - * Set the value of this vector by an array. - * @param array - The array - * @param offset - The start offset of the array - * @returns This vector - */ - setValueByArray(array: ArrayLike, offset: number = 0): Vector4 { - this._x = array[offset]; - this._y = array[offset + 1]; - this._z = array[offset + 2]; - this._w = array[offset + 3]; - this._onValueChanged && this._onValueChanged(); - return this; - } - /** * Determines the sum of this vector and the specified vector. * @param right - The specified vector @@ -468,18 +454,6 @@ export class Vector4 implements IClone { return this; } - /** - * Clone the value of this vector to an array. - * @param out - The array - * @param outOffset - The start offset of the array - */ - toArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { - out[outOffset] = this._x; - out[outOffset + 1] = this._y; - out[outOffset + 2] = this._z; - out[outOffset + 3] = this._w; - } - /** * Creates a clone of this vector. * @returns A clone of this vector @@ -490,16 +464,54 @@ export class Vector4 implements IClone { } /** - * Clones this vector to the specified vector. - * @param out - The specified vector - * @returns The specified vector + * Copy from vector3 like object. + * @param source - Vector3 like object. + * @returns This vector */ - cloneTo(out: Vector4): Vector4 { - out._x = this._x; - out._y = this._y; - out._z = this._z; - out._w = this._w; - out._onValueChanged && out._onValueChanged(); - return out; + copyFrom(source: Vector4Like): Vector4 { + this._x = source.x; + this._y = source.y; + this._z = source.z; + this._w = source.w; + this._onValueChanged && this._onValueChanged(); + return this; + } + + /** + * Copy the value of this vector by an array. + * @param array - The arrayƒ + * @param offset - The start offset of the array + * @returns This vector + */ + copyFromArray(array: ArrayLike, offset: number = 0): Vector4 { + this._x = array[offset]; + this._y = array[offset + 1]; + this._z = array[offset + 2]; + this._w = array[offset + 3]; + this._onValueChanged && this._onValueChanged(); + return this; } + + /** + * Copy the value of this vector to an array. + * @param out - The array + * @param outOffset - The start offset of the array + */ + copyToArray(out: number[] | Float32Array | Float64Array, outOffset: number = 0) { + out[outOffset] = this._x; + out[outOffset + 1] = this._y; + out[outOffset + 2] = this._z; + out[outOffset + 3] = this._w; + } +} + +interface Vector4Like { + /** {@inheritDoc Vector4.x} */ + x: number; + /** {@inheritDoc Vector4.y} */ + y: number; + /** {@inheritDoc Vector4.z} */ + z: number; + /** {@inheritDoc Vector4.w} */ + w: number; } diff --git a/packages/physics-lite/src/LiteCollider.ts b/packages/physics-lite/src/LiteCollider.ts index 8e9cdb28a6..35075f1b95 100644 --- a/packages/physics-lite/src/LiteCollider.ts +++ b/packages/physics-lite/src/LiteCollider.ts @@ -55,8 +55,8 @@ export abstract class LiteCollider implements ICollider { */ getWorldTransform(outPosition: Vector3, outRotation: Quaternion): void { const { position, rotationQuaternion } = this._transform; - outPosition.setValue(position.x, position.y, position.z); - outRotation.setValue(rotationQuaternion.x, rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w); + outPosition.set(position.x, position.y, position.z); + outRotation.set(rotationQuaternion.x, rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w); } /** diff --git a/packages/physics-lite/src/LitePhysicsManager.ts b/packages/physics-lite/src/LitePhysicsManager.ts index ff7b2ffc6b..c7e9d36488 100644 --- a/packages/physics-lite/src/LitePhysicsManager.ts +++ b/packages/physics-lite/src/LitePhysicsManager.ts @@ -1,12 +1,11 @@ import { ICharacterController, IPhysicsManager } from "@oasis-engine/design"; -import { BoundingBox, BoundingSphere, Ray, Vector3, CollisionUtil } from "oasis-engine"; +import { BoundingBox, BoundingSphere, CollisionUtil, Ray, Vector3 } from "oasis-engine"; +import { DisorderedArray } from "./DisorderedArray"; import { LiteCollider } from "./LiteCollider"; import { LiteHitResult } from "./LiteHitResult"; import { LiteBoxColliderShape } from "./shape/LiteBoxColliderShape"; -import { LiteSphereColliderShape } from "./shape/LiteSphereColliderShape"; import { LiteColliderShape } from "./shape/LiteColliderShape"; -import { DisorderedArray } from "./DisorderedArray"; -import { IColliderShape } from "@oasis-engine/design/src"; +import { LiteSphereColliderShape } from "./shape/LiteSphereColliderShape"; /** * A manager is a collection of bodies and constraints which can interact. @@ -130,8 +129,8 @@ export class LitePhysicsManager implements IPhysicsManager { isHit = true; if (curHit.distance < distance) { if (hitResult) { - curHit.normal.cloneTo(hitResult.normal); - curHit.point.cloneTo(hitResult.point); + hitResult.normal.copyFrom(curHit.normal); + hitResult.point.copyFrom(curHit.point); hitResult.distance = curHit.distance; hitResult.shapeID = curHit.shapeID; } else { @@ -145,8 +144,8 @@ export class LitePhysicsManager implements IPhysicsManager { if (!isHit && hitResult) { hitResult.shapeID = -1; hitResult.distance = 0; - hitResult.point.setValue(0, 0, 0); - hitResult.normal.setValue(0, 0, 0); + hitResult.point.set(0, 0, 0); + hitResult.normal.set(0, 0, 0); } else if (isHit && hitResult) { hit(hitResult.shapeID, hitResult.distance, hitResult.point, hitResult.normal); } @@ -174,8 +173,8 @@ export class LitePhysicsManager implements IPhysicsManager { */ private static _updateWorldBox(boxCollider: LiteBoxColliderShape, out: BoundingBox): void { const mat = boxCollider._transform.worldMatrix; - boxCollider._boxMax.cloneTo(out.max); - boxCollider._boxMin.cloneTo(out.min); + out.min.copyFrom(boxCollider._boxMin); + out.max.copyFrom(boxCollider._boxMax); BoundingBox.transform(out, mat, out); } diff --git a/packages/physics-lite/src/LiteTransform.ts b/packages/physics-lite/src/LiteTransform.ts index 11fd85c619..338956eea7 100644 --- a/packages/physics-lite/src/LiteTransform.ts +++ b/packages/physics-lite/src/LiteTransform.ts @@ -1,8 +1,8 @@ import { MathUtil, Matrix, Quaternion, Vector3 } from "oasis-engine"; -import { LiteUpdateFlagManager } from "./LiteUpdateFlagManager"; +import { LiteCollider } from "./LiteCollider"; import { LiteUpdateFlag } from "./LiteUpdateFlag"; +import { LiteUpdateFlagManager } from "./LiteUpdateFlagManager"; import { LiteColliderShape } from "./shape/LiteColliderShape"; -import { LiteCollider } from "./LiteCollider"; /** * Used to implement transformation related functions. @@ -39,7 +39,7 @@ export class LiteTransform { set position(value: Vector3) { if (this._position !== value) { - value.cloneTo(this._position); + this._position.copyFrom(value); } this._setDirtyFlagTrue(TransformFlag.LocalMatrix); this._updateWorldPositionFlag(); @@ -64,7 +64,7 @@ export class LiteTransform { set rotationQuaternion(value: Quaternion) { if (this._rotationQuaternion !== value) { - value.cloneTo(this._rotationQuaternion); + this._rotationQuaternion.copyFrom(value); } this._setDirtyFlagTrue(TransformFlag.LocalMatrix | TransformFlag.LocalEuler); this._setDirtyFlagFalse(TransformFlag.LocalQuat); @@ -81,7 +81,7 @@ export class LiteTransform { if (parent != null) { Quaternion.multiply(parent.worldRotationQuaternion, this.rotationQuaternion, this._worldRotationQuaternion); } else { - this.rotationQuaternion.cloneTo(this._worldRotationQuaternion); + this._worldRotationQuaternion.copyFrom(this.rotationQuaternion); } this._setDirtyFlagFalse(TransformFlag.WorldQuat); } @@ -90,14 +90,14 @@ export class LiteTransform { set worldRotationQuaternion(value: Quaternion) { if (this._worldRotationQuaternion !== value) { - value.cloneTo(this._worldRotationQuaternion); + this._worldRotationQuaternion.copyFrom(value); } const parent = this._getParentTransform(); if (parent) { Quaternion.invert(parent.worldRotationQuaternion, LiteTransform._tempQuat0); Quaternion.multiply(value, LiteTransform._tempQuat0, this._rotationQuaternion); } else { - value.cloneTo(this._rotationQuaternion); + this._rotationQuaternion.copyFrom(value); } this.rotationQuaternion = this._rotationQuaternion; this._setDirtyFlagFalse(TransformFlag.WorldQuat); @@ -113,7 +113,7 @@ export class LiteTransform { set scale(value: Vector3) { if (this._scale !== value) { - value.cloneTo(this._scale); + this._scale.copyFrom(value); } this._setDirtyFlagTrue(TransformFlag.LocalMatrix); this._updateWorldScaleFlag(); @@ -133,7 +133,7 @@ export class LiteTransform { set localMatrix(value: Matrix) { if (this._localMatrix !== value) { - value.cloneTo(this._localMatrix); + this._localMatrix.copyFrom(value); } this._localMatrix.decompose(this._position, this._rotationQuaternion, this._scale); this._setDirtyFlagTrue(TransformFlag.LocalEuler); @@ -151,7 +151,7 @@ export class LiteTransform { if (parent) { Matrix.multiply(parent.worldMatrix, this.localMatrix, this._worldMatrix); } else { - this.localMatrix.cloneTo(this._worldMatrix); + this._worldMatrix.copyFrom(this.localMatrix); } this._setDirtyFlagFalse(TransformFlag.WorldMatrix); } @@ -160,14 +160,14 @@ export class LiteTransform { set worldMatrix(value: Matrix) { if (this._worldMatrix !== value) { - value.cloneTo(this._worldMatrix); + this._worldMatrix.copyFrom(value); } const parent = this._getParentTransform(); if (parent) { Matrix.invert(parent.worldMatrix, LiteTransform._tempMat42); Matrix.multiply(value, LiteTransform._tempMat42, this._localMatrix); } else { - value.cloneTo(this._localMatrix); + this._localMatrix.copyFrom(value); } this.localMatrix = this._localMatrix; this._setDirtyFlagFalse(TransformFlag.WorldMatrix); @@ -180,7 +180,7 @@ export class LiteTransform { * @param z - Z coordinate */ setPosition(x: number, y: number, z: number): void { - this._position.setValue(x, y, z); + this._position.set(x, y, z); this.position = this._position; } @@ -192,7 +192,7 @@ export class LiteTransform { * @param w - W component of quaternion */ setRotationQuaternion(x: number, y: number, z: number, w: number): void { - this._rotationQuaternion.setValue(x, y, z, w); + this._rotationQuaternion.set(x, y, z, w); this.rotationQuaternion = this._rotationQuaternion; } @@ -203,7 +203,7 @@ export class LiteTransform { * @param z - Scaling along Z axis */ setScale(x: number, y: number, z: number): void { - this._scale.setValue(x, y, z); + this._scale.set(x, y, z); this.scale = this._scale; } diff --git a/packages/physics-lite/src/shape/LiteBoxColliderShape.ts b/packages/physics-lite/src/shape/LiteBoxColliderShape.ts index 73d2d40fad..29169009c7 100644 --- a/packages/physics-lite/src/shape/LiteBoxColliderShape.ts +++ b/packages/physics-lite/src/shape/LiteBoxColliderShape.ts @@ -25,7 +25,7 @@ export class LiteBoxColliderShape extends LiteColliderShape implements IBoxColli constructor(uniqueID: number, size: Vector3, material: LitePhysicsMaterial) { super(); this._id = uniqueID; - this._halfSize.setValue(size.x * 0.5, size.y * 0.5, size.z * 0.5); + this._halfSize.set(size.x * 0.5, size.y * 0.5, size.z * 0.5); this._setBondingBox(); } @@ -49,7 +49,7 @@ export class LiteBoxColliderShape extends LiteColliderShape implements IBoxColli * {@inheritDoc IBoxColliderShape.setSize } */ setSize(value: Vector3): void { - this._halfSize.setValue(value.x * 0.5, value.y * 0.5, value.z * 0.5); + this._halfSize.set(value.x * 0.5, value.y * 0.5, value.z * 0.5); this._setBondingBox(); } @@ -60,8 +60,8 @@ export class LiteBoxColliderShape extends LiteColliderShape implements IBoxColli const localRay = this._getLocalRay(ray); const boundingBox = LiteBoxColliderShape._tempBox; - boundingBox.min.setValue(-this._halfSize.x, -this._halfSize.y, -this._halfSize.z); - boundingBox.max.setValue(this._halfSize.x, this._halfSize.y, this._halfSize.z); + boundingBox.min.set(-this._halfSize.x, -this._halfSize.y, -this._halfSize.z); + boundingBox.max.set(this._halfSize.x, this._halfSize.y, this._halfSize.z); const rayDistance = localRay.intersectBox(boundingBox); if (rayDistance !== -1) { this._updateHitResult(localRay, rayDistance, hit, ray.origin); diff --git a/packages/physics-lite/src/shape/LiteColliderShape.ts b/packages/physics-lite/src/shape/LiteColliderShape.ts index 39ffb4f2b6..aa78e32dfb 100644 --- a/packages/physics-lite/src/shape/LiteColliderShape.ts +++ b/packages/physics-lite/src/shape/LiteColliderShape.ts @@ -1,8 +1,8 @@ import { IColliderShape, IPhysicsMaterial } from "@oasis-engine/design"; import { Matrix, Ray, Vector3 } from "oasis-engine"; +import { LiteCollider } from "../LiteCollider"; import { LiteHitResult } from "../LiteHitResult"; import { LiteTransform } from "../LiteTransform"; -import { LiteCollider } from "../LiteCollider"; import { LiteUpdateFlag } from "../LiteUpdateFlag"; /** @@ -101,7 +101,7 @@ export abstract class LiteColliderShape implements IColliderShape { const distance = Vector3.distance(origin, hitPoint); if (distance < outHit.distance) { - hitPoint.cloneTo(outHit.point); + outHit.point.copyFrom(hitPoint); outHit.distance = distance; outHit.shapeID = this._id; } diff --git a/packages/physics-physx/src/PhysXCharacterController.ts b/packages/physics-physx/src/PhysXCharacterController.ts index 30e69337e6..cb2d90a5fa 100644 --- a/packages/physics-physx/src/PhysXCharacterController.ts +++ b/packages/physics-physx/src/PhysXCharacterController.ts @@ -36,11 +36,7 @@ export class PhysXCharacterController implements ICharacterController { * {@inheritDoc ICharacterController.getWorldPosition } */ getWorldPosition(position: Vector3): void { - position.setValue( - this._pxController.getPosition().x, - this._pxController.getPosition().y, - this._pxController.getPosition().z - ); + position.copyFrom(this._pxController.getPosition()); } /** diff --git a/packages/physics-physx/src/PhysXCollider.ts b/packages/physics-physx/src/PhysXCollider.ts index 86203c8940..feaad1e385 100644 --- a/packages/physics-physx/src/PhysXCollider.ts +++ b/packages/physics-physx/src/PhysXCollider.ts @@ -40,8 +40,8 @@ export abstract class PhysXCollider implements ICollider { */ getWorldTransform(outPosition: Vector3, outRotation: Quaternion): void { const transform = this._pxActor.getGlobalPose(); - outPosition.setValue(transform.translation.x, transform.translation.y, transform.translation.z); - outRotation.setValue(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w); + outPosition.set(transform.translation.x, transform.translation.y, transform.translation.z); + outRotation.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w); } /** diff --git a/packages/physics-physx/src/PhysXDynamicCollider.ts b/packages/physics-physx/src/PhysXDynamicCollider.ts index 05b6d1bb15..bcd2746b42 100644 --- a/packages/physics-physx/src/PhysXDynamicCollider.ts +++ b/packages/physics-physx/src/PhysXDynamicCollider.ts @@ -1,7 +1,7 @@ -import { PhysXPhysics } from "./PhysXPhysics"; -import { Quaternion, Vector3 } from "oasis-engine"; import { IDynamicCollider } from "@oasis-engine/design"; +import { Quaternion, Vector3 } from "oasis-engine"; import { PhysXCollider } from "./PhysXCollider"; +import { PhysXPhysics } from "./PhysXPhysics"; /** * The collision detection mode constants used for PhysXDynamicCollider.collisionDetectionMode. @@ -48,14 +48,14 @@ export class PhysXDynamicCollider extends PhysXCollider implements IDynamicColli * {@inheritDoc IDynamicCollider.setLinearVelocity } */ setLinearVelocity(value: Vector3): void { - this._pxActor.setLinearVelocity({ x: value.x, y: value.y, z: value.z }, true); + this._pxActor.setLinearVelocity(value, true); } /** * {@inheritDoc IDynamicCollider.setAngularVelocity } */ setAngularVelocity(value: Vector3): void { - this._pxActor.setAngularVelocity({ x: value.x, y: value.y, z: value.z }, true); + this._pxActor.setAngularVelocity(value, true); } /** diff --git a/packages/physics-physx/src/PhysXPhysicsManager.ts b/packages/physics-physx/src/PhysXPhysicsManager.ts index e26790a957..8ca699c03d 100644 --- a/packages/physics-physx/src/PhysXPhysicsManager.ts +++ b/packages/physics-physx/src/PhysXPhysicsManager.ts @@ -203,8 +203,8 @@ export class PhysXPhysicsManager implements IPhysicsManager { if (result && hit != undefined) { const { _tempPosition: position, _tempNormal: normal } = PhysXPhysicsManager; const { position: pxPosition, normal: pxNormal } = pxHitResult; - position.setValue(pxPosition.x, pxPosition.y, pxPosition.z); - normal.setValue(pxNormal.x, pxNormal.y, pxNormal.z); + position.set(pxPosition.x, pxPosition.y, pxPosition.z); + normal.set(pxNormal.x, pxNormal.y, pxNormal.z); hit(pxHitResult.getShape().getQueryFilterData().word0, pxHitResult.distance, position, normal); } diff --git a/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts b/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts index 1bd13f9378..2b10f71ab2 100644 --- a/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXBoxColliderShape.ts @@ -21,7 +21,7 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol constructor(uniqueID: number, size: Vector3, material: PhysXPhysicsMaterial) { super(); - this._halfSize.setValue(size.x * 0.5, size.y * 0.5, size.z * 0.5); + this._halfSize.set(size.x * 0.5, size.y * 0.5, size.z * 0.5); this._pxGeometry = new PhysXPhysics._physX.PxBoxGeometry( this._halfSize.x * this._scale.x, @@ -36,7 +36,7 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol * {@inheritDoc IBoxColliderShape.setSize } */ setSize(value: Vector3): void { - this._halfSize.setValue(value.x * 0.5, value.y * 0.5, value.z * 0.5); + this._halfSize.set(value.x * 0.5, value.y * 0.5, value.z * 0.5); Vector3.multiply(this._halfSize, this._scale, PhysXBoxColliderShape._tempHalfExtents); this._pxGeometry.halfExtents = PhysXBoxColliderShape._tempHalfExtents; this._pxShape.setGeometry(this._pxGeometry); @@ -54,7 +54,7 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol * {@inheritDoc IColliderShape.setWorldScale } */ setWorldScale(scale: Vector3): void { - scale.cloneTo(this._scale); + this._scale.copyFrom(scale); this._setLocalPose(); Vector3.multiply(this._halfSize, this._scale, PhysXBoxColliderShape._tempHalfExtents); diff --git a/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts b/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts index 9402d50292..3b704cc4d6 100644 --- a/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXCapsuleColliderShape.ts @@ -87,13 +87,13 @@ export class PhysXCapsuleColliderShape extends PhysXColliderShape implements ICa this._upAxis = upAxis; switch (this._upAxis) { case ColliderShapeUpAxis.X: - this._rotation.setValue(0, 0, 0, 1); + this._rotation.set(0, 0, 0, 1); break; case ColliderShapeUpAxis.Y: - this._rotation.setValue(0, 0, PhysXColliderShape.halfSqrt, PhysXColliderShape.halfSqrt); + this._rotation.set(0, 0, PhysXColliderShape.halfSqrt, PhysXColliderShape.halfSqrt); break; case ColliderShapeUpAxis.Z: - this._rotation.setValue(0, PhysXColliderShape.halfSqrt, 0, PhysXColliderShape.halfSqrt); + this._rotation.set(0, PhysXColliderShape.halfSqrt, 0, PhysXColliderShape.halfSqrt); break; } this._setLocalPose(); @@ -103,7 +103,7 @@ export class PhysXCapsuleColliderShape extends PhysXColliderShape implements ICa * {@inheritDoc IColliderShape.setWorldScale } */ setWorldScale(scale: Vector3): void { - scale.cloneTo(this._scale); + this._scale.copyFrom(scale); this._setLocalPose(); switch (this._upAxis) { diff --git a/packages/physics-physx/src/shape/PhysXColliderShape.ts b/packages/physics-physx/src/shape/PhysXColliderShape.ts index a398772bc8..06a24765c9 100644 --- a/packages/physics-physx/src/shape/PhysXColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXColliderShape.ts @@ -52,7 +52,7 @@ export abstract class PhysXColliderShape implements IColliderShape { */ setPosition(value: Vector3): void { if (value !== this._position) { - value.cloneTo(this._position); + this._position.copyFrom(value); } this._setLocalPose(); } diff --git a/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts b/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts index bfcead098e..98b3d6ae09 100644 --- a/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXPlaneColliderShape.ts @@ -1,8 +1,8 @@ -import { PhysXColliderShape } from "./PhysXColliderShape"; import { IPlaneColliderShape } from "@oasis-engine/design"; -import { PhysXPhysicsMaterial } from "../PhysXPhysicsMaterial"; -import { PhysXPhysics } from "../PhysXPhysics"; import { Quaternion, Vector3 } from "oasis-engine"; +import { PhysXPhysics } from "../PhysXPhysics"; +import { PhysXPhysicsMaterial } from "../PhysXPhysicsMaterial"; +import { PhysXColliderShape } from "./PhysXColliderShape"; /** * Plane collider shape in PhysX. @@ -15,7 +15,7 @@ export class PhysXPlaneColliderShape extends PhysXColliderShape implements IPlan */ constructor(uniqueID: number, material: PhysXPhysicsMaterial) { super(); - this._rotation.setValue(0, 0, PhysXColliderShape.halfSqrt, PhysXColliderShape.halfSqrt); + this._rotation.set(0, 0, PhysXColliderShape.halfSqrt, PhysXColliderShape.halfSqrt); this._pxGeometry = new PhysXPhysics._physX.PxPlaneGeometry(); this._initialize(material, uniqueID); @@ -36,7 +36,7 @@ export class PhysXPlaneColliderShape extends PhysXColliderShape implements IPlan * {@inheritDoc IColliderShape.setWorldScale } */ setWorldScale(scale: Vector3): void { - scale.cloneTo(this._scale); + this._scale.copyFrom(scale); this._setLocalPose(); } } diff --git a/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts b/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts index 054f0f563c..a668372d1a 100644 --- a/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts +++ b/packages/physics-physx/src/shape/PhysXSphereColliderShape.ts @@ -40,7 +40,7 @@ export class PhysXSphereColliderShape extends PhysXColliderShape implements ISph * {@inheritDoc IColliderShape.setWorldScale } */ setWorldScale(scale: Vector3): void { - scale.cloneTo(this._scale); + this._scale.copyFrom(scale); this._setLocalPose(); this._maxScale = Math.max(scale.x, Math.max(scale.x, scale.y)); diff --git a/packages/rhi-webgl/src/WebCanvas.ts b/packages/rhi-webgl/src/WebCanvas.ts index cd057bee87..01e545e12d 100644 --- a/packages/rhi-webgl/src/WebCanvas.ts +++ b/packages/rhi-webgl/src/WebCanvas.ts @@ -48,7 +48,7 @@ export class WebCanvas implements Canvas { get scale(): Vector2 { const webCanvas = this._webCanvas; if (webCanvas instanceof HTMLCanvasElement) { - this._scale.setValue( + this._scale.set( (webCanvas.clientWidth * devicePixelRatio) / webCanvas.width, (webCanvas.clientHeight * devicePixelRatio) / webCanvas.height ); @@ -94,7 +94,7 @@ export class WebCanvas implements Canvas { * @param y - Scale along the Y axis */ setScale(x: number, y: number): void { - this._scale.setValue(x, y); + this._scale.set(x, y); this.scale = this._scale; } } diff --git a/packages/rhi-webgl/src/WebGLRenderer.ts b/packages/rhi-webgl/src/WebGLRenderer.ts index ffb0181218..63498418ee 100644 --- a/packages/rhi-webgl/src/WebGLRenderer.ts +++ b/packages/rhi-webgl/src/WebGLRenderer.ts @@ -189,7 +189,7 @@ export class WebGLRenderer implements IHardwareRenderer { if (x !== lv.x || y !== lv.y || width !== lv.z || height !== lv.w) { gl.viewport(x, y, width, height); - lv.setValue(x, y, width, height); + lv.set(x, y, width, height); } } @@ -219,7 +219,7 @@ export class WebGLRenderer implements IHardwareRenderer { if (clearColor && (r !== lc.r || g !== lc.g || b !== lc.b || a !== lc.a)) { gl.clearColor(r, g, b, a); - lc.setValue(r, g, b, a); + lc.set(r, g, b, a); } if (targetBlendState.colorWriteMask !== ColorWriteMask.All) { From 4f4c5fe25666d81b0d8bf5b828a9fb21cd56a9d3 Mon Sep 17 00:00:00 2001 From: ChenMo Date: Wed, 29 Jun 2022 10:49:49 +0800 Subject: [PATCH 18/33] Fix transform`translate` and `rotate` space bug (#847) * fix: transform`translate` and `rotate` space bug * refactor: opt comments --- packages/core/src/Transform.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index eb1732740b..a0633b932c 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -429,7 +429,7 @@ export class Transform extends Component { /** * Translate in the direction and distance of the translation. * @param translation - Direction and distance of translation - * @param relativeToLocal - Is relative to the local coordinate system + * @param relativeToLocal = `true` - Is relative to the local coordinate system */ translate(translation: Vector3, relativeToLocal?: boolean): void; @@ -438,7 +438,7 @@ export class Transform extends Component { * @param x - Distance along the x axis * @param y - Distance along the y axis * @param z - Distance along the z axis - * @param relativeToLocal - Is relative to the local coordinate system + * @param relativeToLocal = `true` - Is relative to the local coordinate system */ translate(x: number, y: number, z: number, relativeToLocal?: boolean): void; @@ -460,7 +460,7 @@ export class Transform extends Component { /** * Rotate around the passed Vector3. * @param rotation - Euler angle in degrees - * @param relativeToLocal - Is relative to the local coordinate system + * @param relativeToLocal = `true` - Is relative to the local coordinate system */ rotate(rotation: Vector3, relativeToLocal?: boolean): void; @@ -469,7 +469,7 @@ export class Transform extends Component { * @param x - Rotation along x axis, in degrees * @param y - Rotation along y axis, in degrees * @param z - Rotation along z axis, in degrees - * @param relativeToLocal - Is relative to the local coordinate system + * @param relativeToLocal = `true` - Is relative to the local coordinate system */ rotate(x: number, y: number, z: number, relativeToLocal?: boolean): void; @@ -490,7 +490,7 @@ export class Transform extends Component { * Rotate around the specified axis according to the specified angle. * @param axis - Rotate axis * @param angle - Rotate angle in degrees - * @param relativeToLocal - Relative to local space + * @param relativeToLocal = `true` - Relative to local space */ rotateByAxis(axis: Vector3, angle: number, relativeToLocal: boolean = true): void { const rad = angle * MathUtil.degreeToRadFactor; @@ -719,7 +719,7 @@ export class Transform extends Component { } } - private _translate(translation: Vector3, relativeToLocal: boolean): void { + private _translate(translation: Vector3, relativeToLocal: boolean = true): void { if (relativeToLocal) { const { _tempVec30 } = Transform; Vector3.transformByQuat(translation, this.worldRotationQuaternion, _tempVec30); @@ -729,7 +729,7 @@ export class Transform extends Component { } } - private _rotateXYZ(x: number, y: number, z: number, relativeToLocal: boolean): void { + private _rotateXYZ(x: number, y: number, z: number, relativeToLocal: boolean = true): void { const radFactor = MathUtil.degreeToRadFactor; const rotQuat = Transform._tempQuat0; Quaternion.rotationEuler(x * radFactor, y * radFactor, z * radFactor, rotQuat); From b898aa527a7dbec859a86d53e0ec6bc62628bd65 Mon Sep 17 00:00:00 2001 From: AZhan Date: Wed, 29 Jun 2022 15:14:02 +0800 Subject: [PATCH 19/33] Feat(core): add more clear flag item for Camera.clearFlags (#843) * feat(core): add more clear flag item for Camera.clearFlags --- packages/core/src/Camera.ts | 4 +- .../src/RenderPipeline/BasicRenderPipeline.ts | 2 +- packages/core/src/enums/CameraClearFlags.ts | 22 +++++-- .../core/src/input/pointer/PointerManager.ts | 2 +- packages/rhi-webgl/src/WebGLRenderer.ts | 58 ++++++++++--------- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 0b680020ab..1ad0840081 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -47,9 +47,9 @@ export class Camera extends Component { /** * Determining what to clear when rendering by a Camera. - * @defaultValue `CameraClearFlags.DepthColor` + * @defaultValue `CameraClearFlags.All` */ - clearFlags: CameraClearFlags = CameraClearFlags.DepthColor; + clearFlags: CameraClearFlags = CameraClearFlags.All; /** * Culling mask - which layers the camera renders. diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index ad87cb5eb2..e48a7ad4d2 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -180,7 +180,7 @@ export class BasicRenderPipeline { } else { this._opaqueQueue.render(camera, pass.replaceMaterial, pass.mask); this._alphaTestQueue.render(camera, pass.replaceMaterial, pass.mask); - if (camera.clearFlags === CameraClearFlags.DepthColor) { + if (camera.clearFlags & CameraClearFlags.Color) { if (background.mode === BackgroundMode.Sky) { this._drawSky(engine, camera, background.sky); } else if (background.mode === BackgroundMode.Texture && background.texture) { diff --git a/packages/core/src/enums/CameraClearFlags.ts b/packages/core/src/enums/CameraClearFlags.ts index 7651e1a595..7646cfbe19 100644 --- a/packages/core/src/enums/CameraClearFlags.ts +++ b/packages/core/src/enums/CameraClearFlags.ts @@ -2,10 +2,22 @@ * Camera clear flags enumeration. */ export enum CameraClearFlags { - /* Clear depth and color from background. */ - DepthColor, - /* Clear depth only. */ - Depth, /* Do nothing. */ - None + None = 0x0, + /* Clear color with scene background. */ + Color = 0x1, + /* Clear depth only. */ + Depth = 0x2, + /* Clear depth only. */ + Stencil = 0x4, + + /* Clear color with scene background and depth. */ + ColorDepth = 0x3, + /* Clear color with scene background and stencil. */ + ColorStencil = 0x5, + /* Clear depth and stencil. */ + DepthStencil = 0x6, + + /* Clear color with scene background, depth, and stencil. */ + All = 0x7 } diff --git a/packages/core/src/input/pointer/PointerManager.ts b/packages/core/src/input/pointer/PointerManager.ts index 4ce88b4dc0..bdd6e9aefe 100644 --- a/packages/core/src/input/pointer/PointerManager.ts +++ b/packages/core/src/input/pointer/PointerManager.ts @@ -244,7 +244,7 @@ export class PointerManager { // TODO: Only check which colliders have listened to the input. if (this._engine.physicsManager.raycast(camera.viewportPointToRay(point, ray), hitResult)) { return hitResult.entity; - } else if (camera.clearFlags === CameraClearFlags.DepthColor) { + } else if (camera.clearFlags & CameraClearFlags.Color) { return null; } } diff --git a/packages/rhi-webgl/src/WebGLRenderer.ts b/packages/rhi-webgl/src/WebGLRenderer.ts index 63498418ee..b6ce70250e 100644 --- a/packages/rhi-webgl/src/WebGLRenderer.ts +++ b/packages/rhi-webgl/src/WebGLRenderer.ts @@ -66,6 +66,7 @@ export class WebGLRenderer implements IHardwareRenderer { private _extensions; private _capability: GLCapability; private _isWebGL2: boolean; + private _webCanvas: WebCanvas; private _activeTextureID: number; private _activeTextures: GLTexture[] = new Array(32); @@ -73,6 +74,7 @@ export class WebGLRenderer implements IHardwareRenderer { // cache value private _lastViewport: Vector4 = new Vector4(null, null, null, null); private _lastClearColor: Color = new Color(null, null, null, null); + private _scissorEnable: boolean = false; get isWebGL2() { return this._isWebGL2; @@ -106,8 +108,7 @@ export class WebGLRenderer implements IHardwareRenderer { const option = this._options; option.alpha === undefined && (option.alpha = false); option.stencil === undefined && (option.stencil = true); - - const webCanvas = (canvas as WebCanvas)._webCanvas; + const webCanvas = (this._webCanvas = (canvas as WebCanvas)._webCanvas); const webGLMode = option.webGLMode || WebGLMode.Auto; let gl: (WebGLRenderingContext & WebGLExtension) | WebGL2RenderingContext; @@ -182,12 +183,21 @@ export class WebGLRenderer implements IHardwareRenderer { } viewport(x: number, y: number, width: number, height: number): void { - // gl.enable(gl.SCISSOR_TEST); - // gl.scissor(x, transformY, width, height); - const gl = this._gl; - const lv = this._lastViewport; - + const { _gl: gl, _lastViewport: lv } = this; if (x !== lv.x || y !== lv.y || width !== lv.z || height !== lv.w) { + const { _webCanvas: webCanvas } = this; + if (x === 0 && y === 0 && width === webCanvas.width && height === webCanvas.height) { + if (this._scissorEnable) { + gl.disable(gl.SCISSOR_TEST); + this._scissorEnable = false; + } + } else { + if (!this._scissorEnable) { + gl.enable(gl.SCISSOR_TEST); + this._scissorEnable = true; + } + gl.scissor(x, y, width, height); + } gl.viewport(x, y, width, height); lv.set(x, y, width, height); } @@ -197,26 +207,19 @@ export class WebGLRenderer implements IHardwareRenderer { this._gl.colorMask(r, g, b, a); } - clearRenderTarget( - engine: Engine, - clearFlags: CameraClearFlags.Depth | CameraClearFlags.DepthColor, - clearColor: Color - ) { + clearRenderTarget(engine: Engine, clearFlags: CameraClearFlags, clearColor: Color) { const gl = this._gl; const { blendState: { targetBlendState }, depthState, stencilState } = engine._lastRenderState; - - let clearFlag = gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT; - - if (clearFlags === CameraClearFlags.DepthColor) { + let clearFlag = 0; + if (clearFlags & CameraClearFlags.Color) { clearFlag |= gl.COLOR_BUFFER_BIT; const lc = this._lastClearColor; const { r, g, b, a } = clearColor; - if (clearColor && (r !== lc.r || g !== lc.g || b !== lc.b || a !== lc.a)) { gl.clearColor(r, g, b, a); lc.set(r, g, b, a); @@ -227,17 +230,20 @@ export class WebGLRenderer implements IHardwareRenderer { targetBlendState.colorWriteMask = ColorWriteMask.All; } } - - if (depthState.writeEnabled !== true) { - gl.depthMask(true); - depthState.writeEnabled = true; + if (clearFlags & CameraClearFlags.Depth) { + clearFlag |= gl.DEPTH_BUFFER_BIT; + if (depthState.writeEnabled !== true) { + gl.depthMask(true); + depthState.writeEnabled = true; + } } - - if (stencilState.writeMask !== 0xff) { - gl.stencilMask(0xff); - stencilState.writeMask = 0xff; + if (clearFlags & CameraClearFlags.Stencil) { + clearFlag |= gl.STENCIL_BUFFER_BIT; + if (stencilState.writeMask !== 0xff) { + gl.stencilMask(0xff); + stencilState.writeMask = 0xff; + } } - gl.clear(clearFlag); } From dba43c1e4deace8cccc82b6fc437cf5f8f08ff18 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 29 Jun 2022 15:57:54 +0800 Subject: [PATCH 20/33] v0.8.0-alpha.0 --- lerna.json | 2 +- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- tests/package.json | 4 ++-- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/lerna.json b/lerna.json index 70794d55c2..f785fca7c2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index dc24d391d2..a798c9e61c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.7.0-beta.7" + "@oasis-engine/math": "0.8.0-alpha.0" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.7" + "@oasis-engine/design": "0.8.0-alpha.0" } } diff --git a/packages/design/package.json b/packages/design/package.json index 5e8250b3db..f81d72c003 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -13,6 +13,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.7.0-beta.7" + "@oasis-engine/math": "0.8.0-alpha.0" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 8fd5741a1a..1158844aad 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "scripts": { "b:types": "tsc" @@ -13,6 +13,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.7" + "@oasis-engine/core": "0.8.0-alpha.0" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index 165fe4027d..aaf776d2df 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "types": "types/index.d.ts", "scripts": { @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.7", - "@oasis-engine/draco": "0.7.0-beta.7", - "@oasis-engine/math": "0.7.0-beta.7", - "@oasis-engine/rhi-webgl": "0.7.0-beta.7" + "@oasis-engine/core": "0.8.0-alpha.0", + "@oasis-engine/draco": "0.8.0-alpha.0", + "@oasis-engine/math": "0.8.0-alpha.0", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.0" } } diff --git a/packages/math/package.json b/packages/math/package.json index 404408608c..7ecb9498bf 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index 04b1aa8ef5..429d4926cf 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "scripts": { "b:types": "tsc" @@ -14,9 +14,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.7", - "@oasis-engine/loader": "0.7.0-beta.7", - "@oasis-engine/math": "0.7.0-beta.7", - "@oasis-engine/rhi-webgl": "0.7.0-beta.7" + "@oasis-engine/core": "0.8.0-alpha.0", + "@oasis-engine/loader": "0.8.0-alpha.0", + "@oasis-engine/math": "0.8.0-alpha.0", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.0" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index b396b25001..c3ace8ba4f 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.7", - "oasis-engine": "0.7.0-beta.7" + "@oasis-engine/design": "0.8.0-alpha.0", + "oasis-engine": "0.8.0-alpha.0" }, "publishConfig": { "access": "public" diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 8d1d571ecb..95ca3f0896 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,8 +15,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.7.0-beta.7", - "oasis-engine": "0.7.0-beta.7" + "@oasis-engine/design": "0.8.0-alpha.0", + "oasis-engine": "0.8.0-alpha.0" }, "publishConfig": { "access": "public" diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index ff8579a328..f8af4d6761 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.7.0-beta.7", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,10 +14,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.7.0-beta.7", - "@oasis-engine/math": "0.7.0-beta.7" + "@oasis-engine/core": "0.8.0-alpha.0", + "@oasis-engine/math": "0.8.0-alpha.0" }, "devDependencies": { - "@oasis-engine/design": "0.7.0-beta.7" + "@oasis-engine/design": "0.8.0-alpha.0" } } diff --git a/tests/package.json b/tests/package.json index 4f12584065..6e6ae0b0c7 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/tests", - "version": "0.7.0-beta.4", + "version": "0.8.0-alpha.0", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,8 +14,8 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.7.0-beta.4", "@oasis-engine/core": "0.7.0-beta.4", + "@oasis-engine/math": "0.7.0-beta.4", "@oasis-engine/rhi-webgl": "0.7.0-beta.4" }, "devDependencies": { From 6355c207b271d4684eacb83e916cb989ae7b4d91 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Wed, 29 Jun 2022 16:08:40 +0800 Subject: [PATCH 21/33] v0.8.0-alpha.1 --- lerna.json | 2 +- packages/core/package.json | 10 +++++++--- packages/design/package.json | 8 ++++++-- packages/draco/package.json | 8 ++++++-- packages/loader/package.json | 14 +++++++++----- packages/math/package.json | 6 +++++- packages/oasis-engine/package.json | 14 +++++++++----- packages/physics-lite/package.json | 13 +++++++------ packages/physics-physx/package.json | 13 +++++++------ packages/rhi-webgl/package.json | 12 ++++++++---- tests/package.json | 3 ++- 11 files changed, 67 insertions(+), 36 deletions(-) diff --git a/lerna.json b/lerna.json index f785fca7c2..66ade2fb62 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index a798c9e61c..62f17743da 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/core", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.0" + "@oasis-engine/math": "0.8.0-alpha.1" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.0" + "@oasis-engine/design": "0.8.0-alpha.1" } } diff --git a/packages/design/package.json b/packages/design/package.json index f81d72c003..b7bba317af 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/design", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -13,6 +17,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.0" + "@oasis-engine/math": "0.8.0-alpha.1" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 1158844aad..68378da0f0 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/draco", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "scripts": { "b:types": "tsc" @@ -13,6 +17,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.0" + "@oasis-engine/core": "0.8.0-alpha.1" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index aaf776d2df..d1f387ca0e 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/loader", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "types": "types/index.d.ts", "scripts": { @@ -14,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.0", - "@oasis-engine/draco": "0.8.0-alpha.0", - "@oasis-engine/math": "0.8.0-alpha.0", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.0" + "@oasis-engine/core": "0.8.0-alpha.1", + "@oasis-engine/draco": "0.8.0-alpha.1", + "@oasis-engine/math": "0.8.0-alpha.1", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.1" } } diff --git a/packages/math/package.json b/packages/math/package.json index 7ecb9498bf..5280ab2086 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/math", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index 429d4926cf..98f80c2ff4 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,10 @@ { "name": "oasis-engine", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "scripts": { "b:types": "tsc" @@ -14,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.0", - "@oasis-engine/loader": "0.8.0-alpha.0", - "@oasis-engine/math": "0.8.0-alpha.0", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.0" + "@oasis-engine/core": "0.8.0-alpha.1", + "@oasis-engine/loader": "0.8.0-alpha.1", + "@oasis-engine/math": "0.8.0-alpha.1", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.1" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index c3ace8ba4f..caf24f482c 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,10 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.0", - "oasis-engine": "0.8.0-alpha.0" - }, - "publishConfig": { - "access": "public" + "@oasis-engine/design": "0.8.0-alpha.1", + "oasis-engine": "0.8.0-alpha.1" } } diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 95ca3f0896..7dc52bf351 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -15,10 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.0", - "oasis-engine": "0.8.0-alpha.0" - }, - "publishConfig": { - "access": "public" + "@oasis-engine/design": "0.8.0-alpha.1", + "oasis-engine": "0.8.0-alpha.1" } } diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index f8af4d6761..040b174baa 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,10 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.8.0-alpha.0", + "version": "0.8.0-alpha.1", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", @@ -14,10 +18,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.0", - "@oasis-engine/math": "0.8.0-alpha.0" + "@oasis-engine/core": "0.8.0-alpha.1", + "@oasis-engine/math": "0.8.0-alpha.1" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.0" + "@oasis-engine/design": "0.8.0-alpha.1" } } diff --git a/tests/package.json b/tests/package.json index 6e6ae0b0c7..3e30b50724 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,6 +1,7 @@ { "name": "@oasis-engine/tests", - "version": "0.8.0-alpha.0", + "private": true, + "version": "0.8.0-alpha.1", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", From 186ace804fb39eb88dbc4e4d7f903fee0fe0a0ba Mon Sep 17 00:00:00 2001 From: AZhan Date: Fri, 1 Jul 2022 18:36:20 +0800 Subject: [PATCH 22/33] Add SpriteRenderer drawMode property(support simple and sliced) (#828) * feat: add sprite draw mode(support simple and sliced) --- packages/core/src/2d/assembler/IAssembler.ts | 8 + .../src/2d/assembler/SimpleSpriteAssembler.ts | 77 ++++ .../src/2d/assembler/SlicedSpriteAssembler.ts | 151 ++++++++ .../2d/assembler/StaticInterfaceImplement.ts | 10 + packages/core/src/2d/data/RenderData2D.ts | 14 + packages/core/src/2d/enums/SpriteDirtyFlag.ts | 13 + packages/core/src/2d/enums/SpriteDrawMode.ts | 9 + packages/core/src/2d/index.ts | 1 + packages/core/src/2d/sprite/Sprite.ts | 333 ++++++++++-------- packages/core/src/2d/sprite/SpriteMask.ts | 197 ++++++++--- packages/core/src/2d/sprite/SpriteRenderer.ts | 303 +++++++++------- .../core/src/RenderPipeline/Basic2DBatcher.ts | 24 +- .../core/src/RenderPipeline/RenderQueue.ts | 8 +- .../core/src/RenderPipeline/SpriteBatcher.ts | 22 +- .../core/src/RenderPipeline/SpriteElement.ts | 25 +- .../src/RenderPipeline/SpriteMaskBatcher.ts | 21 +- .../src/RenderPipeline/SpriteMaskElement.ts | 12 +- .../src/RenderPipeline/SpriteMaskManager.ts | 6 +- packages/core/src/Renderer.ts | 10 +- packages/loader/src/SpriteAtlasLoader.ts | 37 +- packages/math/src/CollisionUtil.ts | 2 +- 21 files changed, 863 insertions(+), 420 deletions(-) create mode 100644 packages/core/src/2d/assembler/IAssembler.ts create mode 100644 packages/core/src/2d/assembler/SimpleSpriteAssembler.ts create mode 100644 packages/core/src/2d/assembler/SlicedSpriteAssembler.ts create mode 100644 packages/core/src/2d/assembler/StaticInterfaceImplement.ts create mode 100644 packages/core/src/2d/data/RenderData2D.ts create mode 100644 packages/core/src/2d/enums/SpriteDirtyFlag.ts create mode 100644 packages/core/src/2d/enums/SpriteDrawMode.ts diff --git a/packages/core/src/2d/assembler/IAssembler.ts b/packages/core/src/2d/assembler/IAssembler.ts new file mode 100644 index 0000000000..84a71f0412 --- /dev/null +++ b/packages/core/src/2d/assembler/IAssembler.ts @@ -0,0 +1,8 @@ +import { Renderer } from "../../Renderer"; + +export interface IAssembler { + resetData(renderer: Renderer): void; + updateData(renderer: Renderer): void; + updatePositions(renderer: Renderer): void; + updateUVs(renderer: Renderer): void; +} diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts new file mode 100644 index 0000000000..aa7cf342e6 --- /dev/null +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -0,0 +1,77 @@ +import { BoundingBox, Matrix, Vector2, Vector3 } from "@oasis-engine/math"; +import { SpriteMask } from "../sprite"; +import { SpriteRenderer } from "../sprite/SpriteRenderer"; +import { IAssembler } from "./IAssembler"; +import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; + +@StaticInterfaceImplement() +/** + * @internal + */ +export class SimpleSpriteAssembler { + static _rectangleTriangles: number[] = [0, 1, 2, 2, 1, 3]; + static _worldMatrix: Matrix = new Matrix(); + + static resetData(renderer: SpriteRenderer | SpriteMask): void { + const { _renderData: renderData } = renderer; + const vertexCount = (renderData.vertexCount = 4); + const { positions, uvs } = renderData; + if (positions.length < vertexCount) { + for (let i = positions.length; i < vertexCount; i++) { + positions.push(new Vector3()); + uvs.push(new Vector2()); + } + } + renderData.triangles = SimpleSpriteAssembler._rectangleTriangles; + } + + static updateData(renderer: SpriteRenderer | SpriteMask): void {} + + static updatePositions(renderer: SpriteRenderer | SpriteMask): void { + const { width, height } = renderer; + if (width === 0 || height === 0) { + return; + } + const { sprite } = renderer; + const { x: pivotX, y: pivotY } = sprite.pivot; + // Renderer's worldMatrix; + const { _worldMatrix: worldMatrix } = SimpleSpriteAssembler; + const { elements: wE } = worldMatrix; + // Parent's worldMatrix. + const { elements: pWE } = renderer.entity.transform.worldMatrix; + const sx = renderer.flipX ? -width : width; + const sy = renderer.flipY ? -height : height; + (wE[0] = pWE[0] * sx), (wE[1] = pWE[1] * sx), (wE[2] = pWE[2] * sx); + (wE[4] = pWE[4] * sy), (wE[5] = pWE[5] * sy), (wE[6] = pWE[6] * sy); + (wE[8] = pWE[8]), (wE[9] = pWE[9]), (wE[10] = pWE[10]); + wE[12] = pWE[12] - pivotX * wE[0] - pivotY * wE[4]; + wE[13] = pWE[13] - pivotX * wE[1] - pivotY * wE[5]; + wE[14] = pWE[14]; + + // --------------- + // 2 - 3 + // | | + // 0 - 1 + // --------------- + // Update positions. + const spritePositions = sprite._getPositions(); + const { positions } = renderer._renderData; + for (let i = 0; i < 4; i++) { + const { x, y } = spritePositions[i]; + positions[i].set(wE[0] * x + wE[4] * y + wE[12], wE[1] * x + wE[5] * y + wE[13], wE[2] * x + wE[6] * y + wE[14]); + } + + BoundingBox.transform(sprite._getBounds(), worldMatrix, renderer._bounds); + } + + static updateUVs(renderer: SpriteRenderer | SpriteMask): void { + const spriteUVs = renderer.sprite._getUVs(); + const renderUVs = renderer._renderData.uvs; + const { x: left, y: bottom } = spriteUVs[0]; + const { x: right, y: top } = spriteUVs[3]; + renderUVs[0].set(left, bottom); + renderUVs[1].set(right, bottom); + renderUVs[2].set(left, top); + renderUVs[3].set(right, top); + } +} diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts new file mode 100644 index 0000000000..7d6b95d0ad --- /dev/null +++ b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts @@ -0,0 +1,151 @@ +import { Matrix, Vector2, Vector3 } from "@oasis-engine/math"; +import { SpriteMask } from "../sprite"; +import { SpriteRenderer } from "../sprite/SpriteRenderer"; +import { IAssembler } from "./IAssembler"; +import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; + +@StaticInterfaceImplement() +/** + * @internal + */ +export class SlicedSpriteAssembler { + static _worldMatrix: Matrix = new Matrix(); + static resetData(renderer: SpriteRenderer | SpriteMask): void { + const { _renderData: renderData } = renderer; + const { positions, uvs } = renderData; + if (positions.length < 16) { + for (let i = positions.length; i < 16; i++) { + positions.push(new Vector3()); + uvs.push(new Vector2()); + } + } + renderData.triangles = []; + } + + static updateData(renderer: SpriteRenderer | SpriteMask): void {} + + static updatePositions(renderer: SpriteRenderer | SpriteMask): void { + const { width, height } = renderer; + if (width === 0 || height === 0) { + return; + } + const { sprite } = renderer; + const { positions, uvs, triangles } = renderer._renderData; + const { border } = sprite; + const spriteUVs = sprite._getUVs(); + // Update local positions. + const spritePositions = sprite._getPositions(); + const { x: left, y: bottom } = spritePositions[0]; + const { x: right, y: top } = spritePositions[3]; + const { width: expectWidth, height: expectHeight } = sprite; + const fixedLeft = expectWidth * border.x; + const fixedBottom = expectHeight * border.y; + const fixedRight = expectHeight * border.z; + const fixedTop = expectWidth * border.w; + + // ------------------------ + // [3] + // | + // [2] + // | + // [1] + // | + // row [0] - [1] - [2] - [3] + // column + // ------------------------ + // Calculate row and column. + let row: number[], column: number[]; + if (fixedLeft + fixedRight > width) { + const widthScale = width / (fixedLeft + fixedRight); + row = [ + expectWidth * left * widthScale, + fixedLeft * widthScale, + fixedLeft * widthScale, + width - expectWidth * (1 - right) * widthScale + ]; + } else { + row = [expectWidth * left, fixedLeft, width - fixedRight, width - expectWidth * (1 - right)]; + } + + if (fixedTop + fixedBottom > height) { + const heightScale = height / (fixedTop + fixedBottom); + column = [ + expectHeight * bottom * heightScale, + fixedBottom * heightScale, + fixedBottom * heightScale, + height - expectHeight * (1 - top) * heightScale + ]; + } else { + column = [expectHeight * bottom, fixedBottom, height - fixedTop, height - expectHeight * (1 - top)]; + } + + // Update renderer's worldMatrix. + const { x: pivotX, y: pivotY } = renderer.sprite.pivot; + const localTransX = renderer.width * pivotX; + const localTransY = renderer.height * pivotY; + // Renderer's worldMatrix. + const { _worldMatrix: worldMatrix } = SlicedSpriteAssembler; + const { elements: wE } = worldMatrix; + // Parent's worldMatrix. + const { elements: pWE } = renderer.entity.transform.worldMatrix; + const sx = renderer.flipX ? -1 : 1; + const sy = renderer.flipY ? -1 : 1; + (wE[0] = pWE[0] * sx), (wE[1] = pWE[1] * sx), (wE[2] = pWE[2] * sx); + (wE[4] = pWE[4] * sy), (wE[5] = pWE[5] * sy), (wE[6] = pWE[6] * sy); + (wE[8] = pWE[8]), (wE[9] = pWE[9]), (wE[10] = pWE[10]); + wE[12] = pWE[12] - localTransX * wE[0] - localTransY * wE[4]; + wE[13] = pWE[13] - localTransX * wE[1] - localTransY * wE[5]; + wE[14] = pWE[14]; + + // ------------------------ + // 3 - 7 - 11 - 15 + // | | | | + // 2 - 6 - 10 - 14 + // | | | | + // 1 - 5 - 9 - 13 + // | | | | + // 0 - 4 - 8 - 12 + // ------------------------ + // Assemble position and uv. + let vertexCount = 0; + let realICount = 0; + for (let i = 0; i < 4; i++) { + const rowValue = row[i]; + const rowU = spriteUVs[i].x; + for (let j = 0; j < 4; j++) { + const columnValue = column[j]; + positions[vertexCount].set( + wE[0] * rowValue + wE[4] * columnValue + wE[12], + wE[1] * rowValue + wE[5] * columnValue + wE[13], + wE[2] * rowValue + wE[6] * columnValue + wE[14] + ); + uvs[vertexCount].set(rowU, spriteUVs[j].y); + ++vertexCount; + } + ++realICount; + } + + const realJCount = vertexCount / realICount; + let indexOffset = 0; + for (let i = 0; i < realICount - 1; ++i) { + for (let j = 0; j < realJCount - 1; ++j) { + const start = i * realJCount + j; + triangles[indexOffset++] = start; + triangles[indexOffset++] = start + 1; + triangles[indexOffset++] = start + realJCount; + triangles[indexOffset++] = start + 1; + triangles[indexOffset++] = start + realJCount + 1; + triangles[indexOffset++] = start + realJCount; + } + } + renderer._renderData.vertexCount = realICount * realJCount; + triangles.length = (realICount - 1) * (realJCount - 1) * 6; + + const { min, max } = renderer._bounds; + min.set(row[0], column[0], 0); + max.set(row[3], column[3], 0); + renderer._bounds.transform(worldMatrix); + } + + static updateUVs(renderer: SpriteRenderer | SpriteMask): void {} +} diff --git a/packages/core/src/2d/assembler/StaticInterfaceImplement.ts b/packages/core/src/2d/assembler/StaticInterfaceImplement.ts new file mode 100644 index 0000000000..855b817e42 --- /dev/null +++ b/packages/core/src/2d/assembler/StaticInterfaceImplement.ts @@ -0,0 +1,10 @@ +/** + * Static interface implement decorator. + * https://stackoverflow.com/questions/13955157/how-to-define-static-property-in-typescript-interface + */ + export function StaticInterfaceImplement() { + return (constructor: U) => { + constructor; + }; + } + \ No newline at end of file diff --git a/packages/core/src/2d/data/RenderData2D.ts b/packages/core/src/2d/data/RenderData2D.ts new file mode 100644 index 0000000000..13e3aeb684 --- /dev/null +++ b/packages/core/src/2d/data/RenderData2D.ts @@ -0,0 +1,14 @@ +import { Color, Vector2, Vector3 } from "@oasis-engine/math"; + +/** + * @internal + */ +export class RenderData2D { + constructor( + public vertexCount: number, + public positions: Vector3[], + public uvs: Vector2[], + public triangles: number[] = null, + public color: Color = null + ) {} +} diff --git a/packages/core/src/2d/enums/SpriteDirtyFlag.ts b/packages/core/src/2d/enums/SpriteDirtyFlag.ts new file mode 100644 index 0000000000..3070862dcf --- /dev/null +++ b/packages/core/src/2d/enums/SpriteDirtyFlag.ts @@ -0,0 +1,13 @@ +/** + * Sprite Property Dirty Flag. + */ +export enum SpritePropertyDirtyFlag { + texture = 0x1, + size = 0x2, + atlasRotate = 0x4, + atlasRegion = 0x8, + atlasRegionOffset = 0x10, + region = 0x20, + pivot = 0x40, + border = 0x80 +} diff --git a/packages/core/src/2d/enums/SpriteDrawMode.ts b/packages/core/src/2d/enums/SpriteDrawMode.ts new file mode 100644 index 0000000000..40b7979e95 --- /dev/null +++ b/packages/core/src/2d/enums/SpriteDrawMode.ts @@ -0,0 +1,9 @@ +/** + * Sprite's drawing mode enumeration. + */ +export enum SpriteDrawMode { + /** Overall scaling when modifying size. */ + Simple, + /** When modifying the size, it is transformed according to the 9-slice settings (border). */ + Sliced +} diff --git a/packages/core/src/2d/index.ts b/packages/core/src/2d/index.ts index f58f66ada7..c7bb91fa4e 100644 --- a/packages/core/src/2d/index.ts +++ b/packages/core/src/2d/index.ts @@ -4,5 +4,6 @@ export { TextHorizontalAlignment, TextVerticalAlignment } from "./enums/TextAlig export { OverflowMode } from "./enums/TextOverflow"; export { FontStyle } from "./enums/FontStyle"; export { SpriteAtlas } from "./atlas/SpriteAtlas"; +export { SpriteDrawMode } from "./enums/SpriteDrawMode"; export * from "./sprite/index"; export * from "./text/index"; diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index d9075392e3..c68e21817e 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -1,37 +1,40 @@ import { BoundingBox, MathUtil, Rect, Vector2, Vector4 } from "@oasis-engine/math"; import { RefObject } from "../../asset/RefObject"; -import { BoolUpdateFlag } from "../../BoolUpdateFlag"; import { Engine } from "../../Engine"; +import { ListenerUpdateFlag } from "../../ListenerUpdateFlag"; import { Texture2D } from "../../texture/Texture2D"; import { UpdateFlagManager } from "../../UpdateFlagManager"; +import { SpritePropertyDirtyFlag } from "../enums/SpriteDirtyFlag"; /** * 2D sprite. */ export class Sprite extends RefObject { - private static _rectangleTriangles: number[] = [0, 2, 1, 2, 0, 3]; + /** @internal Conversion of space units to pixel units. */ + static _pixelPerUnit: number = 100; /** The name of sprite. */ name: string; - /** @internal */ - _uv: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; - /** @internal */ - _positions: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; - /** @internal */ - _bounds: BoundingBox = new BoundingBox(); - /** @internal */ - _triangles: number[]; /** @internal temp solution. */ _assetID: number; - private _pixelsPerUnit: number; + private _width: number = undefined; + private _height: number = undefined; + + private _positions: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; + private _uvs: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; + private _bounds: BoundingBox = new BoundingBox(); + private _texture: Texture2D = null; private _atlasRotated: boolean = false; - private _region: Rect = new Rect(0, 0, 1, 1); - private _pivot: Vector2 = new Vector2(0.5, 0.5); private _atlasRegion: Rect = new Rect(0, 0, 1, 1); private _atlasRegionOffset: Vector4 = new Vector4(0, 0, 0, 0); + + private _region: Rect = new Rect(0, 0, 1, 1); + private _pivot: Vector2 = new Vector2(0.5, 0.5); + private _border: Vector4 = new Vector4(0, 0, 0, 0); + private _dirtyFlag: DirtyFlag = DirtyFlag.all; private _updateFlagManager: UpdateFlagManager = new UpdateFlagManager(); @@ -45,20 +48,38 @@ export class Sprite extends RefObject { set texture(value: Texture2D) { if (this._texture !== value) { this._texture = value; - this._setDirtyFlagTrue(DirtyFlag.positions); + this._dispatchSpriteChange(SpritePropertyDirtyFlag.texture); } } /** - * Bounding volume of the sprite. - * @remarks The returned bounds should be considered deep-read-only. + * The width of the sprite (in world coordinates). */ - get bounds(): Readonly { - if (this._isContainDirtyFlag(DirtyFlag.positions) && this._texture) { - this._updatePositionsAndBounds(); - this._setDirtyFlagFalse(DirtyFlag.positions); + get width(): number { + this._width === undefined && this._calDefaultSize(); + return this._width; + } + + set width(value: number) { + if (this._width !== value) { + this._width = value; + this._dispatchSpriteChange(SpritePropertyDirtyFlag.size); + } + } + + /** + * The height of the sprite (in world coordinates). + */ + get height(): number { + this._height === undefined && this._calDefaultSize(); + return this._height; + } + + set height(value: number) { + if (this._height !== value) { + this._height = value; + this._dispatchSpriteChange(SpritePropertyDirtyFlag.size); } - return this._bounds; } /** @@ -71,7 +92,6 @@ export class Sprite extends RefObject { set atlasRotated(value: boolean) { if (this._atlasRotated != value) { this._atlasRotated = value; - this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); } } @@ -86,7 +106,7 @@ export class Sprite extends RefObject { const x = MathUtil.clamp(value.x, 0, 1); const y = MathUtil.clamp(value.y, 0, 1); this._atlasRegion.set(x, y, MathUtil.clamp(value.width, 0, 1 - x), MathUtil.clamp(value.height, 0, 1 - y)); - this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); + this._dispatchSpriteChange(SpritePropertyDirtyFlag.atlasRegion); } /** @@ -100,23 +120,7 @@ export class Sprite extends RefObject { const x = MathUtil.clamp(value.x, 0, 1); const y = MathUtil.clamp(value.y, 0, 1); this._atlasRegionOffset.set(x, y, MathUtil.clamp(value.z, 0, 1 - x), MathUtil.clamp(value.w, 0, 1 - y)); - this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); - } - - /** - * Location of the sprite's center point in the rectangle region, specified in normalized. - */ - get pivot(): Vector2 { - return this._pivot; - } - - set pivot(value: Vector2) { - const pivot = this._pivot; - const { x, y } = value; - if (pivot === value || pivot.x !== x || pivot.y !== y) { - pivot.set(x, y); - this._setDirtyFlagTrue(DirtyFlag.positions); - } + this._dispatchSpriteChange(SpritePropertyDirtyFlag.atlasRegionOffset); } /** @@ -131,30 +135,56 @@ export class Sprite extends RefObject { const x = MathUtil.clamp(value.x, 0, 1); const y = MathUtil.clamp(value.y, 0, 1); region.set(x, y, MathUtil.clamp(value.width, 0, 1 - x), MathUtil.clamp(value.height, 0, 1 - y)); - this._setDirtyFlagTrue(DirtyFlag.positions | DirtyFlag.uv); + this._dispatchSpriteChange(SpritePropertyDirtyFlag.region); } /** - * The number of pixels in the sprite that correspond to one unit in world space. + * Location of the sprite's center point in the rectangle region, specified in normalized. + * The origin is at the bottom left and the default value is (0.5, 0.5). */ - get pixelsPerUnit(): number { - return this._pixelsPerUnit; + get pivot(): Vector2 { + return this._pivot; } - set pixelsPerUnit(value: number) { - if (this._pixelsPerUnit !== value) { - this._pixelsPerUnit = value; - this._setDirtyFlagTrue(DirtyFlag.positions); + set pivot(value: Vector2) { + const pivot = this._pivot; + if (pivot === value) { + this._dispatchSpriteChange(SpritePropertyDirtyFlag.pivot); + } else { + const { x, y } = value; + if (pivot.x !== x || pivot.y !== y) { + pivot.set(x, y); + this._dispatchSpriteChange(SpritePropertyDirtyFlag.pivot); + } } } + /** + * Get the border of the sprite. + * x y z w + * | | | | + * Left, bottom, right, top. + * @remark only use in sliced mode. + */ + get border(): Vector4 { + return this._border; + } + + set border(value: Vector4) { + const border = this._border; + const x = MathUtil.clamp(value.x, 0, 1); + const y = MathUtil.clamp(value.y, 0, 1); + border.set(x, y, MathUtil.clamp(value.z, 0, 1 - x), MathUtil.clamp(value.w, 0, 1 - y)); + this._dispatchSpriteChange(SpritePropertyDirtyFlag.border); + } + /** * Constructor a Sprite. * @param engine - Engine to which the sprite belongs * @param texture - Texture from which to obtain the Sprite * @param region - Rectangle region of the texture to use for the Sprite, specified in normalized * @param pivot - Sprite's pivot point relative to its graphic rectangle, specified in normalized - * @param pixelsPerUnit - The number of pixels in the Sprite that correspond to one unit in world space + * @param border - Boundaries when using Slice DrawMode, specified in normalized * @param name - The name of Sprite */ constructor( @@ -162,19 +192,15 @@ export class Sprite extends RefObject { texture: Texture2D = null, region: Rect = null, pivot: Vector2 = null, - pixelsPerUnit: number = 128, + border: Vector4 = null, name: string = null ) { super(engine); - - this.name = name; this._texture = texture; - this._pixelsPerUnit = pixelsPerUnit; - - region && this._region.copyFrom(region); - pivot && this._pivot.copyFrom(pivot); - - this._triangles = Sprite._rectangleTriangles; + region && region.copyFrom(this._region); + pivot && pivot.copyFrom(this._pivot); + border && border.copyFrom(this._border); + this.name = name; } /** @@ -182,14 +208,7 @@ export class Sprite extends RefObject { * @returns Cloned sprite */ clone(): Sprite { - const cloneSprite = new Sprite( - this._engine, - this._texture, - this._region, - this._pivot, - this._pixelsPerUnit, - this.name - ); + const cloneSprite = new Sprite(this._engine, this._texture, this._region, this._pivot, this._border, this.name); cloneSprite._assetID = this._assetID; cloneSprite._atlasRotated = this._atlasRotated; cloneSprite._atlasRegion.copyFrom(this._atlasRegion); @@ -200,111 +219,135 @@ export class Sprite extends RefObject { /** * @internal */ - _registerUpdateFlag(): BoolUpdateFlag { - return this._updateFlagManager.createFlag(BoolUpdateFlag); + _registerUpdateFlag(): ListenerUpdateFlag { + return this._updateFlagManager.createFlag(ListenerUpdateFlag); } /** - * @override + * @internal */ - _onDestroy(): void { - if (this._texture) { - this._texture = null; - } + _getPositions(): Vector2[] { + this._dirtyFlag & DirtyFlag.positions && this._updatePositions(); + return this._positions; } /** - * Update positions and bounds. + * @internal */ - private _updatePositionsAndBounds(): void { - const { _texture: texture, _bounds: bounds } = this; - if (texture) { - const { _atlasRegion: atlasRegion, _pivot: pivot } = this; - const { x: blankLeft, y: blankTop, z: blankRight, w: blankBottom } = this._atlasRegionOffset; - const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; - const regionRight = 1 - regionX - regionW; - const regionBottom = 1 - regionY - regionH; - // Real rendering size. - const realRenderW = - (texture.width * atlasRegion.width * regionW) / ((1 - blankLeft - blankRight) * this._pixelsPerUnit); - const realRenderH = - (texture.height * atlasRegion.height * regionH) / ((1 - blankTop - blankBottom) * this._pixelsPerUnit); - // Coordinates of the four boundaries. - const left = (Math.max(blankLeft - regionX, 0) / regionW - pivot.x) * realRenderW; - const right = (1 - Math.max(blankRight - regionRight, 0) / regionW - pivot.x) * realRenderW; - const top = (1 - Math.max(blankTop - regionBottom, 0) / regionH - pivot.y) * realRenderH; - const bottom = (Math.max(blankBottom - regionY, 0) / regionH - pivot.y) * realRenderH; - // Assign values ​​to _positions - const positions = this._positions; - // Top-left. - positions[0].set(left, top); - // Top-right. - positions[1].set(right, top); - // Bottom-right. - positions[2].set(right, bottom); - // Bottom-left. - positions[3].set(left, bottom); - - // Update bounds. - bounds.min.set(left, bottom, 0); - bounds.max.set(right, top, 0); - } else { - // Update bounds. - bounds.min.set(0, 0, 0); - bounds.max.set(0, 0, 0); - } + _getUVs(): Vector2[] { + this._dirtyFlag & DirtyFlag.uvs && this._updateUVs(); + return this._uvs; } /** * @internal */ - _updateMesh(): void { - if (this._isContainDirtyFlag(DirtyFlag.positions)) { - this._updatePositionsAndBounds(); + _getBounds(): BoundingBox { + this._dirtyFlag & DirtyFlag.positions && this._updatePositions(); + return this._bounds; + } + + /** + * @override + */ + _onDestroy(): void { + if (this._texture) { + this._texture = null; } + } - if (this._isContainDirtyFlag(DirtyFlag.uv)) { - const { _uv: uv, _atlasRegionOffset: atlasRegionOffset } = this; - const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; - const regionRight = 1 - regionX - regionW; - const regionBottom = 1 - regionY - regionH; - const { x: atlasRegionX, y: atlasRegionY, width: atlasRegionW, height: atlasRegionH } = this._atlasRegion; - const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; - const realWidth = atlasRegionW / (1 - offsetLeft - offsetRight); - const realHeight = atlasRegionH / (1 - offsetTop - offsetBottom); - // Coordinates of the four boundaries. - const left = Math.max(regionX - offsetLeft, 0) * realWidth + atlasRegionX; - const top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; - const right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; - const bottom = atlasRegionH + atlasRegionY - Math.max(regionY - offsetBottom, 0) * realHeight; - // Top-left. - uv[0].set(left, top); - // Top-right. - uv[1].set(right, top); - // Bottom-right. - uv[2].set(right, bottom); - // Bottom-left. - uv[3].set(left, bottom); + private _calDefaultSize(): void { + if (this._texture) { + const { _texture, _atlasRegion, _atlasRegionOffset, _region } = this; + this.width = + (((_texture.width * _atlasRegion.width) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * _region.width) / + Sprite._pixelPerUnit; + this.height = + (((_texture.height * _atlasRegion.height) / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * + _region.height) / + Sprite._pixelPerUnit; } - this._setDirtyFlagFalse(DirtyFlag.all); } - private _isContainDirtyFlag(type: number): boolean { - return (this._dirtyFlag & type) != 0; + private _updatePositions(): void { + const blank = this._atlasRegionOffset; + const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; + const regionRight = 1 - regionX - regionW; + const regionBottom = 1 - regionY - regionH; + const left = Math.max(blank.x - regionX, 0) / regionW; + const bottom = Math.max(blank.w - regionY, 0) / regionH; + const right = 1 - Math.max(blank.z - regionRight, 0) / regionW; + const top = 1 - Math.max(blank.y - regionBottom, 0) / regionH; + + // Update positions. + // --------------- + // 2 - 3 + // | | + // 0 - 1 + // --------------- + const positions = this._positions; + positions[0].set(left, bottom); + positions[1].set(right, bottom); + positions[2].set(left, top); + positions[3].set(right, top); + + const { min, max } = this._bounds; + min.set(left, bottom, 0); + max.set(right, top, 0); + this._dirtyFlag &= ~DirtyFlag.positions; } - private _setDirtyFlagTrue(type: number): void { - this._dirtyFlag |= type; - this._updateFlagManager.dispatch(); + private _updateUVs(): void { + const { _uvs: uv, _atlasRegionOffset: atlasRegionOffset } = this; + const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; + const regionRight = 1 - regionX - regionW; + const regionBottom = 1 - regionY - regionH; + const { x: atlasRegionX, y: atlasRegionY, width: atlasRegionW, height: atlasRegionH } = this._atlasRegion; + const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; + const realWidth = atlasRegionW / (1 - offsetLeft - offsetRight); + const realHeight = atlasRegionH / (1 - offsetTop - offsetBottom); + // Coordinates of the four boundaries. + const left = Math.max(regionX - offsetLeft, 0) * realWidth + atlasRegionX; + const top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; + const right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; + const bottom = atlasRegionH + atlasRegionY - Math.max(regionY - offsetBottom, 0) * realHeight; + const { x: borderLeft, y: borderBottom, z: borderRight, w: borderTop } = this._border; + // Left-Bottom + uv[0].set(left, bottom); + // Border ( Left-Bottom ) + uv[1].set( + (regionX - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX, + atlasRegionH + atlasRegionY - (regionY - offsetBottom + borderBottom * regionH) * realHeight + ); + // Border ( Right-Top ) + uv[2].set( + atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth, + (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY + ); + // Right-Top + uv[3].set(right, top); + this._dirtyFlag &= ~DirtyFlag.uvs; } - private _setDirtyFlagFalse(type: number): void { - this._dirtyFlag &= ~type; + private _dispatchSpriteChange(type: SpritePropertyDirtyFlag): void { + switch (type) { + case SpritePropertyDirtyFlag.atlasRegionOffset: + case SpritePropertyDirtyFlag.region: + this._dirtyFlag |= DirtyFlag.all; + break; + case SpritePropertyDirtyFlag.atlasRegion: + case SpritePropertyDirtyFlag.border: + this._dirtyFlag |= DirtyFlag.uvs; + break; + default: + break; + } + this._updateFlagManager.dispatch(type); } } enum DirtyFlag { positions = 0x1, - uv = 0x2, + uvs = 0x2, all = 0x3 } diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 4ca887862b..49833f2827 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -1,13 +1,16 @@ -import { Vector3 } from "@oasis-engine/math"; -import { BoolUpdateFlag } from "../../BoolUpdateFlag"; +import { BoundingBox } from "@oasis-engine/math"; import { Camera } from "../../Camera"; -import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager"; +import { assignmentClone, ignoreClone } from "../../clone/CloneManager"; import { ICustomClone } from "../../clone/ComponentCloner"; import { Entity } from "../../Entity"; +import { ListenerUpdateFlag } from "../../ListenerUpdateFlag"; import { Renderer } from "../../Renderer"; import { SpriteMaskElement } from "../../RenderPipeline/SpriteMaskElement"; import { Shader } from "../../shader/Shader"; import { ShaderProperty } from "../../shader/ShaderProperty"; +import { SimpleSpriteAssembler } from "../assembler/SimpleSpriteAssembler"; +import { RenderData2D } from "../data/RenderData2D"; +import { SpritePropertyDirtyFlag } from "../enums/SpriteDirtyFlag"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { Sprite } from "./Sprite"; @@ -20,40 +23,114 @@ export class SpriteMask extends Renderer implements ICustomClone { /** @internal */ static _alphaCutoffProperty: ShaderProperty = Shader.getPropertyByName("u_maskAlphaCutoff"); - private static _tempVec3: Vector3 = new Vector3(); - + /** The mask layers the sprite mask influence to. */ + @assignmentClone + influenceLayers: number = SpriteMaskLayer.Everything; /** @internal */ _maskElement: SpriteMaskElement; - @deepClone - private _positions: Vector3[] = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; - @ignoreClone - private _worldMatrixDirtyFlag: BoolUpdateFlag; + /** @internal */ + _renderData: RenderData2D; + @ignoreClone private _sprite: Sprite = null; + + @ignoreClone + private _width: number = undefined; + @ignoreClone + private _height: number = undefined; + @assignmentClone + private _flipX: boolean = false; + @assignmentClone + private _flipY: boolean = false; + @assignmentClone private _alphaCutoff: number = 0.5; + @ignoreClone - private _spriteDirty: BoolUpdateFlag; + private _dirtyFlag: number = 0; + @ignoreClone + private _spriteChangeFlag: ListenerUpdateFlag = null; - /** The mask layers the sprite mask influence to. */ - @assignmentClone - influenceLayers: number = SpriteMaskLayer.Everything; + /** + * Render width. + */ + get width(): number { + if (this._width === undefined && this._sprite) { + this.width = this._sprite.width; + } + return this._width; + } + + set width(value: number) { + if (this._width !== value) { + this._width = value; + this._dirtyFlag |= DirtyFlag.Position; + } + } /** - * The Sprite used to define the mask. + * Render height. + */ + get height(): number { + if (this._height === undefined && this._sprite) { + this.height = this._sprite.height; + } + return this._height; + } + + set height(value: number) { + if (this._height !== value) { + this._height = value; + this._dirtyFlag |= DirtyFlag.Position; + } + } + + /** + * Flips the sprite on the X axis. + */ + get flipX(): boolean { + return this._flipX; + } + + set flipX(value: boolean) { + if (this._flipX !== value) { + this._flipX = value; + this._dirtyFlag |= DirtyFlag.Position; + } + } + + /** + * Flips the sprite on the Y axis. + */ + get flipY(): boolean { + return this._flipY; + } + + set flipY(value: boolean) { + if (this._flipY !== value) { + this._flipY = value; + this._dirtyFlag |= DirtyFlag.Position; + } + } + + /** + * The Sprite to render. */ get sprite(): Sprite { return this._sprite; } - set sprite(value: Sprite) { + set sprite(value: Sprite | null) { if (this._sprite !== value) { - this._spriteDirty && this._spriteDirty.destroy(); this._sprite = value; + this._spriteChangeFlag && this._spriteChangeFlag.destroy(); if (value) { - this._spriteDirty = value._registerUpdateFlag(); + this._spriteChangeFlag = value._registerUpdateFlag(); + this._spriteChangeFlag.listener = this._onSpriteChange; + this._dirtyFlag |= DirtyFlag.All; } + this.shaderData.setTexture(SpriteMask._textureProperty, value.texture); } } @@ -76,9 +153,11 @@ export class SpriteMask extends Renderer implements ICustomClone { */ constructor(entity: Entity) { super(entity); - this._worldMatrixDirtyFlag = entity.transform.registerWorldChangeFlag(); + this._renderData = new RenderData2D(4, [], []); + SimpleSpriteAssembler.resetData(this); this.setMaterial(this._engine._spriteMaskDefaultMaterial); this.shaderData.setFloat(SpriteMask._alphaCutoffProperty, this._alphaCutoff); + this._onSpriteChange = this._onSpriteChange.bind(this); } /** @@ -86,8 +165,9 @@ export class SpriteMask extends Renderer implements ICustomClone { * @inheritdoc */ _onDestroy(): void { - this._worldMatrixDirtyFlag.destroy(); - this._spriteDirty && this._spriteDirty.destroy(); + this._sprite = null; + this._renderData = null; + this._spriteChangeFlag && this._spriteChangeFlag.destroy(); super._onDestroy(); } @@ -96,50 +176,69 @@ export class SpriteMask extends Renderer implements ICustomClone { * @inheritdoc */ _render(camera: Camera): void { - const sprite = this.sprite; - if (!sprite) { - return null; + const { sprite } = this; + if (!sprite || !sprite.texture) { + return; } - const texture = sprite.texture; - if (!texture) { - return null; + // Update position. + if (this._transformChangeFlag.flag || this._dirtyFlag & DirtyFlag.Position) { + SimpleSpriteAssembler.updatePositions(this); + this._dirtyFlag &= ~DirtyFlag.Position; + this._transformChangeFlag.flag = false; } - const positions = this._positions; - const transform = this.entity.transform; - - // Update sprite data. - sprite._updateMesh(); - - if (this._worldMatrixDirtyFlag.flag || this._spriteDirty.flag) { - const localPositions = sprite._positions; - const localVertexPos = SpriteMask._tempVec3; - const worldMatrix = transform.worldMatrix; - - for (let i = 0, n = positions.length; i < n; i++) { - const curVertexPos = localPositions[i]; - localVertexPos.set(curVertexPos.x, curVertexPos.y, 0); - Vector3.transformToVec3(localVertexPos, worldMatrix, positions[i]); - } - - this._spriteDirty.flag = false; - this._worldMatrixDirtyFlag.flag = false; + // Update uv. + if (this._dirtyFlag & DirtyFlag.UV) { + SimpleSpriteAssembler.updateUVs(this); + this._dirtyFlag &= ~DirtyFlag.UV; } - this.shaderData.setTexture(SpriteMask._textureProperty, texture); const spriteMaskElementPool = this._engine._spriteMaskElementPool; const maskElement = spriteMaskElementPool.getFromPool(); - maskElement.setValue(this, positions, sprite._uv, sprite._triangles, this.getMaterial()); - maskElement.camera = camera; - + maskElement.setValue(this, this._renderData, this.getMaterial()); camera._renderPipeline._allSpriteMasks.add(this); this._maskElement = maskElement; } + /** + * The bounding volume of the spriteRenderer. + */ + get bounds(): BoundingBox { + if (this._transformChangeFlag.flag || this._dirtyFlag & DirtyFlag.Position) { + SimpleSpriteAssembler.updatePositions(this); + this._dirtyFlag &= ~DirtyFlag.Position; + this._transformChangeFlag.flag = false; + } + return this._bounds; + } + /** * @internal */ _cloneTo(target: SpriteMask): void { target.sprite = this._sprite; } + + private _onSpriteChange(dirtyFlag: SpritePropertyDirtyFlag): void { + switch (dirtyFlag) { + case SpritePropertyDirtyFlag.texture: + this.shaderData.setTexture(SpriteMask._textureProperty, this.sprite.texture); + break; + case SpritePropertyDirtyFlag.region: + case SpritePropertyDirtyFlag.atlasRegionOffset: + this._dirtyFlag |= DirtyFlag.All; + break; + case SpritePropertyDirtyFlag.atlasRegion: + this._dirtyFlag |= DirtyFlag.UV; + break; + default: + break; + } + } +} + +enum DirtyFlag { + Position = 0x1, + UV = 0x2, + All = 0x3 } diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index d3d4aff53a..9f7901f3b4 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -1,5 +1,4 @@ -import { BoundingBox, Color, Vector3 } from "@oasis-engine/math"; -import { BoolUpdateFlag } from "../../BoolUpdateFlag"; +import { BoundingBox, Color } from "@oasis-engine/math"; import { Camera } from "../../Camera"; import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager"; import { ICustomClone } from "../../clone/ComponentCloner"; @@ -8,9 +7,16 @@ import { Renderer } from "../../Renderer"; import { CompareFunction } from "../../shader/enums/CompareFunction"; import { Shader } from "../../shader/Shader"; import { ShaderProperty } from "../../shader/ShaderProperty"; +import { RenderData2D } from "../data/RenderData2D"; import { SpriteMaskInteraction } from "../enums/SpriteMaskInteraction"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { Sprite } from "./Sprite"; +import { IAssembler } from "../assembler/IAssembler"; +import { SpritePropertyDirtyFlag } from "../enums/SpriteDirtyFlag"; +import { SpriteDrawMode } from "../enums/SpriteDrawMode"; +import { SimpleSpriteAssembler } from "../assembler/SimpleSpriteAssembler"; +import { ListenerUpdateFlag } from "../../ListenerUpdateFlag"; +import { SlicedSpriteAssembler } from "../assembler/SlicedSpriteAssembler"; /** * Renders a Sprite for 2D graphics. @@ -19,39 +25,63 @@ export class SpriteRenderer extends Renderer implements ICustomClone { /** @internal */ static _textureProperty: ShaderProperty = Shader.getPropertyByName("u_spriteTexture"); - private static _tempVec3: Vector3 = new Vector3(); + /** @internal */ + @ignoreClone + _renderData: RenderData2D; - /** @internal temp solution. */ @ignoreClone - _customLocalBounds: BoundingBox = null; - /** @internal temp solution. */ + private _drawMode: SpriteDrawMode; @ignoreClone - _customRootEntity: Entity = null; + private _assembler: IAssembler; @deepClone - private _positions: Vector3[] = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; + private _color: Color = new Color(1, 1, 1, 1); @ignoreClone private _sprite: Sprite = null; - @deepClone - private _color: Color = new Color(1, 1, 1, 1); + + @ignoreClone + private _width: number = undefined; + @ignoreClone + private _height: number = undefined; @assignmentClone private _flipX: boolean = false; @assignmentClone private _flipY: boolean = false; + @assignmentClone - private _cacheFlipX: boolean = false; + private _maskLayer: number = SpriteMaskLayer.Layer0; @assignmentClone - private _cacheFlipY: boolean = false; + private _maskInteraction: SpriteMaskInteraction = SpriteMaskInteraction.None; + @ignoreClone private _dirtyFlag: number = 0; @ignoreClone - private _isWorldMatrixDirty: BoolUpdateFlag; - @ignoreClone - private _spriteDirty: BoolUpdateFlag; - @assignmentClone - private _maskInteraction: SpriteMaskInteraction = SpriteMaskInteraction.None; - @assignmentClone - private _maskLayer: number = SpriteMaskLayer.Layer0; + private _spriteChangeFlag: ListenerUpdateFlag = null; + + /** + * The draw mode of the sprite renderer. + */ + get drawMode(): SpriteDrawMode { + return this._drawMode; + } + + set drawMode(drawMode: SpriteDrawMode) { + if (this._drawMode !== drawMode) { + this._drawMode = drawMode; + switch (drawMode) { + case SpriteDrawMode.Simple: + this._assembler = SimpleSpriteAssembler; + break; + case SpriteDrawMode.Sliced: + this._assembler = SlicedSpriteAssembler; + break; + default: + break; + } + this._assembler.resetData(this); + this._dirtyFlag |= DirtyFlag.All; + } + } /** * The Sprite to render. @@ -62,11 +92,14 @@ export class SpriteRenderer extends Renderer implements ICustomClone { set sprite(value: Sprite | null) { if (this._sprite !== value) { - this._spriteDirty && this._spriteDirty.destroy(); this._sprite = value; + this._spriteChangeFlag && this._spriteChangeFlag.destroy(); if (value) { - this._spriteDirty = value._registerUpdateFlag(); + this._spriteChangeFlag = value._registerUpdateFlag(); + this._spriteChangeFlag.listener = this._onSpriteChange; + this._dirtyFlag |= DirtyFlag.All; } + this.shaderData.setTexture(SpriteRenderer._textureProperty, value.texture); } } @@ -83,6 +116,40 @@ export class SpriteRenderer extends Renderer implements ICustomClone { } } + /** + * Render width. + */ + get width(): number { + if (this._width === undefined && this._sprite) { + this.width = this._sprite.width; + } + return this._width; + } + + set width(value: number) { + if (this._width !== value) { + this._width = value; + this._dirtyFlag |= DirtyFlag.Position; + } + } + + /** + * Render height. + */ + get height(): number { + if (this._height === undefined && this._sprite) { + this.height = this._sprite.height; + } + return this._height; + } + + set height(value: number) { + if (this._height !== value) { + this._height = value; + this._dirtyFlag |= DirtyFlag.Position; + } + } + /** * Flips the sprite on the X axis. */ @@ -93,7 +160,7 @@ export class SpriteRenderer extends Renderer implements ICustomClone { set flipX(value: boolean) { if (this._flipX !== value) { this._flipX = value; - this._setDirtyFlagTrue(DirtyFlag.Flip); + this._dirtyFlag |= DirtyFlag.Position; } } @@ -107,22 +174,20 @@ export class SpriteRenderer extends Renderer implements ICustomClone { set flipY(value: boolean) { if (this._flipY !== value) { this._flipY = value; - this._setDirtyFlagTrue(DirtyFlag.Flip); + this._dirtyFlag |= DirtyFlag.Position; } } /** - * Interacts with the masks. + * The bounding volume of the spriteRenderer. */ - get maskInteraction(): SpriteMaskInteraction { - return this._maskInteraction; - } - - set maskInteraction(value: SpriteMaskInteraction) { - if (this._maskInteraction !== value) { - this._maskInteraction = value; - this._setDirtyFlagTrue(DirtyFlag.MaskInteraction); + get bounds(): BoundingBox { + if (this._transformChangeFlag.flag || this._dirtyFlag & DirtyFlag.Position) { + this._assembler.updatePositions(this); + this._dirtyFlag &= ~DirtyFlag.Position; + this._transformChangeFlag.flag = false; } + return this._bounds; } /** @@ -136,111 +201,58 @@ export class SpriteRenderer extends Renderer implements ICustomClone { this._maskLayer = value; } + /** + * Interacts with the masks. + */ + get maskInteraction(): SpriteMaskInteraction { + return this._maskInteraction; + } + + set maskInteraction(value: SpriteMaskInteraction) { + if (this._maskInteraction !== value) { + this._maskInteraction = value; + this._updateStencilState(); + } + } + /** * @internal */ constructor(entity: Entity) { super(entity); - this._isWorldMatrixDirty = entity.transform.registerWorldChangeFlag(); + this._renderData = new RenderData2D(4, [], [], null, this._color); + this.drawMode = SpriteDrawMode.Simple; this.setMaterial(this._engine._spriteDefaultMaterial); + this._onSpriteChange = this._onSpriteChange.bind(this); } /** * @internal */ _render(camera: Camera): void { - const { sprite } = this; - if (!sprite) { + if (!this.sprite?.texture) { return; } - const { texture } = sprite; - if (!texture) { - return; - } - - const { _positions } = this; - const { transform } = this.entity; - - // Update sprite data. - sprite._updateMesh(); - - if (this._isWorldMatrixDirty.flag || this._spriteDirty.flag) { - const localPositions = sprite._positions; - const localVertexPos = SpriteRenderer._tempVec3; - const worldMatrix = transform.worldMatrix; - const { flipX, flipY } = this; - - for (let i = 0, n = _positions.length; i < n; i++) { - const curVertexPos = localPositions[i]; - localVertexPos.set(flipX ? -curVertexPos.x : curVertexPos.x, flipY ? -curVertexPos.y : curVertexPos.y, 0); - Vector3.transformToVec3(localVertexPos, worldMatrix, _positions[i]); - } - - this._setDirtyFlagFalse(DirtyFlag.Flip); - this._isWorldMatrixDirty.flag = false; - this._spriteDirty.flag = false; - this._cacheFlipX = flipX; - this._cacheFlipY = flipY; - } else if (this._isContainDirtyFlag(DirtyFlag.Flip)) { - const { flipX, flipY } = this; - const flipXChange = this._cacheFlipX !== flipX; - const flipYChange = this._cacheFlipY !== flipY; - - if (flipXChange || flipYChange) { - const { x, y } = transform.worldPosition; - - for (let i = 0, n = _positions.length; i < n; i++) { - const curPos = _positions[i]; - - if (flipXChange) { - curPos.x = x * 2 - curPos.x; - } - if (flipYChange) { - curPos.y = y * 2 - curPos.y; - } - } - } - this._setDirtyFlagFalse(DirtyFlag.Flip); - this._cacheFlipX = flipX; - this._cacheFlipY = flipY; + // Update position. + if (this._transformChangeFlag.flag || this._dirtyFlag & DirtyFlag.Position) { + this._assembler.updatePositions(this); + this._dirtyFlag &= ~DirtyFlag.Position; + this._transformChangeFlag.flag = false; } - if (this._isContainDirtyFlag(DirtyFlag.MaskInteraction)) { - this._updateStencilState(); - this._setDirtyFlagFalse(DirtyFlag.MaskInteraction); + // Update uv. + if (this._dirtyFlag & DirtyFlag.UV) { + this._assembler.updateUVs(this); + this._dirtyFlag &= ~DirtyFlag.UV; } - this.shaderData.setTexture(SpriteRenderer._textureProperty, texture); - const material = this.getMaterial(); - - const spriteElementPool = this._engine._spriteElementPool; - const spriteElement = spriteElementPool.getFromPool(); - spriteElement.setValue(this, _positions, sprite._uv, sprite._triangles, this.color, material, camera); + // Push primitive. + const spriteElement = this._engine._spriteElementPool.getFromPool(); + spriteElement.setValue(this, this._renderData, this.getMaterial()); camera._renderPipeline.pushPrimitive(spriteElement); } - /** - * @internal - */ - _onDestroy(): void { - this._isWorldMatrixDirty.destroy(); - this._spriteDirty && this._spriteDirty.destroy(); - super._onDestroy(); - } - - private _isContainDirtyFlag(type: number): boolean { - return (this._dirtyFlag & type) != 0; - } - - private _setDirtyFlagTrue(type: number): void { - this._dirtyFlag |= type; - } - - private _setDirtyFlagFalse(type: number): void { - this._dirtyFlag &= ~type; - } - /** * @internal */ @@ -249,23 +261,15 @@ export class SpriteRenderer extends Renderer implements ICustomClone { } /** - * @override + * @internal */ - protected _updateBounds(worldBounds: BoundingBox): void { - const sprite = this._sprite; - if (sprite) { - if (this._customLocalBounds && this._customRootEntity) { - const worldMatrix = this._customRootEntity.transform.worldMatrix; - BoundingBox.transform(this._customLocalBounds, worldMatrix, worldBounds); - } else { - const localBounds = sprite.bounds; - const worldMatrix = this._entity.transform.worldMatrix; - BoundingBox.transform(localBounds, worldMatrix, worldBounds); - } - } else { - worldBounds.min.set(0, 0, 0); - worldBounds.max.set(0, 0, 0); - } + _onDestroy(): void { + this._color = null; + this._sprite = null; + this._assembler = null; + this._renderData = null; + this._spriteChangeFlag && this._spriteChangeFlag.destroy(); + super._onDestroy(); } private _updateStencilState(): void { @@ -273,7 +277,6 @@ export class SpriteRenderer extends Renderer implements ICustomClone { const material = this.getInstanceMaterial(); const stencilState = material.renderState.stencilState; const maskInteraction = this._maskInteraction; - if (maskInteraction === SpriteMaskInteraction.None) { stencilState.enabled = false; stencilState.writeMask = 0xff; @@ -291,9 +294,41 @@ export class SpriteRenderer extends Renderer implements ICustomClone { stencilState.compareFunctionBack = compare; } } + + private _onSpriteChange(dirtyFlag: SpritePropertyDirtyFlag): void { + switch (dirtyFlag) { + case SpritePropertyDirtyFlag.texture: + const { _sprite: sprite } = this; + if (this._width === undefined && this._height === undefined) { + this.width = sprite.width; + this.height = sprite.height; + } + this.shaderData.setTexture(SpriteRenderer._textureProperty, sprite.texture); + break; + case SpritePropertyDirtyFlag.size: + this._drawMode === SpriteDrawMode.Sliced && (this._dirtyFlag |= DirtyFlag.Position); + break; + case SpritePropertyDirtyFlag.border: + this._drawMode === SpriteDrawMode.Sliced && (this._dirtyFlag |= DirtyFlag.All); + break; + case SpritePropertyDirtyFlag.region: + case SpritePropertyDirtyFlag.atlasRegionOffset: + this._dirtyFlag |= DirtyFlag.All; + break; + case SpritePropertyDirtyFlag.atlasRegion: + this._dirtyFlag |= DirtyFlag.UV; + break; + case SpritePropertyDirtyFlag.pivot: + this._dirtyFlag |= DirtyFlag.Position; + break; + default: + break; + } + } } enum DirtyFlag { - Flip = 0x1, - MaskInteraction = 0x2 + Position = 0x1, + UV = 0x2, + All = 0x3 } diff --git a/packages/core/src/RenderPipeline/Basic2DBatcher.ts b/packages/core/src/RenderPipeline/Basic2DBatcher.ts index c9811d00ec..ff76a839e0 100644 --- a/packages/core/src/RenderPipeline/Basic2DBatcher.ts +++ b/packages/core/src/RenderPipeline/Basic2DBatcher.ts @@ -1,3 +1,4 @@ +import { Camera } from "../Camera"; import { Engine } from "../Engine"; import { Buffer, BufferBindFlag, BufferUsage, IndexFormat, MeshTopology, SubMesh, VertexElement } from "../graphic"; import { BufferMesh } from "../mesh"; @@ -13,6 +14,8 @@ export abstract class Basic2DBatcher { static MAX_VERTEX_COUNT: number = 4096; static _canUploadSameBuffer: boolean = true; + /** @internal */ + _engine: Engine; /** @internal */ _subMeshPool: ClassPool = new ClassPool(SubMesh); /** @internal */ @@ -37,6 +40,8 @@ export abstract class Basic2DBatcher { _elementCount: number = 0; constructor(engine: Engine) { + this._engine = engine; + const { MAX_VERTEX_COUNT } = Basic2DBatcher; this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); this._indices = new Uint16Array(MAX_VERTEX_COUNT * 3); @@ -47,25 +52,24 @@ export abstract class Basic2DBatcher { } } - drawElement(element: Element): void { - const len = element.positions.length; + drawElement(element: Element, camera: Camera): void { + const len = element.renderData.vertexCount; if (this._vertexCount + len > Basic2DBatcher.MAX_VERTEX_COUNT) { - this.flush(element.camera.engine); + this.flush(camera); } this._vertexCount += len; this._batchedQueue[this._elementCount++] = element; } - flush(engine: Engine): void { + flush(camera: Camera): void { const batchedQueue = this._batchedQueue; if (batchedQueue.length === 0) { return; } - - this._updateData(engine); - this.drawBatches(engine); + this._updateData(this._engine); + this.drawBatches(camera); if (!Basic2DBatcher._canUploadSameBuffer) { this._flushId++; @@ -159,13 +163,13 @@ export abstract class Basic2DBatcher { vertexIndex = this.updateVertices(curElement, vertices, vertexIndex); // Batch indice - const { triangles } = curElement; + const { triangles } = curElement.renderData; const triangleNum = triangles.length; for (let j = 0; j < triangleNum; j++) { indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; } - curIndiceStartIndex += curElement.positions.length; + curIndiceStartIndex += curElement.renderData.vertexCount; if (preElement === null) { vertexCount += triangleNum; @@ -216,5 +220,5 @@ export abstract class Basic2DBatcher { /** * @internal */ - abstract drawBatches(engine: Engine): void; + abstract drawBatches(camera: Camera): void; } diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 757c9ad0fb..55c173e0fe 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -69,7 +69,7 @@ export class RenderQueue { } if (!!(item as RenderElement).mesh) { - this._spriteBatcher.flush(engine); + this._spriteBatcher.flush(camera); const compileMacros = Shader._compileMacros; const element = item; @@ -135,16 +135,16 @@ export class RenderQueue { program.uploadUnGroupTextures(); } } - material.renderState._apply(camera.engine, renderer.entity.transform._isFrontFaceInvert()); + material.renderState._apply(engine, renderer.entity.transform._isFrontFaceInvert()); rhi.drawPrimitive(element.mesh, element.subMesh, program); } else { const spriteElement = item; - this._spriteBatcher.drawElement(spriteElement); + this._spriteBatcher.drawElement(spriteElement, camera); } } - this._spriteBatcher.flush(engine); + this._spriteBatcher.flush(camera); } /** diff --git a/packages/core/src/RenderPipeline/SpriteBatcher.ts b/packages/core/src/RenderPipeline/SpriteBatcher.ts index c382bfbca0..3e6919424f 100644 --- a/packages/core/src/RenderPipeline/SpriteBatcher.ts +++ b/packages/core/src/RenderPipeline/SpriteBatcher.ts @@ -1,5 +1,6 @@ import { SpriteMaskInteraction } from "../2d/enums/SpriteMaskInteraction"; import { SpriteRenderer } from "../2d/sprite/SpriteRenderer"; +import { Camera } from "../Camera"; import { Engine } from "../Engine"; import { VertexElementFormat } from "../graphic/enums/VertexElementFormat"; import { VertexElement } from "../graphic/VertexElement"; @@ -54,12 +55,10 @@ export class SpriteBatcher extends Basic2DBatcher { } updateVertices(element: SpriteElement, vertices: Float32Array, vertexIndex: number): number { - const { positions, uv, color } = element; - const verticesNum = positions.length; - for (let i = 0; i < verticesNum; i++) { + const { positions, uvs, color, vertexCount } = element.renderData; + for (let i = 0; i < vertexCount; i++) { const curPos = positions[i]; - const curUV = uv[i]; - + const curUV = uvs[i]; vertices[vertexIndex++] = curPos.x; vertices[vertexIndex++] = curPos.y; vertices[vertexIndex++] = curPos.z; @@ -74,11 +73,13 @@ export class SpriteBatcher extends Basic2DBatcher { return vertexIndex; } - drawBatches(engine: Engine): void { + drawBatches(camera: Camera): void { + const { _engine: engine, _batchedQueue: batchedQueue } = this; const mesh = this._meshes[this._flushId]; const subMeshes = mesh.subMeshes; - const batchedQueue = this._batchedQueue; const maskManager = engine._spriteMaskManager; + const sceneData = camera.scene.shaderData; + const cameraData = camera.shaderData; for (let i = 0, len = subMeshes.length; i < len; i++) { const subMesh = subMeshes[i]; @@ -89,7 +90,6 @@ export class SpriteBatcher extends Basic2DBatcher { } const renderer = spriteElement.component; - const camera = spriteElement.camera; const material = spriteElement.material; maskManager.preRender(camera, renderer); @@ -108,12 +108,12 @@ export class SpriteBatcher extends Basic2DBatcher { program.bind(); program.groupingOtherUniformBlock(); - program.uploadAll(program.sceneUniformBlock, camera.scene.shaderData); - program.uploadAll(program.cameraUniformBlock, camera.shaderData); + program.uploadAll(program.sceneUniformBlock, sceneData); + program.uploadAll(program.cameraUniformBlock, cameraData); program.uploadAll(program.rendererUniformBlock, renderer.shaderData); program.uploadAll(program.materialUniformBlock, material.shaderData); - material.renderState._apply(engine,false); + material.renderState._apply(engine, false); engine._hardwareRenderer.drawPrimitive(mesh, subMesh, program); diff --git a/packages/core/src/RenderPipeline/SpriteElement.ts b/packages/core/src/RenderPipeline/SpriteElement.ts index 133770318b..4b46ec8213 100644 --- a/packages/core/src/RenderPipeline/SpriteElement.ts +++ b/packages/core/src/RenderPipeline/SpriteElement.ts @@ -1,32 +1,15 @@ -import { Color, Vector2, Vector3 } from "@oasis-engine/math"; -import { Camera } from "../Camera"; +import { RenderData2D } from "../2d/data/RenderData2D"; import { Material } from "../material/Material"; import { Renderer } from "../Renderer"; export class SpriteElement { component: Renderer; - positions: Vector3[]; - uv: Vector2[]; - triangles: number[]; - color: Color; + renderData: RenderData2D; material: Material; - camera: Camera; - setValue( - component: Renderer, - positions: Vector3[], - uv: Vector2[], - triangles: number[], - color: Color, - material: Material, - camera: Camera - ): void { + setValue(component: Renderer, renderDate: RenderData2D, material: Material): void { this.component = component; - this.positions = positions; - this.uv = uv; - this.triangles = triangles; - this.color = color; + this.renderData = renderDate; this.material = material; - this.camera = camera; } } diff --git a/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts index 4236e6533c..254e7bf1a7 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts @@ -1,4 +1,5 @@ import { SpriteMask } from "../2d/sprite/SpriteMask"; +import { Camera } from "../Camera"; import { Engine } from "../Engine"; import { VertexElementFormat } from "../graphic/enums/VertexElementFormat"; import { VertexElement } from "../graphic/VertexElement"; @@ -33,12 +34,10 @@ export class SpriteMaskBatcher extends Basic2DBatcher { } updateVertices(element: SpriteMaskElement, vertices: Float32Array, vertexIndex: number): number { - const { positions, uv } = element; - const verticesNum = positions.length; - for (let i = 0; i < verticesNum; i++) { + const { positions, uvs, vertexCount } = element.renderData; + for (let i = 0; i < vertexCount; i++) { const curPos = positions[i]; - const curUV = uv[i]; - + const curUV = uvs[i]; vertices[vertexIndex++] = curPos.x; vertices[vertexIndex++] = curPos.y; vertices[vertexIndex++] = curPos.z; @@ -49,10 +48,12 @@ export class SpriteMaskBatcher extends Basic2DBatcher { return vertexIndex; } - drawBatches(engine: Engine): void { + drawBatches(camera: Camera): void { + const { _engine: engine, _batchedQueue: batchedQueue } = this; const mesh = this._meshes[this._flushId]; const subMeshes = mesh.subMeshes; - const batchedQueue = this._batchedQueue; + const sceneData = camera.scene.shaderData; + const cameraData = camera.shaderData; for (let i = 0, len = subMeshes.length; i < len; i++) { const subMesh = subMeshes[i]; @@ -84,12 +85,10 @@ export class SpriteMaskBatcher extends Basic2DBatcher { return; } - const camera = spriteMaskElement.camera; - program.bind(); program.groupingOtherUniformBlock(); - program.uploadAll(program.sceneUniformBlock, camera.scene.shaderData); - program.uploadAll(program.cameraUniformBlock, camera.shaderData); + program.uploadAll(program.sceneUniformBlock, sceneData); + program.uploadAll(program.cameraUniformBlock, cameraData); program.uploadAll(program.rendererUniformBlock, renderer.shaderData); program.uploadAll(program.materialUniformBlock, material.shaderData); diff --git a/packages/core/src/RenderPipeline/SpriteMaskElement.ts b/packages/core/src/RenderPipeline/SpriteMaskElement.ts index 4f83015466..1f6ec69300 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskElement.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskElement.ts @@ -1,22 +1,18 @@ import { Vector2, Vector3 } from "@oasis-engine/math"; +import { RenderData2D } from "../2d/data/RenderData2D"; import { Camera } from "../Camera"; import { Component } from "../Component"; import { Material } from "../material/Material"; export class SpriteMaskElement { component: Component; - positions: Vector3[]; - uv: Vector2[]; - triangles: number[]; + renderData: RenderData2D; material: Material; isAdd: boolean = true; - camera: Camera; - setValue(component: Component, positions: Vector3[], uv: Vector2[], triangles: number[], material: Material): void { + setValue(component: Component, renderData: RenderData2D, material: Material): void { this.component = component; - this.positions = positions; - this.uv = uv; - this.triangles = triangles; + this.renderData = renderData; this.material = material; } } diff --git a/packages/core/src/RenderPipeline/SpriteMaskManager.ts b/packages/core/src/RenderPipeline/SpriteMaskManager.ts index a1631c4101..8117b7c712 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskManager.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskManager.ts @@ -28,7 +28,7 @@ export class SpriteMaskManager { this._batcher.clear(); this._processMasksDiff(camera, renderer); - this._batcher.flush(camera.engine); + this._batcher.flush(camera); } postRender(renderer: SpriteRenderer): void { @@ -65,14 +65,14 @@ export class SpriteMaskManager { if (influenceLayers & addLayer) { const maskRenderElement = mask._maskElement; maskRenderElement.isAdd = true; - this._batcher.drawElement(maskRenderElement); + this._batcher.drawElement(maskRenderElement, camera); continue; } if (influenceLayers & reduceLayer) { const maskRenderElement = mask._maskElement; maskRenderElement.isAdd = false; - this._batcher.drawElement(maskRenderElement); + this._batcher.drawElement(maskRenderElement, camera); } } } diff --git a/packages/core/src/Renderer.ts b/packages/core/src/Renderer.ts index 1ca9d1b801..8a0d0898de 100644 --- a/packages/core/src/Renderer.ts +++ b/packages/core/src/Renderer.ts @@ -45,16 +45,18 @@ export class Renderer extends Component { /** @internal */ @ignoreClone _globalShaderMacro: ShaderMacroCollection = new ShaderMacroCollection(); + /** @internal */ + @ignoreClone + _transformChangeFlag: BoolUpdateFlag; + /** @internal */ + @deepClone + _bounds: BoundingBox = new BoundingBox(); @ignoreClone protected _overrideUpdate: boolean = false; @shallowClone protected _materials: Material[] = []; - @ignoreClone - private _transformChangeFlag: BoolUpdateFlag; - @deepClone - private _bounds: BoundingBox = new BoundingBox(new Vector3(), new Vector3()); @ignoreClone private _mvMatrix: Matrix = new Matrix(); @ignoreClone diff --git a/packages/loader/src/SpriteAtlasLoader.ts b/packages/loader/src/SpriteAtlasLoader.ts index 31502fdc4c..95b6d5d621 100644 --- a/packages/loader/src/SpriteAtlasLoader.ts +++ b/packages/loader/src/SpriteAtlasLoader.ts @@ -1,7 +1,13 @@ import { AssetPromise, - AssetType, Loader, LoadItem, resourceLoader, ResourceManager, Sprite, - SpriteAtlas, Texture2D + AssetType, + Loader, + LoadItem, + resourceLoader, + ResourceManager, + Sprite, + SpriteAtlas, + Texture2D } from "@oasis-engine/core"; import { AtlasConfig } from "@oasis-engine/core/types/2d/atlas/types"; import { Rect, Vector2 } from "@oasis-engine/math"; @@ -9,6 +15,8 @@ import { GLTFUtil } from "./gltf/GLTFUtil"; @resourceLoader(AssetType.SpriteAtlas, ["atlas"], false) class SpriteAtlasLoader extends Loader { + private _tempRect: Rect = new Rect(); + private _tempVec2: Vector2 = new Vector2(); load(item: LoadItem, resourceManager: ResourceManager): AssetPromise { return new AssetPromise((resolve, reject) => { this.request(item.url, { @@ -28,8 +36,7 @@ class SpriteAtlasLoader extends Loader { ).then((imgs) => { const { engine } = resourceManager; // Generate a SpriteAtlas object. - const tempRect = new Rect(); - const tempVect2 = new Vector2(); + const { _tempRect: tempRect, _tempVec2: tempVec2 } = this; const spriteAtlas = new SpriteAtlas(engine); for (let i = 0; i < atlasItemsLen; i++) { // Generate Texture2D according to configuration. @@ -45,13 +52,13 @@ class SpriteAtlasLoader extends Loader { const sourceHeightReciprocal = 1.0 / height; for (let j = sprites.length - 1; j >= 0; j--) { const atlasSprite = sprites[j]; - const { region, pivot, atlasRegionOffset, atlasRegion, id } = atlasSprite; + const { region, atlasRegionOffset, atlasRegion, id, pivot } = atlasSprite; const sprite = new Sprite( engine, texture, region ? tempRect.set(region.x, region.y, region.w, region.h) : undefined, - pivot ? tempVect2.set(pivot.x, pivot.y) : undefined, - atlasSprite.pixelsPerUnit || undefined, + pivot ? tempVec2.set(pivot.x, pivot.y) : undefined, + undefined, atlasSprite.name ); sprite.atlasRegion.set( @@ -63,19 +70,11 @@ class SpriteAtlasLoader extends Loader { atlasSprite.atlasRotated && (sprite.atlasRotated = true); if (atlasRegionOffset) { const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; - let originalWReciprocal: number, originalHReciprocal: number; - if (atlasSprite.atlasRotated) { - originalWReciprocal = 1 / (offsetLeft + atlasRegion.h + offsetRight); - originalHReciprocal = 1 / (offsetTop + atlasRegion.w + offsetBottom); - } else { - originalWReciprocal = 1 / (offsetLeft + atlasRegion.w + offsetRight); - originalHReciprocal = 1 / (offsetTop + atlasRegion.h + offsetBottom); - } sprite.atlasRegionOffset.set( - offsetLeft * originalWReciprocal, - offsetTop * originalHReciprocal, - offsetRight * originalWReciprocal, - offsetBottom * originalHReciprocal + offsetLeft * sourceWidthReciprocal, + offsetTop * sourceHeightReciprocal, + offsetRight * sourceWidthReciprocal, + offsetBottom * sourceHeightReciprocal ); } if (id !== undefined) { diff --git a/packages/math/src/CollisionUtil.ts b/packages/math/src/CollisionUtil.ts index 350ee14520..9eb68efe89 100644 --- a/packages/math/src/CollisionUtil.ts +++ b/packages/math/src/CollisionUtil.ts @@ -324,7 +324,7 @@ export class CollisionUtil { const normal = plane.normal; back.set(normal.x >= 0 ? min.x : max.x, normal.y >= 0 ? min.y : max.y, normal.z >= 0 ? min.z : max.z); - if (Vector3.dot(plane.normal, back) > -plane.distance) { + if (Vector3.dot(normal, back) > -plane.distance) { return false; } } From 67a12a8fb018318b5835233cfbab9214b5ecdfe6 Mon Sep 17 00:00:00 2001 From: zhuxudong Date: Tue, 5 Jul 2022 12:17:53 +0800 Subject: [PATCH 23/33] fix: TextureCube is left-hand,so x need inverse (#855) --- packages/core/src/shaderlib/pbr/ibl_frag_define.glsl | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl b/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl index 9f46499bee..786293b776 100644 --- a/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl +++ b/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl @@ -2,6 +2,7 @@ // sh need be pre-scaled in CPU. vec3 getLightProbeIrradiance(vec3 sh[9], vec3 normal){ + normal.x = -normal.x; vec3 result = sh[0] + sh[1] * (normal.y) + From 6a008251687c51801eea78664176d6fc8cc52a05 Mon Sep 17 00:00:00 2001 From: AZhan Date: Tue, 5 Jul 2022 17:43:48 +0800 Subject: [PATCH 24/33] `InputManager` support pointer button and wheel (#831) * feat: `InputManager` support pointer button and wheel --- packages/core/src/Engine.ts | 4 +- packages/core/src/input/InputManager.ts | 161 +++++++++++--- .../core/src/input/enums/PointerButton.ts | 29 +++ packages/core/src/input/index.ts | 3 +- packages/core/src/input/interface/IInput.ts | 18 ++ .../src/input/keyboard/KeyboardManager.ts | 200 +++++++++-------- .../core/src/input/pointer/PointerManager.ts | 203 +++++++++++++----- packages/core/src/input/wheel/WheelManager.ts | 80 +++++++ 8 files changed, 524 insertions(+), 174 deletions(-) create mode 100644 packages/core/src/input/enums/PointerButton.ts create mode 100644 packages/core/src/input/interface/IInput.ts create mode 100644 packages/core/src/input/wheel/WheelManager.ts diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 4d072611e8..c795ccf46d 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -280,9 +280,7 @@ export class Engine extends EventDispatcher { scene._activeCameras.sort((camera1, camera2) => camera1.priority - camera2.priority); componentsManager.callScriptOnStart(); - if (this.physicsManager._initialized) { - this.physicsManager._update(deltaTime / 1000.0); - } + this.physicsManager._initialized && this.physicsManager._update(deltaTime / 1000.0); this.inputManager._update(); componentsManager.callScriptOnUpdate(deltaTime); componentsManager.callAnimationUpdate(deltaTime); diff --git a/packages/core/src/input/InputManager.ts b/packages/core/src/input/InputManager.ts index ad989bdf59..0a1268e32d 100644 --- a/packages/core/src/input/InputManager.ts +++ b/packages/core/src/input/InputManager.ts @@ -3,70 +3,164 @@ import { KeyboardManager } from "./keyboard/KeyboardManager"; import { Keys } from "./enums/Keys"; import { Pointer } from "./pointer/Pointer"; import { PointerManager } from "./pointer/PointerManager"; +import { PointerButton } from "./enums/PointerButton"; +import { WheelManager } from "./wheel/WheelManager"; +import { Vector2, Vector3 } from "@oasis-engine/math"; /** * InputManager manages device input such as mouse, touch, keyboard, etc. */ export class InputManager { - /** Disable input for offscreen rendering. */ - private _enabled: boolean = true; + /** Sometimes the input module will not be initialized, such as off-screen rendering. */ + private _initialized: boolean = false; + private _curFrameCount: number = 0; + private _wheelManager: WheelManager; private _pointerManager: PointerManager; private _keyboardManager: KeyboardManager; /** * Pointer List. */ - get pointers(): Readonly { - return this._enabled ? this._pointerManager._pointers : null; + get pointers(): Readonly { + return this._initialized ? this._pointerManager._pointers : null; } /** * Whether to handle multi-pointer. */ get multiPointerEnabled(): boolean { - return this._enabled ? this._pointerManager._multiPointerEnabled : false; + return this._initialized ? this._pointerManager._multiPointerEnabled : false; } set multiPointerEnabled(enabled: boolean) { - this._enabled && (this._pointerManager._multiPointerEnabled = enabled); + this._initialized && (this._pointerManager._multiPointerEnabled = enabled); + } + + /** + * Get the change of the scroll wheel on the x-axis. + * @returns Change value + */ + get wheelDelta(): Readonly { + return this._initialized ? this._wheelManager._delta : null; + } + + /** + * Get the change of the pointer. + * @returns Change value + */ + get pointerMovingDelta(): Readonly { + return this._initialized ? this._pointerManager._movingDelta : null; + } + + /** + * Get the position of the pointer. + * @returns The position of the pointer + */ + get pointerPosition(): Readonly { + return this._initialized && this._pointerManager._pointers.length > 0 + ? this._pointerManager._currentPosition + : null; } /** * Whether the key is being held down, if there is no parameter, return whether any key is being held down. * @param key - The keys of the keyboard - * @returns Whether the key is being held down. + * @returns Whether the key is being held down */ isKeyHeldDown(key?: Keys): boolean { - if (key === undefined) { - return this._keyboardManager._curFrameHeldDownList.length > 0; + if (this._initialized) { + if (key === undefined) { + return this._keyboardManager._curFrameHeldDownList.length > 0; + } else { + return this._keyboardManager._curHeldDownKeyToIndexMap[key] != null; + } } else { - return !!this._keyboardManager._curHeldDownKeyToIndexMap[key]; + return false; } } /** * Whether the key starts to be pressed down during the current frame, if there is no parameter, return whether any key starts to be pressed down during the current frame. * @param key - The keys of the keyboard - * @returns Whether the key starts to be pressed down during the current frame. + * @returns Whether the key starts to be pressed down during the current frame */ isKeyDown(key?: Keys): boolean { - if (key === undefined) { - return this._keyboardManager._curFrameDownList.length > 0; + if (this._initialized) { + if (key === undefined) { + return this._keyboardManager._curFrameDownList.length > 0; + } else { + return this._keyboardManager._downKeyToFrameCountMap[key] === this._curFrameCount; + } } else { - return this._keyboardManager._downKeyToFrameCountMap[key] === this._keyboardManager._curFrameCount; + return false; } } /** * Whether the key is released during the current frame, if there is no parameter, return whether any key released during the current frame. * @param key - The keys of the keyboard - * @returns Whether the key is released during the current frame. + * @returns Whether the key is released during the current frame */ isKeyUp(key?: Keys): boolean { - if (key === undefined) { - return this._keyboardManager._curFrameUpList.length > 0; + if (this._initialized) { + if (key === undefined) { + return this._keyboardManager._curFrameUpList.length > 0; + } else { + return this._keyboardManager._upKeyToFrameCountMap[key] === this._curFrameCount; + } + } else { + return false; + } + } + + /** + * Whether the pointer is being held down, if there is no parameter, return whether any pointer is being held down. + * @param pointerButton - The pointerButton on a pointer device + * @returns Whether the pointer is being held down + */ + isPointerHeldDown(pointerButton?: PointerButton): boolean { + if (this._initialized) { + if (pointerButton === undefined) { + return this._pointerManager._buttons !== 0; + } else { + return (this._pointerManager._buttons & PointerManager.Buttons[pointerButton]) !== 0; + } } else { - return this._keyboardManager._upKeyToFrameCountMap[key] === this._keyboardManager._curFrameCount; + return false; + } + } + + /** + * Whether the pointer starts to be pressed down during the current frame, if there is no parameter, return whether any pointer starts to be pressed down during the current frame. + * @param pointerButton - The pointerButton on a pointer device + * @returns Whether the pointer starts to be pressed down during the current frame + */ + isPointerDown(pointerButton: PointerButton): boolean { + if (this._initialized) { + if (pointerButton === undefined) { + return this._pointerManager._downList.length > 0; + } else { + return this._pointerManager._downMap[pointerButton] === this._curFrameCount; + } + } else { + return false; + } + } + + /** + * Whether the pointer is released during the current frame, if there is no parameter, return whether any pointer released during the current frame. + * @param pointerButton - The pointerButtons on a mouse device + * @returns Whether the pointer is released during the current frame + */ + isPointerUp(pointerButton: PointerButton): boolean { + if (this._initialized) { + if (pointerButton === undefined) { + return this._pointerManager._upList.length > 0; + } else { + return this._pointerManager._upMap[pointerButton] === this._curFrameCount; + } + } else { + return false; } } @@ -77,13 +171,14 @@ export class InputManager { // @ts-ignore const canvas = engine._canvas._webCanvas; if (canvas instanceof HTMLCanvasElement) { - this._enabled = true; + this._wheelManager = new WheelManager(canvas); this._pointerManager = new PointerManager(engine, canvas); this._keyboardManager = new KeyboardManager(); this._onBlur = this._onBlur.bind(this); window.addEventListener("blur", this._onBlur); - } else { - this._enabled = false; + this._onFocus = this._onFocus.bind(this); + window.addEventListener("focus", this._onFocus); + this._initialized = true; } } @@ -91,9 +186,11 @@ export class InputManager { * @internal */ _update(): void { - if (this._enabled) { - this._pointerManager._update(); - this._keyboardManager._update(); + if (this._initialized) { + ++this._curFrameCount; + this._wheelManager._update(); + this._pointerManager._update(this._curFrameCount); + this._keyboardManager._update(this._curFrameCount); } } @@ -101,16 +198,24 @@ export class InputManager { * @internal */ _destroy(): void { - if (this._enabled) { + if (this._initialized) { window.removeEventListener("blur", this._onBlur); + window.removeEventListener("focus", this._onFocus); + this._wheelManager._destroy(); this._pointerManager._destroy(); this._keyboardManager._destroy(); } } private _onBlur(): void { - if (this._enabled) { - this._keyboardManager._onBlur(); - } + this._wheelManager._onBlur(); + this._pointerManager._onBlur(); + this._keyboardManager._onBlur(); + } + + private _onFocus(): void { + this._wheelManager._onFocus(); + this._pointerManager._onFocus(); + this._keyboardManager._onFocus(); } } diff --git a/packages/core/src/input/enums/PointerButton.ts b/packages/core/src/input/enums/PointerButton.ts new file mode 100644 index 0000000000..8060aabe7e --- /dev/null +++ b/packages/core/src/input/enums/PointerButton.ts @@ -0,0 +1,29 @@ +/** + * Defines values that specify the buttons on a pointer device. + * Refer to the W3C standards.(https://www.w3.org/TR/uievents/#dom-mouseevent-button) + * Refer to Microsoft's documentation.(https://docs.microsoft.com/en-us/dotnet/api/system.windows.input.mousebutton?view=windowsdesktop-6.0) + */ +export enum PointerButton { + /** Indicate the primary pointer of the device (in general, the left button or the only button on single-button devices, used to activate a user interface control or select text) or the un-initialized value. */ + Primary = 0, + /** Indicate the auxiliary pointer (in general, the middle button, often combined with a mouse wheel). */ + Auxiliary = 1, + /** Indicate the secondary pointer (in general, the right button, often used to display a context menu). */ + Secondary = 2, + /** Indicate the X1 (back) pointer. */ + XButton1 = 3, + /** Indicate the X2 (forward) pointer. */ + XButton2 = 4, + /** Indicate the X3 pointer. */ + XButton3 = 5, + /** Indicate the X4 pointer. */ + XButton4 = 6, + /** Indicate the X5 pointer. */ + XButton5 = 7, + /** Indicate the X6 pointer. */ + XButton6 = 8, + /** Indicate the X7 pointer. */ + XButton7 = 9, + /** Indicate the X8 pointer. */ + XButton8 = 10 +} diff --git a/packages/core/src/input/index.ts b/packages/core/src/input/index.ts index eccbaf0429..8edd5391dc 100644 --- a/packages/core/src/input/index.ts +++ b/packages/core/src/input/index.ts @@ -1,4 +1,5 @@ export { PointerPhase } from "./enums/PointerPhase"; export { Pointer } from "./pointer/Pointer"; export { InputManager } from "./InputManager"; -export { Keys } from "./enums/Keys"; \ No newline at end of file +export { Keys } from "./enums/Keys"; +export { PointerButton } from "./enums/PointerButton"; diff --git a/packages/core/src/input/interface/IInput.ts b/packages/core/src/input/interface/IInput.ts new file mode 100644 index 0000000000..cfc0a20867 --- /dev/null +++ b/packages/core/src/input/interface/IInput.ts @@ -0,0 +1,18 @@ +export interface IInput { + /** + * Handler function updated every frame. + */ + _update(frameCount?: number): void; + /** + * Function called when the engine is destroyed. + */ + _destroy(): void; + /** + * Function called when focused. + */ + _onFocus(): void; + /** + * Function called when focus is lost. + */ + _onBlur(): void; +} diff --git a/packages/core/src/input/keyboard/KeyboardManager.ts b/packages/core/src/input/keyboard/KeyboardManager.ts index a36c45fd16..c1cbd90c0f 100644 --- a/packages/core/src/input/keyboard/KeyboardManager.ts +++ b/packages/core/src/input/keyboard/KeyboardManager.ts @@ -1,107 +1,131 @@ - import { DisorderedArray } from "../../DisorderedArray"; import { Keys } from "../enums/Keys"; +import { IInput } from "../interface/IInput"; /** * Keyboard Manager. * @internal */ -export class KeyboardManager { - /** @internal */ - _curFrameCount: number = 0; - /** @internal */ - _curHeldDownKeyToIndexMap: number[] = []; - /** @internal */ - _upKeyToFrameCountMap: number[] = []; - /** @internal */ - _downKeyToFrameCountMap: number[] = []; +export class KeyboardManager implements IInput { + /** @internal */ + _curHeldDownKeyToIndexMap: number[] = []; + /** @internal */ + _upKeyToFrameCountMap: number[] = []; + /** @internal */ + _downKeyToFrameCountMap: number[] = []; - /** @internal */ - _curFrameHeldDownList: DisorderedArray = new DisorderedArray(); - /** @internal */ - _curFrameDownList: DisorderedArray = new DisorderedArray(); - /** @internal */ - _curFrameUpList: DisorderedArray = new DisorderedArray(); + /** @internal */ + _curFrameHeldDownList: DisorderedArray = new DisorderedArray(); + /** @internal */ + _curFrameDownList: DisorderedArray = new DisorderedArray(); + /** @internal */ + _curFrameUpList: DisorderedArray = new DisorderedArray(); - private _nativeEvents: KeyboardEvent[] = []; - private _onKeyEvent: (evt: KeyboardEvent) => void; + private _nativeEvents: KeyboardEvent[] = []; + private _hadListener: boolean = false; - /** - * Create a KeyboardManager. - */ - constructor() { - this._onKeyEvent = (evt: KeyboardEvent) => { - this._nativeEvents.push(evt); - } - window.addEventListener('keydown', this._onKeyEvent); - window.addEventListener('keyup', this._onKeyEvent); - } + /** + * Create a KeyboardManager. + */ + constructor() { + this._onKeyEvent = this._onKeyEvent.bind(this); + window.addEventListener("keydown", this._onKeyEvent); + window.addEventListener("keyup", this._onKeyEvent); + this._hadListener = true; + } - /** - * @internal - */ - _update(): void { - const curFrameCount = ++this._curFrameCount; - const { _nativeEvents: nativeEvents, _curFrameDownList: curFrameDownList, _curFrameUpList: curFrameUpList } = this; - curFrameDownList.length = 0; - curFrameUpList.length = 0; - if (nativeEvents.length > 0) { - const { _curHeldDownKeyToIndexMap: curHeldDownKeyToIndexMap, _curFrameHeldDownList: curFrameHeldDownList, _downKeyToFrameCountMap: downKeyToFrameCountMap, _upKeyToFrameCountMap: upKeyToFrameCountMap } = this; - for (let i = 0, n = nativeEvents.length; i < n; i++) { - const evt = nativeEvents[i]; - const codeKey = Keys[evt.code]; - switch (evt.type) { - case 'keydown': - // Filter the repeated triggers of the keyboard. - if (curHeldDownKeyToIndexMap[codeKey] == null) { - curFrameDownList.add(codeKey); - curFrameHeldDownList.add(codeKey); - curHeldDownKeyToIndexMap[codeKey] = curFrameHeldDownList.length - 1; - downKeyToFrameCountMap[codeKey] = curFrameCount; - } - break; - case 'keyup': - const delIndex = curHeldDownKeyToIndexMap[codeKey]; - if (delIndex != null) { - curHeldDownKeyToIndexMap[codeKey] = null; - const swapCode = curFrameHeldDownList.deleteByIndex(delIndex); - swapCode && (curHeldDownKeyToIndexMap[swapCode] = delIndex); - } - curFrameUpList.add(codeKey); - upKeyToFrameCountMap[codeKey] = curFrameCount; - break; - default: - break; - } + /** + * @internal + */ + _update(frameCount: number): void { + const { _nativeEvents: nativeEvents, _curFrameDownList: curFrameDownList, _curFrameUpList: curFrameUpList } = this; + curFrameDownList.length = 0; + curFrameUpList.length = 0; + if (nativeEvents.length > 0) { + const { + _curHeldDownKeyToIndexMap: curHeldDownKeyToIndexMap, + _curFrameHeldDownList: curFrameHeldDownList, + _downKeyToFrameCountMap: downKeyToFrameCountMap, + _upKeyToFrameCountMap: upKeyToFrameCountMap + } = this; + for (let i = 0, n = nativeEvents.length; i < n; i++) { + const evt = nativeEvents[i]; + const codeKey = Keys[evt.code]; + switch (evt.type) { + case "keydown": + // Filter the repeated triggers of the keyboard. + if (curHeldDownKeyToIndexMap[codeKey] == null) { + curFrameDownList.add(codeKey); + curFrameHeldDownList.add(codeKey); + curHeldDownKeyToIndexMap[codeKey] = curFrameHeldDownList.length - 1; + downKeyToFrameCountMap[codeKey] = frameCount; + } + break; + case "keyup": + const delIndex = curHeldDownKeyToIndexMap[codeKey]; + if (delIndex != null) { + curHeldDownKeyToIndexMap[codeKey] = null; + const swapCode = curFrameHeldDownList.deleteByIndex(delIndex); + swapCode && (curHeldDownKeyToIndexMap[swapCode] = delIndex); } - nativeEvents.length = 0; + curFrameUpList.add(codeKey); + upKeyToFrameCountMap[codeKey] = frameCount; + break; + default: + break; } + } + nativeEvents.length = 0; } + } - /** - * @internal - */ - _onBlur(): void { - this._curHeldDownKeyToIndexMap.length = 0; - this._nativeEvents.length = 0; - this._curFrameHeldDownList.length = 0; - this._curFrameDownList.length = 0; - this._curFrameUpList.length = 0; + /** + * @internal + */ + _onFocus(): void { + if (!this._hadListener) { + window.addEventListener("keydown", this._onKeyEvent); + window.addEventListener("keyup", this._onKeyEvent); + this._hadListener = true; } + } - /** - * @internal - */ - _destroy(): void { - window.removeEventListener('keydown', this._onKeyEvent); - window.removeEventListener('keyup', this._onKeyEvent); - this._curHeldDownKeyToIndexMap = null; - this._upKeyToFrameCountMap = null; - this._downKeyToFrameCountMap = null; - this._nativeEvents = null; + /** + * @internal + */ + _onBlur(): void { + if (this._hadListener) { + window.removeEventListener("keydown", this._onKeyEvent); + window.removeEventListener("keyup", this._onKeyEvent); + this._curHeldDownKeyToIndexMap.length = 0; + this._curFrameHeldDownList.length = 0; + this._curFrameDownList.length = 0; + this._curFrameUpList.length = 0; + this._nativeEvents.length = 0; + this._hadListener = false; + } + } - this._curFrameHeldDownList = null; - this._curFrameDownList = null; - this._curFrameUpList = null; + /** + * @internal + */ + _destroy(): void { + if (this._hadListener) { + window.removeEventListener("keydown", this._onKeyEvent); + window.removeEventListener("keyup", this._onKeyEvent); + this._hadListener = false; } -} \ No newline at end of file + this._curHeldDownKeyToIndexMap = null; + this._upKeyToFrameCountMap = null; + this._downKeyToFrameCountMap = null; + this._nativeEvents = null; + + this._curFrameHeldDownList = null; + this._curFrameDownList = null; + this._curFrameUpList = null; + } + + private _onKeyEvent(evt: KeyboardEvent): void { + this._nativeEvents.push(evt); + } +} diff --git a/packages/core/src/input/pointer/PointerManager.ts b/packages/core/src/input/pointer/PointerManager.ts index bdd6e9aefe..b453bf297e 100644 --- a/packages/core/src/input/pointer/PointerManager.ts +++ b/packages/core/src/input/pointer/PointerManager.ts @@ -1,17 +1,23 @@ import { Ray, Vector2 } from "@oasis-engine/math"; import { Canvas } from "../../Canvas"; +import { DisorderedArray } from "../../DisorderedArray"; import { Engine } from "../../Engine"; import { Entity } from "../../Entity"; import { CameraClearFlags } from "../../enums/CameraClearFlags"; -import { HitResult, PhysicsManager } from "../../physics"; +import { HitResult } from "../../physics"; import { PointerPhase } from "../enums/PointerPhase"; +import { PointerButton } from "../enums/PointerButton"; +import { IInput } from "../interface/IInput"; import { Pointer } from "./Pointer"; /** * Pointer Manager. * @internal */ -export class PointerManager { +export class PointerManager implements IInput { + /** Refer to the W3C standards.(https://www.w3.org/TR/uievents/#dom-mouseevent-buttons) */ + public static Buttons = [0x1, 0x4, 0x2, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400]; + private static _tempRay: Ray = new Ray(); private static _tempPoint: Vector2 = new Vector2(); private static _tempHitResult: HitResult = new HitResult(); @@ -19,18 +25,34 @@ export class PointerManager { /** @internal */ _pointers: Pointer[] = []; /** @internal */ + _movingDelta: Vector2 = new Vector2(); + /** @internal */ _multiPointerEnabled: boolean = true; + /** @internal */ + _buttons: number = 0x0; + /** @internal */ + _upMap: number[] = []; + /** @internal */ + _downMap: number[] = []; + /** @internal */ + _downList: DisorderedArray = new DisorderedArray(); + /** @internal */ + _upList: DisorderedArray = new DisorderedArray(); + /** @internal */ + _currentPosition: Vector2 = new Vector2(); + + private _currentPressedEntity: Entity; + private _currentEnteredEntity: Entity; private _engine: Engine; private _canvas: Canvas; + private _htmlCanvas: HTMLCanvasElement; private _nativeEvents: PointerEvent[] = []; private _pointerPool: Pointer[]; private _keyEventList: number[] = []; private _keyEventCount: number = 0; private _needOverallPointers: boolean = false; - private _currentPosition: Vector2 = new Vector2(); - private _currentPressedEntity: Entity; - private _currentEnteredEntity: Entity; + private _hadListener: boolean = false; /** * Create a PointerManager. @@ -40,11 +62,17 @@ export class PointerManager { constructor(engine: Engine, htmlCanvas: HTMLCanvasElement) { this._engine = engine; this._canvas = engine.canvas; + this._htmlCanvas = htmlCanvas; htmlCanvas.style.touchAction = "none"; - // prettier-ignore - htmlCanvas.onpointerdown = htmlCanvas.onpointerup = htmlCanvas.onpointerout = htmlCanvas.onpointermove = (evt: PointerEvent) => { - this._nativeEvents.push(evt); + htmlCanvas.oncontextmenu = (event: UIEvent) => { + return false; }; + const onPointerEvent = (this._onPointerEvent = this._onPointerEvent.bind(this)); + htmlCanvas.addEventListener("pointerdown", onPointerEvent); + htmlCanvas.addEventListener("pointerup", onPointerEvent); + htmlCanvas.addEventListener("pointerout", onPointerEvent); + htmlCanvas.addEventListener("pointermove", onPointerEvent); + this._hadListener = true; // If there are no compatibility issues, navigator.maxTouchPoints should be used here. this._pointerPool = new Array(11); } @@ -52,9 +80,12 @@ export class PointerManager { /** * @internal */ - _update(): void { + _update(frameCount: number): void { this._needOverallPointers && this._overallPointers(); - this._nativeEvents.length > 0 && this._handlePointerEvent(this._nativeEvents); + this._downList.length = 0; + this._upList.length = 0; + this._movingDelta.set(0, 0); + this._nativeEvents.length > 0 && this._handlePointerEvent(this._nativeEvents, frameCount); if (this._engine.physicsManager._initialized) { const rayCastEntity = this._pointerRayCast(); const { _keyEventCount: keyEventCount } = this; @@ -80,13 +111,53 @@ export class PointerManager { } } + /** + * @internal + */ + _onFocus(): void { + if (!this._hadListener) { + const { _htmlCanvas: htmlCanvas, _onPointerEvent: onPointerEvent } = this; + htmlCanvas.addEventListener("pointerdown", onPointerEvent); + htmlCanvas.addEventListener("pointerup", onPointerEvent); + htmlCanvas.addEventListener("pointerout", onPointerEvent); + htmlCanvas.addEventListener("pointermove", onPointerEvent); + this._hadListener = true; + } + } + + /** + * @internal + */ + _onBlur(): void { + if (this._hadListener) { + const { _htmlCanvas: htmlCanvas, _onPointerEvent: onPointerEvent } = this; + htmlCanvas.removeEventListener("pointerdown", onPointerEvent); + htmlCanvas.removeEventListener("pointerup", onPointerEvent); + htmlCanvas.removeEventListener("pointerout", onPointerEvent); + htmlCanvas.removeEventListener("pointermove", onPointerEvent); + this._nativeEvents.length = 0; + this._pointerPool.length = 0; + this._currentEnteredEntity = null; + this._currentPressedEntity = null; + this._downList.length = 0; + this._upList.length = 0; + this._hadListener = false; + } + } + /** * @internal */ _destroy(): void { // @ts-ignore - const htmlCanvas = this._canvas._webCanvas as HTMLCanvasElement; - htmlCanvas.onpointerdown = htmlCanvas.onpointerup = htmlCanvas.onpointerout = htmlCanvas.onpointermove = null; + if (this._hadListener) { + const { _htmlCanvas: htmlCanvas, _onPointerEvent: onPointerEvent } = this; + htmlCanvas.removeEventListener("pointerdown", onPointerEvent); + htmlCanvas.removeEventListener("pointerup", onPointerEvent); + htmlCanvas.removeEventListener("pointerout", onPointerEvent); + htmlCanvas.removeEventListener("pointermove", onPointerEvent); + this._hadListener = false; + } this._nativeEvents.length = 0; this._pointerPool.length = 0; this._pointers.length = 0; @@ -97,6 +168,10 @@ export class PointerManager { this._canvas = null; } + private _onPointerEvent(evt: PointerEvent) { + this._nativeEvents.push(evt); + } + private _overallPointers(): void { const { _pointers: pointers } = this; let deleteCount = 0; @@ -149,7 +224,8 @@ export class PointerManager { } private _removePointer(pointerIndex: number): void { - this._pointers[pointerIndex].phase = PointerPhase.Leave; + const leavePointer = this._pointers[pointerIndex]; + leavePointer.phase = PointerPhase.Leave; } private _updatePointer(pointerIndex: number, x: number, y: number, phase: PointerPhase): void { @@ -159,53 +235,67 @@ export class PointerManager { updatedPointer.phase = phase; } - private _handlePointerEvent(nativeEvents: PointerEvent[]): void { - const { _pointers: pointers, _keyEventList: keyEventList } = this; + private _handlePointerEvent(nativeEvents: PointerEvent[], frameCount: number): void { + const { + _pointers: pointers, + _keyEventList: keyEventList, + _upMap: upMap, + _downMap: downMap, + _upList: upList, + _downList: downList + } = this; let activePointerCount = pointers.length; const nativeEventsLen = nativeEvents.length; - for (let i = 0; i < nativeEventsLen; i++) { - const evt = nativeEvents[i]; - let pointerIndex = this._getIndexByPointerID(evt.pointerId); - switch (evt.type) { - case "pointerdown": - if (pointerIndex === -1) { - this._addPointer(evt.pointerId, evt.offsetX, evt.offsetY, PointerPhase.Down); - activePointerCount++; - } else { - this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Down); - } - activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Down); - break; - case "pointerup": - if (pointerIndex >= 0) { - this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Up); - activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Up); - } - break; - case "pointermove": - if (pointerIndex === -1) { - this._addPointer(evt.pointerId, evt.offsetX, evt.offsetY, PointerPhase.Move); - activePointerCount++; - } else { - this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Move); - } - break; - case "pointerout": - if (pointerIndex >= 0) { - this._removePointer(pointerIndex); - --activePointerCount === 0 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Leave); - this._needOverallPointers = true; - } - break; + if (nativeEventsLen > 0) { + for (let i = 0; i < nativeEventsLen; i++) { + const evt = nativeEvents[i]; + const pointerButton: PointerButton = evt.button | PointerButton.Primary; + const pointerIndex = this._getIndexByPointerID(evt.pointerId); + switch (evt.type) { + case "pointerdown": + if (pointerIndex === -1) { + this._addPointer(evt.pointerId, evt.offsetX, evt.offsetY, PointerPhase.Down); + activePointerCount++; + } else { + this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Down); + } + activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Down); + downList.add(pointerButton); + downMap[pointerButton] = frameCount; + break; + case "pointerup": + if (pointerIndex >= 0) { + this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Up); + activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Up); + } + upList.add(pointerButton); + upMap[pointerButton] = frameCount; + break; + case "pointermove": + if (pointerIndex === -1) { + this._addPointer(evt.pointerId, evt.offsetX, evt.offsetY, PointerPhase.Move); + activePointerCount++; + } else { + this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Move); + } + break; + case "pointerout": + if (pointerIndex >= 0) { + this._removePointer(pointerIndex); + --activePointerCount === 0 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Leave); + this._needOverallPointers = true; + } + break; + } } + this._buttons = nativeEvents[nativeEventsLen - 1].buttons; } const pointerCount = pointers.length; if (pointerCount > 0) { - const { _canvas: canvas, _currentPosition: currentPosition } = this; - // @ts-ignore - const pixelRatioWidth = canvas.width / (canvas._webCanvas as HTMLCanvasElement).clientWidth; - // @ts-ignore - const pixelRatioHeight = canvas.height / (canvas._webCanvas as HTMLCanvasElement).clientHeight; + const { _canvas: canvas, _currentPosition: currentPosition, _htmlCanvas: htmlCanvas } = this; + const { x: lastX, y: lastY } = currentPosition; + const pixelRatioWidth = canvas.width / htmlCanvas.clientWidth; + const pixelRatioHeight = canvas.height / htmlCanvas.clientHeight; if (activePointerCount === 0) { // Get the pointer coordinates when leaving, and use it to correctly dispatch the click event. const lastNativeEvent = nativeEvents[nativeEventsLen - 1]; @@ -223,6 +313,11 @@ export class PointerManager { } currentPosition.scale(1 / pointerCount); } + // Update pointer moving delta. + // Todo: Need to consider if the last coordinate is(0, 0). + if (lastX !== 0 || lastY !== 0) { + this._movingDelta.set(currentPosition.x - lastX, currentPosition.y - lastY); + } } nativeEvents.length = 0; } diff --git a/packages/core/src/input/wheel/WheelManager.ts b/packages/core/src/input/wheel/WheelManager.ts new file mode 100644 index 0000000000..363f936604 --- /dev/null +++ b/packages/core/src/input/wheel/WheelManager.ts @@ -0,0 +1,80 @@ +import { Vector3 } from "@oasis-engine/math"; +import { IInput } from "../interface/IInput"; + +/** + * Wheel Manager. + * @internal + */ +export class WheelManager implements IInput { + /** @internal */ + _delta: Vector3 = new Vector3(); + + private _nativeEvents: WheelEvent[] = []; + private _canvas: HTMLCanvasElement; + private _hadListener: boolean; + + /** + * Create a KeyboardManager. + */ + constructor(htmlCanvas: HTMLCanvasElement) { + this._onWheelEvent = this._onWheelEvent.bind(this); + htmlCanvas.addEventListener("wheel", this._onWheelEvent); + this._canvas = htmlCanvas; + this._hadListener = true; + } + + /** + * @internal + */ + _update(): void { + const { _delta: delta } = this; + delta.set(0, 0, 0); + const { _nativeEvents: nativeEvents } = this; + if (nativeEvents.length > 0) { + for (let i = nativeEvents.length - 1; i >= 0; i--) { + const evt = nativeEvents[i]; + delta.x += evt.deltaX; + delta.y += evt.deltaY; + delta.z += evt.deltaZ; + } + nativeEvents.length = 0; + } + } + + /** + * @internal + */ + _onFocus(): void { + if (!this._hadListener) { + this._canvas.addEventListener("wheel", this._onWheelEvent); + this._hadListener = true; + } + } + + /** + * @internal + */ + _onBlur(): void { + if (this._hadListener) { + this._canvas.removeEventListener("wheel", this._onWheelEvent); + this._nativeEvents.length = 0; + this._delta.set(0, 0, 0); + this._hadListener = false; + } + } + + /** + * @internal + */ + _destroy(): void { + if (this._hadListener) { + this._canvas.removeEventListener("wheel", this._onWheelEvent); + this._hadListener = false; + } + this._nativeEvents = null; + } + + private _onWheelEvent(evt: WheelEvent): void { + this._nativeEvents.push(evt); + } +} From 859771fdd7eb68bbb4a1e8d7bad573dd6a7248b7 Mon Sep 17 00:00:00 2001 From: yangfengzzz Date: Wed, 6 Jul 2022 14:22:57 +0800 Subject: [PATCH 25/33] Add basic physics joint component include `FixedJoint`, `SpringJoint`, `HingeJoint` (#853) * feat: basic physics joint --- packages/core/src/physics/PhysicsManager.ts | 2 +- .../core/src/physics/enums/HingeJointFlag.ts | 12 ++ packages/core/src/physics/enums/index.ts | 4 + packages/core/src/physics/index.ts | 7 +- packages/core/src/physics/joint/FixedJoint.ts | 18 +++ packages/core/src/physics/joint/HingeJoint.ts | 146 ++++++++++++++++++ packages/core/src/physics/joint/Joint.ts | 143 +++++++++++++++++ .../core/src/physics/joint/JointLimits.ts | 16 ++ packages/core/src/physics/joint/JointMotor.ts | 13 ++ .../core/src/physics/joint/SpringJoint.ts | 103 ++++++++++++ packages/core/src/physics/joint/index.ts | 7 + packages/design/src/physics/IPhysics.ts | 20 +++ packages/design/src/physics/index.ts | 1 + .../design/src/physics/joints/IFixedJoint.ts | 6 + .../design/src/physics/joints/IHingeJoint.ts | 69 +++++++++ packages/design/src/physics/joints/IJoint.ts | 48 ++++++ .../design/src/physics/joints/ISpringJoint.ts | 42 +++++ packages/design/src/physics/joints/index.ts | 4 + packages/physics-lite/src/LitePhysics.ts | 27 +++- .../physics-lite/src/LitePhysicsManager.ts | 2 +- packages/physics-physx/src/PhysXPhysics.ts | 30 +++- .../physics-physx/src/PhysXPhysicsManager.ts | 2 +- .../src/joint/PhysXFixedJoint.ts | 22 +++ .../src/joint/PhysXHingeJoint.ts | 108 +++++++++++++ .../physics-physx/src/joint/PhysXJoint.ts | 86 +++++++++++ .../src/joint/PhysXSpringJoint.ts | 71 +++++++++ 26 files changed, 999 insertions(+), 10 deletions(-) create mode 100644 packages/core/src/physics/enums/HingeJointFlag.ts create mode 100644 packages/core/src/physics/enums/index.ts create mode 100644 packages/core/src/physics/joint/FixedJoint.ts create mode 100644 packages/core/src/physics/joint/HingeJoint.ts create mode 100644 packages/core/src/physics/joint/Joint.ts create mode 100644 packages/core/src/physics/joint/JointLimits.ts create mode 100644 packages/core/src/physics/joint/JointMotor.ts create mode 100644 packages/core/src/physics/joint/SpringJoint.ts create mode 100644 packages/core/src/physics/joint/index.ts create mode 100644 packages/design/src/physics/joints/IFixedJoint.ts create mode 100644 packages/design/src/physics/joints/IHingeJoint.ts create mode 100644 packages/design/src/physics/joints/IJoint.ts create mode 100644 packages/design/src/physics/joints/ISpringJoint.ts create mode 100644 packages/design/src/physics/joints/index.ts create mode 100644 packages/physics-physx/src/joint/PhysXFixedJoint.ts create mode 100644 packages/physics-physx/src/joint/PhysXHingeJoint.ts create mode 100644 packages/physics-physx/src/joint/PhysXJoint.ts create mode 100644 packages/physics-physx/src/joint/PhysXSpringJoint.ts diff --git a/packages/core/src/physics/PhysicsManager.ts b/packages/core/src/physics/PhysicsManager.ts index caf90e98a4..8954e4b3c3 100644 --- a/packages/core/src/physics/PhysicsManager.ts +++ b/packages/core/src/physics/PhysicsManager.ts @@ -9,7 +9,7 @@ import { HitResult } from "./HitResult"; import { ColliderShape } from "./shape"; /** - * A physics manager is a collection of bodies and constraints which can interact. + * A physics manager is a collection of colliders and constraints which can interact. */ export class PhysicsManager { /** @internal */ diff --git a/packages/core/src/physics/enums/HingeJointFlag.ts b/packages/core/src/physics/enums/HingeJointFlag.ts new file mode 100644 index 0000000000..140038f249 --- /dev/null +++ b/packages/core/src/physics/enums/HingeJointFlag.ts @@ -0,0 +1,12 @@ +/** + * Flags specific to the Hinge Joint. + * @internal + */ +export enum HingeJointFlag { + /** enable the limit */ + LimitEnabled = 1, + /** enable the drive */ + DriveEnabled = 2, + /** if the existing velocity is beyond the drive velocity, do not add force */ + DriveFreeSpin = 4 +} diff --git a/packages/core/src/physics/enums/index.ts b/packages/core/src/physics/enums/index.ts new file mode 100644 index 0000000000..23b168e2c4 --- /dev/null +++ b/packages/core/src/physics/enums/index.ts @@ -0,0 +1,4 @@ +export * from "./PhysicsMaterialCombineMode"; +export * from "./ColliderShapeUpAxis"; +export * from "./ControllerCollisionFlag"; +export * from "./ControllerNonWalkableMode"; diff --git a/packages/core/src/physics/index.ts b/packages/core/src/physics/index.ts index 1bfd79ad2d..07f7e4bfde 100644 --- a/packages/core/src/physics/index.ts +++ b/packages/core/src/physics/index.ts @@ -1,13 +1,10 @@ export { HitResult } from "./HitResult"; -export { PhysicsMaterialCombineMode } from "./enums/PhysicsMaterialCombineMode"; -export { ColliderShapeUpAxis } from "./enums/ColliderShapeUpAxis"; -export { ControllerCollisionFlag } from "./enums/ControllerCollisionFlag"; -export { ControllerNonWalkableMode } from "./enums/ControllerNonWalkableMode"; - export { PhysicsManager } from "./PhysicsManager"; export { PhysicsMaterial } from "./PhysicsMaterial"; export { CharacterController } from "./CharacterController"; export * from "./shape"; +export * from "./joint"; +export * from "./enums"; export { Collider } from "./Collider"; export { StaticCollider } from "./StaticCollider"; diff --git a/packages/core/src/physics/joint/FixedJoint.ts b/packages/core/src/physics/joint/FixedJoint.ts new file mode 100644 index 0000000000..4b78b75f89 --- /dev/null +++ b/packages/core/src/physics/joint/FixedJoint.ts @@ -0,0 +1,18 @@ +import { Joint } from "./Joint"; +import { PhysicsManager } from "../PhysicsManager"; +import { Collider } from "../Collider"; + +/* + * A fixed joint permits no relative movement between two colliders. ie the colliders are glued together. + */ +export class FixedJoint extends Joint { + /** + * @override + * @internal + */ + _onAwake() { + const collider = this._collider; + collider.collider = this.entity.getComponent(Collider); + this._nativeJoint = PhysicsManager._nativePhysics.createFixedJoint(collider.collider._nativeCollider); + } +} diff --git a/packages/core/src/physics/joint/HingeJoint.ts b/packages/core/src/physics/joint/HingeJoint.ts new file mode 100644 index 0000000000..02de0cdae8 --- /dev/null +++ b/packages/core/src/physics/joint/HingeJoint.ts @@ -0,0 +1,146 @@ +import { Joint } from "./Joint"; +import { IHingeJoint } from "@oasis-engine/design"; +import { PhysicsManager } from "../PhysicsManager"; +import { HingeJointFlag } from "../enums/HingeJointFlag"; +import { Collider } from "../Collider"; +import { Vector3 } from "@oasis-engine/math"; +import { JointMotor } from "./JointMotor"; +import { JointLimits } from "./JointLimits"; + +/** + * A joint which behaves in a similar way to a hinge or axle. + */ +export class HingeJoint extends Joint { + private _axis: Vector3 = new Vector3(1, 0, 0); + private _hingeFlags: number = 0; + private _useSpring: boolean = false; + private _jointMonitor: JointMotor; + private _limits: JointLimits; + + /** + * The anchor rotation. + */ + get axis(): Vector3 { + return this._axis; + } + + set axis(value: Vector3) { + const axis = this._axis; + if (value !== axis) { + axis.copyFrom(value); + } + (this._nativeJoint).setAxis(axis); + } + + /** + * The swing offset. + */ + get swingOffset(): Vector3 { + return this._collider.localPosition; + } + + set swingOffset(value: Vector3) { + const swingOffset = this._collider.localPosition; + if (value !== swingOffset) { + swingOffset.copyFrom(value); + } + (this._nativeJoint).setSwingOffset(swingOffset); + } + + /** + * The current angle in degrees of the joint relative to its rest position. + */ + get angle(): number { + return (this._nativeJoint).getAngle(); + } + + /** + * The angular velocity of the joint in degrees per second. + */ + get velocity(): Readonly { + return (this._nativeJoint).getVelocity(); + } + + /** + * Enables the joint's limits. Disabled by default. + */ + get useLimits(): boolean { + return (this._hingeFlags & HingeJointFlag.LimitEnabled) == HingeJointFlag.LimitEnabled; + } + + set useLimits(value: boolean) { + if (value !== this.useLimits) { + this._hingeFlags |= HingeJointFlag.LimitEnabled; + } + (this._nativeJoint).setHingeJointFlag(HingeJointFlag.LimitEnabled, value); + } + + /** + * Enables the joint's motor. Disabled by default. + */ + get useMotor(): boolean { + return (this._hingeFlags & HingeJointFlag.DriveEnabled) == HingeJointFlag.DriveEnabled; + } + + set useMotor(value: boolean) { + if (value !== this.useMotor) { + this._hingeFlags |= HingeJointFlag.DriveEnabled; + } + (this._nativeJoint).setHingeJointFlag(HingeJointFlag.DriveEnabled, value); + } + + /** + * Enables the joint's spring. Disabled by default. + */ + get useSpring(): boolean { + return this._useSpring; + } + + set useSpring(value: boolean) { + this._useSpring = value; + this.limits = this._limits; + } + + /** + * The motor will apply a force up to a maximum force to achieve the target velocity in degrees per second. + */ + get motor(): JointMotor { + return this._jointMonitor; + } + + set motor(value: JointMotor) { + this._jointMonitor = value; + (this._nativeJoint).setDriveVelocity(value.targetVelocity); + (this._nativeJoint).setDriveForceLimit(value.forceLimit); + (this._nativeJoint).setDriveGearRatio(value.gearRation); + (this._nativeJoint).setHingeJointFlag(HingeJointFlag.DriveFreeSpin, value.freeSpin); + } + + /** + * Limit of angular rotation (in degrees) on the hinge joint. + */ + get limits(): JointLimits { + return this._limits; + } + + set limits(value: JointLimits) { + this._limits = value; + if (this.useSpring) { + (this._nativeJoint).setSoftLimit(value.min, value.max, value.stiffness, value.damping); + } else { + (this._nativeJoint).setHardLimit(value.min, value.max, value.contactDistance); + } + } + + /** + * @override + * @internal + */ + _onAwake() { + const { _connectedCollider: connectedCollider, _collider: collider } = this; + connectedCollider.localPosition = new Vector3(); + collider.localPosition = new Vector3(); + collider.collider = this.entity.getComponent(Collider); + this._nativeJoint = PhysicsManager._nativePhysics.createHingeJoint(collider.collider._nativeCollider); + } +} diff --git a/packages/core/src/physics/joint/Joint.ts b/packages/core/src/physics/joint/Joint.ts new file mode 100644 index 0000000000..f5c79903be --- /dev/null +++ b/packages/core/src/physics/joint/Joint.ts @@ -0,0 +1,143 @@ +import { IJoint } from "@oasis-engine/design"; +import { Vector3, Quaternion } from "@oasis-engine/math"; +import { Component } from "../../Component"; +import { Collider } from "../Collider"; +import { dependentComponents } from "../../ComponentsDependencies"; + +/** + * A base class providing common functionality for joints. + * @decorator `@dependentComponents(Collider)` + */ +@dependentComponents(Collider) +export class Joint extends Component { + protected _connectedCollider = new JointCollider(); + protected _collider = new JointCollider(); + protected _nativeJoint: IJoint; + private _force: number = 0; + private _torque: number = 0; + + /** + * The connected collider. + */ + get connectedCollider(): Collider { + return this._connectedCollider.collider; + } + + set connectedCollider(value: Collider) { + if (this._connectedCollider.collider !== value) { + this._connectedCollider.collider = value; + this._nativeJoint.setConnectedCollider(value._nativeCollider); + } + } + + /** + * The connected anchor position. + * @remarks If connectedCollider is set, this anchor is relative offset, or the anchor is world position. + */ + get connectedAnchor(): Vector3 { + return this._connectedCollider.localPosition; + } + + set connectedAnchor(value: Vector3) { + const connectedAnchor = this._connectedCollider.localPosition; + if (value !== connectedAnchor) { + connectedAnchor.copyFrom(value); + } + this._nativeJoint.setConnectedAnchor(value); + } + + /** + * The scale to apply to the inverse mass of collider 0 for resolving this constraint. + */ + get connectedMassScale(): number { + return this._connectedCollider.massScale; + } + + set connectedMassScale(value: number) { + if (value !== this._connectedCollider.massScale) { + this._connectedCollider.massScale = value; + this._nativeJoint.setConnectedMassScale(value); + } + } + + /** + * The scale to apply to the inverse inertia of collider0 for resolving this constraint. + */ + get connectedInertiaScale(): number { + return this._connectedCollider.inertiaScale; + } + + set connectedInertiaScale(value: number) { + if (value !== this._connectedCollider.inertiaScale) { + this._connectedCollider.inertiaScale = value; + this._nativeJoint.setConnectedInertiaScale(value); + } + } + + /** + * The scale to apply to the inverse mass of collider 1 for resolving this constraint. + */ + get massScale(): number { + return this._collider.massScale; + } + + set massScale(value: number) { + if (value !== this._collider.massScale) { + this._collider.massScale = value; + this._nativeJoint.setMassScale(value); + } + } + + /** + * The scale to apply to the inverse inertia of collider1 for resolving this constraint. + */ + get inertiaScale(): number { + return this._collider.inertiaScale; + } + + set inertiaScale(value: number) { + if (value !== this._collider.inertiaScale) { + this._collider.inertiaScale = value; + this._nativeJoint.setInertiaScale(value); + } + } + + /** + * The maximum force the joint can apply before breaking. + */ + get breakForce(): number { + return this._force; + } + + set breakForce(value: number) { + if (value !== this._force) { + this._force = value; + this._nativeJoint.setBreakForce(value); + } + } + + /** + * The maximum torque the joint can apply before breaking. + */ + get breakTorque(): number { + return this._torque; + } + + set breakTorque(value: number) { + if (value !== this._torque) { + this._torque = value; + this._nativeJoint.setBreakTorque(value); + } + } +} + +/** + * @internal + */ +class JointCollider { + collider: Collider = null; + localPosition: Vector3; + localRotation: Quaternion; + massScale: number = 0; + inertiaScale: number = 0; +} diff --git a/packages/core/src/physics/joint/JointLimits.ts b/packages/core/src/physics/joint/JointLimits.ts new file mode 100644 index 0000000000..55836e7d65 --- /dev/null +++ b/packages/core/src/physics/joint/JointLimits.ts @@ -0,0 +1,16 @@ +/** + * JointLimits is used to limit the joints angle. + */ +export class JointLimits { + /** The upper angular limit (in degrees) of the joint. */ + max: number = 0; + /** The lower angular limit (in degrees) of the joint. */ + min: number = 0; + /** Distance inside the limit value at which the limit will be considered to be active by the solver. */ + contactDistance: number = -1; + + /** The spring forces used to reach the target position. */ + stiffness: number = 0; + /** The damper force uses to dampen the spring. */ + damping: number = 0; +} diff --git a/packages/core/src/physics/joint/JointMotor.ts b/packages/core/src/physics/joint/JointMotor.ts new file mode 100644 index 0000000000..e225af4f95 --- /dev/null +++ b/packages/core/src/physics/joint/JointMotor.ts @@ -0,0 +1,13 @@ +/** + * The JointMotor is used to motorize a joint. + */ +export class JointMotor { + /** The motor will apply a force up to force to achieve targetVelocity. */ + targetVelocity: number = 0; + /** The force limit.*/ + forceLimit: number = Number.MAX_VALUE; + /** Gear ration for the motor */ + gearRation: number = 1.0; + /** If freeSpin is enabled the motor will only accelerate but never slow down. */ + freeSpin: boolean = false; +} diff --git a/packages/core/src/physics/joint/SpringJoint.ts b/packages/core/src/physics/joint/SpringJoint.ts new file mode 100644 index 0000000000..efee6abf4f --- /dev/null +++ b/packages/core/src/physics/joint/SpringJoint.ts @@ -0,0 +1,103 @@ +import { Joint } from "./Joint"; +import { ISpringJoint } from "@oasis-engine/design"; +import { PhysicsManager } from "../PhysicsManager"; +import { Collider } from "../Collider"; +import { Vector3 } from "@oasis-engine/math"; + +/** + * A joint that maintains an upper or lower bound (or both) on the distance between two points on different objects. + */ +export class SpringJoint extends Joint { + private _minDistance: number = 0; + private _maxDistance: number = 0; + private _tolerance: number = 0.25; + private _stiffness: number = 0; + private _damping: number = 0; + + /** + * The swing offset. + */ + get swingOffset(): Vector3 { + return this._collider.localPosition; + } + + set swingOffset(value: Vector3) { + const swingOffset = this._collider.localPosition; + if (value !== swingOffset) { + swingOffset.copyFrom(value); + } + (this._nativeJoint).setSwingOffset(value); + } + + /** + * The minimum distance. + */ + get minDistance(): number { + return this._minDistance; + } + + set minDistance(value: number) { + this._minDistance = value; + (this._nativeJoint).setMinDistance(value); + } + + /** + * The maximum distance. + */ + get maxDistance(): number { + return this._maxDistance; + } + + set maxDistance(value: number) { + this._maxDistance = value; + (this._nativeJoint).setMaxDistance(value); + } + + /** + * The distance beyond the allowed range at which the joint becomes active. + */ + get tolerance(): number { + return this._tolerance; + } + + set tolerance(value: number) { + this._tolerance = value; + (this._nativeJoint).setTolerance(value); + } + + /** + * The spring strength of the joint. + */ + get stiffness(): number { + return this._stiffness; + } + + set stiffness(value: number) { + this._stiffness = value; + (this._nativeJoint).setStiffness(value); + } + + /** + * The degree of damping of the joint spring of the joint. + */ + get damping(): number { + return this._damping; + } + + set damping(value: number) { + this._damping = value; + (this._nativeJoint).setDamping(value); + } + + /** + * @override + * @internal + */ + _onAwake() { + const { _connectedCollider: connectedCollider, _collider: collider } = this; + connectedCollider.localPosition = new Vector3(); + collider.localPosition = new Vector3(); + collider.collider = this.entity.getComponent(Collider); + this._nativeJoint = PhysicsManager._nativePhysics.createSpringJoint(collider.collider._nativeCollider); + } +} diff --git a/packages/core/src/physics/joint/index.ts b/packages/core/src/physics/joint/index.ts new file mode 100644 index 0000000000..2ffd2e3cb2 --- /dev/null +++ b/packages/core/src/physics/joint/index.ts @@ -0,0 +1,7 @@ +export { Joint } from "./Joint"; +export { FixedJoint } from "./FixedJoint"; +export { HingeJoint } from "./HingeJoint"; +export { SpringJoint } from "./SpringJoint"; + +export { JointLimits } from "./JointLimits"; +export { JointMotor } from "./JointMotor"; diff --git a/packages/design/src/physics/IPhysics.ts b/packages/design/src/physics/IPhysics.ts index d5badf7399..ad90d00da2 100644 --- a/packages/design/src/physics/IPhysics.ts +++ b/packages/design/src/physics/IPhysics.ts @@ -4,7 +4,9 @@ import { IBoxColliderShape, ISphereColliderShape, ICapsuleColliderShape, IPlaneC import { IDynamicCollider } from "./IDynamicCollider"; import { IStaticCollider } from "./IStaticCollider"; import { Quaternion, Vector3 } from "@oasis-engine/math"; +import { ICollider } from "./ICollider"; import { ICharacterController } from "./ICharacterController"; +import { IFixedJoint, IHingeJoint, ISpringJoint } from "./joints"; /** * The interface of physics creation. @@ -99,4 +101,22 @@ export interface IPhysics { height: number, material: IPhysicsMaterial ): ICapsuleColliderShape; + + /** + * Create fixed joint. + * @param collider - Affector of joint + */ + createFixedJoint(collider: ICollider): IFixedJoint; + + /** + * Create hinge joint. + * @param collider - Affector of joint + */ + createHingeJoint(collider: ICollider): IHingeJoint; + + /** + * Create spring joint + * @param collider - Affector of joint + */ + createSpringJoint(collider: ICollider): ISpringJoint; } diff --git a/packages/design/src/physics/index.ts b/packages/design/src/physics/index.ts index b73c672b12..334b731bc4 100644 --- a/packages/design/src/physics/index.ts +++ b/packages/design/src/physics/index.ts @@ -6,3 +6,4 @@ export type { IDynamicCollider } from "./IDynamicCollider"; export type { IPhysicsMaterial } from "./IPhysicsMaterial"; export type { ICharacterController } from "./ICharacterController"; export * from "./shape/index"; +export * from "./joints/index"; diff --git a/packages/design/src/physics/joints/IFixedJoint.ts b/packages/design/src/physics/joints/IFixedJoint.ts new file mode 100644 index 0000000000..d35cafb171 --- /dev/null +++ b/packages/design/src/physics/joints/IFixedJoint.ts @@ -0,0 +1,6 @@ +import { IJoint } from "./IJoint"; + +/* + A fixed joint permits no relative movement between two colliders. ie the colliders are glued together. + */ +export interface IFixedJoint extends IJoint {} diff --git a/packages/design/src/physics/joints/IHingeJoint.ts b/packages/design/src/physics/joints/IHingeJoint.ts new file mode 100644 index 0000000000..2e08154f12 --- /dev/null +++ b/packages/design/src/physics/joints/IHingeJoint.ts @@ -0,0 +1,69 @@ +import { IJoint } from "./IJoint"; +import { Vector3 } from "@oasis-engine/math"; + +/** + * A joint which behaves in a similar way to a hinge or axle. + */ +export interface IHingeJoint extends IJoint { + /** + * The anchor rotation. + */ + setAxis(value: Vector3): void; + + /** + * The swing offset. + */ + setSwingOffset(value: Vector3): void; + + /** + * The current angle in degrees of the joint relative to its rest position. + */ + getAngle(): number; + + /** + * The angular velocity of the joint in degrees per second. + */ + getVelocity(): Readonly; + + /** + * Set a cone hard limit. + * @param lowerLimit The lower angle of the limit + * @param upperLimit The upper angle of the limit + * @param contactDist The distance from the limit at which it becomes active. Default is the lesser of 0.1 radians, and 0.49 * the lower of the limit angles + */ + setHardLimit(lowerLimit: number, upperLimit: number, contactDist: number): void; + + /** + * Set a cone soft limit. + * @param lowerLimit The lower angle of the limit + * @param upperLimit The upper angle of the limit + * @param stiffness the spring strength of the drive + * @param damping the damping strength of the drive + */ + setSoftLimit(lowerLimit: number, upperLimit: number, stiffness: number, damping: number): void; + + /** + * set the target velocity for the drive model. + * @param velocity the drive target velocity + */ + setDriveVelocity(velocity: number): void; + + /** + * sets the maximum torque the drive can exert. + * @param limit the maximum torque + */ + setDriveForceLimit(limit: number): void; + + /** + * sets the gear ratio for the drive. + * @param ratio the gear ratio + */ + setDriveGearRatio(ratio: number): void; + + /** + * sets a single flag specific to a Hinge Joint. + * @param flag The flag to set or clear. + * @param value the value to which to set the flag + */ + setHingeJointFlag(flag: number, value: boolean): void; +} diff --git a/packages/design/src/physics/joints/IJoint.ts b/packages/design/src/physics/joints/IJoint.ts new file mode 100644 index 0000000000..d88a551e9a --- /dev/null +++ b/packages/design/src/physics/joints/IJoint.ts @@ -0,0 +1,48 @@ +import { Vector3 } from "@oasis-engine/math"; +import { ICollider } from "../ICollider"; + +/** + * a base interface providing common functionality for joints. + */ +export interface IJoint { + /** + * The connected collider. + */ + setConnectedCollider(value: ICollider): void; + + /** + * The connected anchor position. + * @remarks If connectedCollider is set, this anchor is relative offset, or the anchor is world position. + */ + setConnectedAnchor(value: Vector3): void; + + /** + * The scale to apply to the inverse mass of collider 0 for resolving this constraint. + */ + setConnectedMassScale(value: number): void; + + /** + * The scale to apply to the inverse inertia of collider0 for resolving this constraint. + */ + setConnectedInertiaScale(value: number): void; + + /** + * The scale to apply to the inverse mass of collider 1 for resolving this constraint. + */ + setMassScale(value: number): void; + + /** + * The scale to apply to the inverse inertia of collider1 for resolving this constraint. + */ + setInertiaScale(value: number): void; + + /** + * The maximum force the joint can apply before breaking. + */ + setBreakForce(value: number): void; + + /** + * The maximum torque the joint can apply before breaking. + */ + setBreakTorque(value: number): void; +} diff --git a/packages/design/src/physics/joints/ISpringJoint.ts b/packages/design/src/physics/joints/ISpringJoint.ts new file mode 100644 index 0000000000..e8f4ecd469 --- /dev/null +++ b/packages/design/src/physics/joints/ISpringJoint.ts @@ -0,0 +1,42 @@ +import { IJoint } from "./IJoint"; +import { Vector3 } from "@oasis-engine/math"; + +/** + * a joint that maintains an upper or lower bound (or both) on the distance between two points on different objects + */ +export interface ISpringJoint extends IJoint { + /** + * The swing offset. + */ + setSwingOffset(value: Vector3): void; + + /** + * Set the allowed minimum distance for the joint. + * @param distance the minimum distance + */ + setMinDistance(distance: number): void; + + /** + * Set the allowed maximum distance for the joint. + * @param distance the maximum distance + */ + setMaxDistance(distance: number): void; + + /** + * Set the error tolerance of the joint. + * @param tolerance the distance beyond the allowed range at which the joint becomes active + */ + setTolerance(tolerance: number): void; + + /** + * Set the strength of the joint spring. + * @param stiffness the spring strength of the joint + */ + setStiffness(stiffness: number): void; + + /** + * Set the damping of the joint spring. + * @param damping the degree of damping of the joint spring of the joint + */ + setDamping(damping: number): void; +} diff --git a/packages/design/src/physics/joints/index.ts b/packages/design/src/physics/joints/index.ts new file mode 100644 index 0000000000..6a0b39f4e6 --- /dev/null +++ b/packages/design/src/physics/joints/index.ts @@ -0,0 +1,4 @@ +export type { IJoint } from "./IJoint"; +export type { IFixedJoint } from "./IFixedJoint"; +export type { IHingeJoint } from "./IHingeJoint"; +export type { ISpringJoint } from "./ISpringJoint"; diff --git a/packages/physics-lite/src/LitePhysics.ts b/packages/physics-lite/src/LitePhysics.ts index 858037c8ef..6cc92369b3 100644 --- a/packages/physics-lite/src/LitePhysics.ts +++ b/packages/physics-lite/src/LitePhysics.ts @@ -8,7 +8,10 @@ import { IPhysicsMaterial, IPlaneColliderShape, ISphereColliderShape, - IStaticCollider + IStaticCollider, + IFixedJoint, + IHingeJoint, + ISpringJoint, } from "@oasis-engine/design"; import { Quaternion, Vector3 } from "oasis-engine"; import { LiteDynamicCollider } from "./LiteDynamicCollider"; @@ -17,6 +20,7 @@ import { LitePhysicsMaterial } from "./LitePhysicsMaterial"; import { LiteStaticCollider } from "./LiteStaticCollider"; import { LiteBoxColliderShape } from "./shape/LiteBoxColliderShape"; import { LiteSphereColliderShape } from "./shape/LiteSphereColliderShape"; +import { LiteCollider } from "./LiteCollider"; import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; @StaticInterfaceImplement() @@ -112,4 +116,25 @@ export class LitePhysics { ): ICapsuleColliderShape { throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; } + + /** + * {@inheritDoc IPhysics.createFixedJoint } + */ + static createFixedJoint(collider: LiteCollider): IFixedJoint { + throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; + } + + /** + * {@inheritDoc IPhysics.createHingeJoint } + */ + static createHingeJoint(collider: LiteCollider): IHingeJoint { + throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; + } + + /** + * {@inheritDoc IPhysics.createSpringJoint } + */ + static createSpringJoint(collider: LiteCollider): ISpringJoint { + throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; + } } diff --git a/packages/physics-lite/src/LitePhysicsManager.ts b/packages/physics-lite/src/LitePhysicsManager.ts index c7e9d36488..1093086002 100644 --- a/packages/physics-lite/src/LitePhysicsManager.ts +++ b/packages/physics-lite/src/LitePhysicsManager.ts @@ -8,7 +8,7 @@ import { LiteColliderShape } from "./shape/LiteColliderShape"; import { LiteSphereColliderShape } from "./shape/LiteSphereColliderShape"; /** - * A manager is a collection of bodies and constraints which can interact. + * A manager is a collection of colliders and constraints which can interact. */ export class LitePhysicsManager implements IPhysicsManager { private static _tempSphere: BoundingSphere = new BoundingSphere(); diff --git a/packages/physics-physx/src/PhysXPhysics.ts b/packages/physics-physx/src/PhysXPhysics.ts index f5042a6e8c..8665354e7e 100644 --- a/packages/physics-physx/src/PhysXPhysics.ts +++ b/packages/physics-physx/src/PhysXPhysics.ts @@ -8,7 +8,10 @@ import { IPhysicsMaterial, IPlaneColliderShape, ISphereColliderShape, - IStaticCollider + IStaticCollider, + IFixedJoint, + IHingeJoint, + ISpringJoint } from "@oasis-engine/design"; import { Quaternion, Vector3 } from "oasis-engine"; import { PhysXRuntimeMode } from "./enum/PhysXRuntimeMode"; @@ -21,7 +24,11 @@ import { PhysXBoxColliderShape } from "./shape/PhysXBoxColliderShape"; import { PhysXCapsuleColliderShape } from "./shape/PhysXCapsuleColliderShape"; import { PhysXPlaneColliderShape } from "./shape/PhysXPlaneColliderShape"; import { PhysXSphereColliderShape } from "./shape/PhysXSphereColliderShape"; +import { PhysXFixedJoint } from "./joint/PhysXFixedJoint"; +import { PhysXHingeJoint } from "./joint/PhysXHingeJoint"; +import { PhysXSpringJoint } from "./joint/PhysXSpringJoint"; import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; +import { PhysXCollider } from "./PhysXCollider"; /** * PhysX object creation. @@ -186,6 +193,27 @@ export class PhysXPhysics { return new PhysXCapsuleColliderShape(uniqueID, radius, height, material); } + /** + * {@inheritDoc IPhysics.createFixedJoint } + */ + static createFixedJoint(collider: PhysXCollider): IFixedJoint { + return new PhysXFixedJoint(collider); + } + + /** + * {@inheritDoc IPhysics.createHingeJoint } + */ + static createHingeJoint(collider: PhysXCollider): IHingeJoint { + return new PhysXHingeJoint(collider); + } + + /** + * {@inheritDoc IPhysics.createSpringJoint } + */ + static createSpringJoint(collider: PhysXCollider): ISpringJoint { + return new PhysXSpringJoint(collider); + } + private static _init(PHYSX: any): void { PhysXPhysics._physX = PHYSX; const version = PhysXPhysics._physX.PX_PHYSICS_VERSION; diff --git a/packages/physics-physx/src/PhysXPhysicsManager.ts b/packages/physics-physx/src/PhysXPhysicsManager.ts index 8ca699c03d..92c17163d5 100644 --- a/packages/physics-physx/src/PhysXPhysicsManager.ts +++ b/packages/physics-physx/src/PhysXPhysicsManager.ts @@ -7,7 +7,7 @@ import { PhysXPhysics } from "./PhysXPhysics"; import { PhysXColliderShape } from "./shape/PhysXColliderShape"; /** - * A manager is a collection of bodies and constraints which can interact. + * A manager is a collection of colliders and constraints which can interact. */ export class PhysXPhysicsManager implements IPhysicsManager { /** @internal */ diff --git a/packages/physics-physx/src/joint/PhysXFixedJoint.ts b/packages/physics-physx/src/joint/PhysXFixedJoint.ts new file mode 100644 index 0000000000..ad9c17a452 --- /dev/null +++ b/packages/physics-physx/src/joint/PhysXFixedJoint.ts @@ -0,0 +1,22 @@ +import { PhysXJoint } from "./PhysXJoint"; +import { IFixedJoint } from "@oasis-engine/design"; +import { PhysXCollider } from "../PhysXCollider"; +import { PhysXPhysics } from "../PhysXPhysics"; + +/** + * A fixed joint permits no relative movement between two colliders. ie the bodies are glued together. + */ +export class PhysXFixedJoint extends PhysXJoint implements IFixedJoint { + constructor(collider: PhysXCollider) { + super(); + this._collider = collider; + this._pxJoint = PhysXPhysics._pxPhysics.createFixedJoint( + null, + PhysXJoint._tempVector, + PhysXJoint._tempQuat, + collider._pxActor, + PhysXJoint._tempVector, + PhysXJoint._tempQuat + ); + } +} diff --git a/packages/physics-physx/src/joint/PhysXHingeJoint.ts b/packages/physics-physx/src/joint/PhysXHingeJoint.ts new file mode 100644 index 0000000000..33903addc7 --- /dev/null +++ b/packages/physics-physx/src/joint/PhysXHingeJoint.ts @@ -0,0 +1,108 @@ +import { PhysXCollider } from "../PhysXCollider"; +import { PhysXJoint } from "./PhysXJoint"; +import { IHingeJoint } from "@oasis-engine/design"; +import { PhysXPhysics } from "../PhysXPhysics"; +import { Quaternion, Vector3 } from "oasis-engine"; + +/** + * A joint which behaves in a similar way to a hinge or axle. + */ +export class PhysXHingeJoint extends PhysXJoint implements IHingeJoint { + private _axisRotationQuaternion = new Quaternion(); + private _swingOffset = new Vector3(); + private _velocity = new Vector3(); + + constructor(collider: PhysXCollider) { + super(); + this._collider = collider; + this._pxJoint = PhysXPhysics._pxPhysics.createRevoluteJoint( + null, + PhysXJoint._tempVector, + PhysXJoint._tempQuat, + collider._pxActor, + PhysXJoint._tempVector, + PhysXJoint._tempQuat + ); + } + + /** + * {@inheritDoc IHingeJoint.setAxis } + */ + setAxis(value: Vector3): void { + const tempVector = PhysXJoint._tempVector; + const axisRotationQuaternion = this._axisRotationQuaternion; + tempVector.set(1, 0, 0); + value.normalize(); + const angle = Math.acos(Vector3.dot(tempVector, value)); + Vector3.cross(tempVector, value, tempVector); + Quaternion.rotationAxisAngle(tempVector, angle, axisRotationQuaternion); + + this._setLocalPose(0, this._swingOffset, axisRotationQuaternion); + } + + /** + * {@inheritDoc IHingeJoint.setSwingOffset } + */ + setSwingOffset(value: Vector3): void { + this._swingOffset.copyFrom(value); + this._setLocalPose(1, this._swingOffset, this._axisRotationQuaternion); + } + + /** + * {@inheritDoc IHingeJoint.getAngle } + */ + getAngle(): number { + return this._pxJoint.getAngle(); + } + + /** + * {@inheritDoc IHingeJoint.getVelocity } + */ + getVelocity(): Readonly { + const velocity = this._velocity; + velocity.copyFrom(this._pxJoint.getVelocity()); + return velocity; + } + + /** + * {@inheritDoc IHingeJoint.setHardLimitCone } + */ + setHardLimit(lowerLimit: number, upperLimit: number, contactDist: number): void { + this._pxJoint.setHardLimit(lowerLimit, upperLimit, contactDist); + } + + /** + * {@inheritDoc IHingeJoint.setHardLimitCone } + */ + setSoftLimit(lowerLimit: number, upperLimit: number, stiffness: number, damping: number): void { + this._pxJoint.setSoftLimit(lowerLimit, upperLimit, stiffness, damping); + } + + /** + * {@inheritDoc IHingeJoint.setDriveVelocity } + */ + setDriveVelocity(velocity: number): void { + this._pxJoint.setDriveVelocity(velocity); + } + + /** + * {@inheritDoc IHingeJoint.setDriveForceLimit } + */ + setDriveForceLimit(limit: number): void { + this._pxJoint.setDriveForceLimit(limit); + } + + /** + * {@inheritDoc IHingeJoint.setDriveGearRatio } + */ + setDriveGearRatio(ratio: number): void { + this._pxJoint.setDriveGearRatio(ratio); + } + + /** + * {@inheritDoc IHingeJoint.setHingeJointFlag } + */ + setHingeJointFlag(flag: number, value: boolean): void { + this._pxJoint.setRevoluteJointFlag(flag, value); + } +} diff --git a/packages/physics-physx/src/joint/PhysXJoint.ts b/packages/physics-physx/src/joint/PhysXJoint.ts new file mode 100644 index 0000000000..b54a1c72aa --- /dev/null +++ b/packages/physics-physx/src/joint/PhysXJoint.ts @@ -0,0 +1,86 @@ +import { IJoint } from "@oasis-engine/design"; +import { PhysXCollider } from "../PhysXCollider"; +import { Quaternion, Vector3 } from "oasis-engine"; + +/** + * a base interface providing common functionality for PhysX joints + */ +export class PhysXJoint implements IJoint { + protected static _tempVector = new Vector3(1, 0, 0); + protected static _tempQuat = new Quaternion(); + + protected _pxJoint: any; + protected _collider: PhysXCollider; + private _connectedAnchor = new Vector3(); + private _breakForce: number = Number.MAX_VALUE; + private _breakTorque: number = Number.MAX_VALUE; + + /** + * {@inheritDoc IJoint.setConnectedCollider } + */ + setConnectedCollider(value: PhysXCollider): void { + this._pxJoint.setActors(value?._pxActor || null, this._collider?._pxActor || null); + } + + /** + * {@inheritDoc IJoint.setConnectedAnchor } + */ + setConnectedAnchor(value: Vector3): void { + this._connectedAnchor.copyFrom(value); + this._setLocalPose(0, value, PhysXJoint._tempQuat); + } + + /** + * {@inheritDoc IJoint.setConnectedMassScale } + */ + setConnectedMassScale(value: number): void { + this._pxJoint.setInvMassScale0(1 / value); + } + + /** + * {@inheritDoc IJoint.setConnectedInertiaScale } + */ + setConnectedInertiaScale(value: number): void { + this._pxJoint.setInvInertiaScale0(1 / value); + } + + /** + * {@inheritDoc IJoint.setMassScale } + */ + setMassScale(value: number): void { + this._pxJoint.setInvMassScale1(1 / value); + } + + /** + * {@inheritDoc IJoint.setInertiaScale } + */ + setInertiaScale(value: number): void { + this._pxJoint.setInvInertiaScale1(1 / value); + } + + /** + * {@inheritDoc IJoint.setBreakForce } + */ + setBreakForce(value: number): void { + this._breakForce = value; + this._pxJoint.setBreakForce(this._breakForce, this._breakTorque); + } + + /** + * {@inheritDoc IJoint.setBreakTorque } + */ + setBreakTorque(value: number): void { + this._breakTorque = value; + this._pxJoint.setBreakForce(this._breakForce, this._breakTorque); + } + + /** + * Set the joint local pose for an actor. + * @param actor 0 for the first actor, 1 for the second actor. + * @param position the local position for the actor this joint + * @param rotation the local rotation for the actor this joint + */ + protected _setLocalPose(actor: number, position: Vector3, rotation: Quaternion): void { + this._pxJoint.setLocalPose(actor, position, rotation); + } +} diff --git a/packages/physics-physx/src/joint/PhysXSpringJoint.ts b/packages/physics-physx/src/joint/PhysXSpringJoint.ts new file mode 100644 index 0000000000..e09ae9a525 --- /dev/null +++ b/packages/physics-physx/src/joint/PhysXSpringJoint.ts @@ -0,0 +1,71 @@ +import { PhysXPhysics } from "../PhysXPhysics"; +import { PhysXJoint } from "./PhysXJoint"; +import { ISpringJoint } from "@oasis-engine/design"; +import { PhysXCollider } from "../PhysXCollider"; +import { Vector3 } from "oasis-engine"; + +/** + * a joint that maintains an upper or lower bound (or both) on the distance between two points on different objects + */ +export class PhysXSpringJoint extends PhysXJoint implements ISpringJoint { + private _swingOffset = new Vector3(); + + constructor(collider: PhysXCollider) { + super(); + this._collider = collider; + this._pxJoint = PhysXPhysics._pxPhysics.createDistanceJoint( + null, + PhysXJoint._tempVector, + PhysXJoint._tempQuat, + collider._pxActor, + PhysXJoint._tempVector, + PhysXJoint._tempQuat + ); + this._pxJoint.setDistanceJointFlag(1, true); // enable max distance; + this._pxJoint.setDistanceJointFlag(2, true); // enable min distance; + this._pxJoint.setDistanceJointFlag(4, true); // enable spring; + } + + /** + * {@inheritDoc ISpringJoint.setSwingOffset } + */ + setSwingOffset(value: Vector3): void { + this._swingOffset.copyFrom(value); + this._setLocalPose(1, value, PhysXJoint._tempQuat); + } + + /** + * {@inheritDoc ISpringJoint.setMinDistance } + */ + setMinDistance(distance: number): void { + this._pxJoint.setMinDistance(distance); + } + + /** + * {@inheritDoc ISpringJoint.setMaxDistance } + */ + setMaxDistance(distance: number): void { + this._pxJoint.setMaxDistance(distance); + } + + /** + * {@inheritDoc ISpringJoint.setTolerance } + */ + setTolerance(tolerance: number): void { + this._pxJoint.setTolerance(tolerance); + } + + /** + * {@inheritDoc ISpringJoint.setStiffness } + */ + setStiffness(stiffness: number): void { + this._pxJoint.setStiffness(stiffness); + } + + /** + * {@inheritDoc ISpringJoint.setDamping } + */ + setDamping(damping: number): void { + this._pxJoint.setDamping(damping); + } +} From f589545d905a2130cf1df753c8c6196f831073dd Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 8 Jul 2022 16:46:30 +0800 Subject: [PATCH 26/33] Use char cache mode for TextRenderer (#837) * feat(text): use char cache mode for TextRenderer --- packages/core/src/2d/assembler/IAssembler.ts | 7 +- .../src/2d/assembler/SimpleSpriteAssembler.ts | 2 +- .../src/2d/assembler/SlicedSpriteAssembler.ts | 2 +- .../2d/assembler/StaticInterfaceImplement.ts | 12 +- packages/core/src/2d/atlas/FontAtlas.ts | 93 +++ .../src/2d/dynamic-atlas/DynamicTextAtlas.ts | 95 --- .../dynamic-atlas/DynamicTextAtlasManager.ts | 126 ---- packages/core/src/2d/sprite/Sprite.ts | 15 +- packages/core/src/2d/text/CharInfo.ts | 19 + packages/core/src/2d/text/CharRenderData.ts | 21 + .../core/src/2d/text/CharRenderDataPool.ts | 26 + packages/core/src/2d/text/Font.ts | 94 ++- packages/core/src/2d/text/TextRenderer.ts | 392 +++++++----- packages/core/src/2d/text/TextUtils.ts | 577 ++++++++---------- packages/core/src/Engine.ts | 5 +- .../core/src/RenderPipeline/SpriteBatcher.ts | 7 +- .../core/src/RenderPipeline/SpriteElement.ts | 5 +- packages/core/src/Transform.ts | 8 + 18 files changed, 794 insertions(+), 712 deletions(-) create mode 100644 packages/core/src/2d/atlas/FontAtlas.ts delete mode 100644 packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts delete mode 100644 packages/core/src/2d/dynamic-atlas/DynamicTextAtlasManager.ts create mode 100644 packages/core/src/2d/text/CharInfo.ts create mode 100644 packages/core/src/2d/text/CharRenderData.ts create mode 100644 packages/core/src/2d/text/CharRenderDataPool.ts diff --git a/packages/core/src/2d/assembler/IAssembler.ts b/packages/core/src/2d/assembler/IAssembler.ts index 84a71f0412..22a571fc1d 100644 --- a/packages/core/src/2d/assembler/IAssembler.ts +++ b/packages/core/src/2d/assembler/IAssembler.ts @@ -1,8 +1,11 @@ import { Renderer } from "../../Renderer"; +/** + * @internal + */ export interface IAssembler { resetData(renderer: Renderer): void; updateData(renderer: Renderer): void; - updatePositions(renderer: Renderer): void; - updateUVs(renderer: Renderer): void; + updatePositions?(renderer: Renderer): void; + updateUVs?(renderer: Renderer): void; } diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index aa7cf342e6..740e14cd1e 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -4,10 +4,10 @@ import { SpriteRenderer } from "../sprite/SpriteRenderer"; import { IAssembler } from "./IAssembler"; import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; -@StaticInterfaceImplement() /** * @internal */ +@StaticInterfaceImplement() export class SimpleSpriteAssembler { static _rectangleTriangles: number[] = [0, 1, 2, 2, 1, 3]; static _worldMatrix: Matrix = new Matrix(); diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts index 7d6b95d0ad..2b8e45ac9a 100644 --- a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts @@ -4,10 +4,10 @@ import { SpriteRenderer } from "../sprite/SpriteRenderer"; import { IAssembler } from "./IAssembler"; import { StaticInterfaceImplement } from "./StaticInterfaceImplement"; -@StaticInterfaceImplement() /** * @internal */ +@StaticInterfaceImplement() export class SlicedSpriteAssembler { static _worldMatrix: Matrix = new Matrix(); static resetData(renderer: SpriteRenderer | SpriteMask): void { diff --git a/packages/core/src/2d/assembler/StaticInterfaceImplement.ts b/packages/core/src/2d/assembler/StaticInterfaceImplement.ts index 855b817e42..0741e6897b 100644 --- a/packages/core/src/2d/assembler/StaticInterfaceImplement.ts +++ b/packages/core/src/2d/assembler/StaticInterfaceImplement.ts @@ -2,9 +2,9 @@ * Static interface implement decorator. * https://stackoverflow.com/questions/13955157/how-to-define-static-property-in-typescript-interface */ - export function StaticInterfaceImplement() { - return (constructor: U) => { - constructor; - }; - } - \ No newline at end of file +export function StaticInterfaceImplement() { + return (constructor: U) => { + constructor; + }; +} + diff --git a/packages/core/src/2d/atlas/FontAtlas.ts b/packages/core/src/2d/atlas/FontAtlas.ts new file mode 100644 index 0000000000..5b5e37241c --- /dev/null +++ b/packages/core/src/2d/atlas/FontAtlas.ts @@ -0,0 +1,93 @@ +import { RefObject } from "../../asset/RefObject"; +import { Engine } from "../../Engine"; +import { Texture2D } from "../../texture/Texture2D"; +import { CharInfo } from "../text/CharInfo"; + +/** + * @internal + * Font Atlas. + */ +export class FontAtlas extends RefObject { + private _charInfoMap: Record = {}; + private _texture: Texture2D; + private _space: number = 1; + private _curX: number = 1; + private _curY: number = 1; + private _nextY: number = 1; + + get texture(): Texture2D { + return this._texture; + } + + set texture(value: Texture2D) { + this._texture = value; + } + + /** + * Constructor a FontAtlas. + * @param engine - Engine to which the FontAtlas belongs + */ + constructor(engine: Engine) { + super(engine); + } + + /** + * @override + */ + _onDestroy(): void { + this._texture.destroy(); + this._texture = null; + this._charInfoMap = {}; + } + + uploadCharTexture(charInfo: CharInfo, imageSource: TexImageSource | OffscreenCanvas): boolean { + const { w: width, h: height } = charInfo; + const { _space: space, texture } = this; + const textureSize = texture.width; + const offsetWidth = width + space; + const offsetHeight = height + space; + if ((1 + offsetWidth) >= textureSize || (1 + offsetHeight) >= textureSize) { + throw Error("The char fontSize is too large."); + } + + const endX = this._curX + offsetWidth; + if (endX >= textureSize) { + this._curX = space; + this._curY = this._nextY + space; + } + const endY = this._curY + offsetHeight; + if (endY > this._nextY) { + this._nextY = endY; + } + if (endY >= textureSize) { + return false; + } + + if (width > 0 && height > 0) { + texture.setImageSource(imageSource, 0, false, false, this._curX, this._curY); + texture.generateMipmaps(); + } + + const textureSizeReciprocal = 1.0 / textureSize; + const x = this._curX; + const y = this._curY; + const w = width; + const h = height; + charInfo.x = x; + charInfo.y = y; + charInfo.u0 = x * textureSizeReciprocal; + charInfo.u1 = (x + w) * textureSizeReciprocal; + charInfo.v0 = y * textureSizeReciprocal; + charInfo.v1 = (y + h) * textureSizeReciprocal; + this._curX += offsetWidth + space; + return true; + } + + addCharInfo(char: string, charInfo: CharInfo) { + this._charInfoMap[char.charCodeAt(0)] = charInfo; + } + + getCharInfo(char: string): CharInfo { + return this._charInfoMap[char.charCodeAt(0)]; + } +} diff --git a/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts b/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts deleted file mode 100644 index 89d91ee39b..0000000000 --- a/packages/core/src/2d/dynamic-atlas/DynamicTextAtlas.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Rect } from "@oasis-engine/math"; -import { Engine } from "../../Engine"; -import { Texture2D } from "../../texture/Texture2D"; -import { Sprite } from "../sprite/Sprite"; - -/** - * Dynamic atlas for text. - */ -export class DynamicTextAtlas { - private static _region: Rect = new Rect(); - - private _texture: Texture2D; - private _width: number; - private _height: number; - - private _space: number = 1; - private _curX: number = 1; - private _curY: number = 1; - private _nextY: number = 1; - - private _sprites: Record = {}; - - constructor(engine: Engine, width: number, height: number) { - this._width = width; - this._height = height; - this._texture = new Texture2D(engine, width, height); - this._texture._addRefCount(1); - } - - /** - * Destroy atlas, it will release the texture. - */ - public destroy() { - this._sprites = {}; - this._texture.destroy(true); - } - - /** - * Add a sprite. - * @param sprite - the sprite to add - * @param imageSource - The source of texture - * @returns true if add sprite success, otherwise false - */ - public addSprite(sprite: Sprite, imageSource: TexImageSource | OffscreenCanvas): boolean { - const { _space: space, _texture: texture } = this; - const { width, height } = imageSource; - - const endX = this._curX + width + space; - if (endX >= this._width) { - this._curX = space; - this._curY = this._nextY + space; - } - - const endY = this._curY + height + space; - if (endY > this._nextY) { - this._nextY = endY; - } - - if (this._nextY >= this._height) { - return false; - } - - texture.setImageSource(imageSource, 0, false, false, this._curX, this._curY); - texture.generateMipmaps(); - - const { _width, _height } = this; - const region = DynamicTextAtlas._region; - region.set(this._curX / _width, this._curY / _height, width / _width, height / _height); - - // destroy origin texture. - sprite.texture && sprite.texture.destroy(); - // Update atlas texture. - sprite.atlasRegion = region; - sprite.texture = texture; - this._curX = endX + space; - - return true; - } - - /** - * Remove a sprite. - * @param sprite - the sprite to remove - * @returns true if remove sprite success, otherwise false - */ - public removeSprite(sprite: Sprite): boolean { - const id = sprite.instanceId; - const { _sprites } = this; - if (_sprites[id]) { - delete _sprites[id]; - return true; - } - return false; - } -} - diff --git a/packages/core/src/2d/dynamic-atlas/DynamicTextAtlasManager.ts b/packages/core/src/2d/dynamic-atlas/DynamicTextAtlasManager.ts deleted file mode 100644 index 0032ac87c1..0000000000 --- a/packages/core/src/2d/dynamic-atlas/DynamicTextAtlasManager.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { Sprite } from "../sprite/Sprite"; -import { Engine } from "../../Engine"; -import { DynamicTextAtlas } from "./DynamicTextAtlas"; - -/** - * Dynamic atlas manager for text. - */ -export class DynamicTextAtlasManager { - private _maxAtlasCount: number = 2; - private _textureSize: number = 1024; - private _atlases: Array = []; - private _atlasIndex: number = -1; - private _spritesInAtlasIndex: Record = {}; - - /** - * Indicates how many atlases should be created. - */ - get maxAtlasCount(): number { - return this._maxAtlasCount; - } - - set maxAtlasCount(val: number) { - this._maxAtlasCount = val; - } - - /** - * Indicates the size of the texture. - */ - get textureSize(): number { - return this._textureSize; - } - - set textureSize(val: number) { - this._textureSize = Math.min(val, 2048); - } - - /** - * @internal - */ - constructor(public readonly engine: Engine) {} - - /** - * Add a sprite to atlas. - * @param sprite - the sprite to add - * @param imageSource - The source of texture - * @returns true if add sprite success, otherwise false - */ - public addSprite(sprite: Sprite, imageSource: TexImageSource | OffscreenCanvas): boolean { - // Remove sprite if the sprite has been add. - const { _spritesInAtlasIndex, _atlases } = this; - const id = sprite.instanceId; - const atlasIndex = _spritesInAtlasIndex[id]; - if (atlasIndex) { - _atlases[atlasIndex].removeSprite(sprite); - delete _spritesInAtlasIndex[id]; - } - - if (this._atlasIndex >= this._maxAtlasCount) { - return false; - } - - let atlas = _atlases[this._atlasIndex]; - if (!atlas) { - atlas = this._createAtlas(); - } - - if (atlas.addSprite(sprite, imageSource)) { - _spritesInAtlasIndex[id] = this._atlasIndex; - return true; - } - - if (this._atlasIndex + 1 >= this._maxAtlasCount) { - this._atlasIndex = this._maxAtlasCount; - return false; - } - - atlas = this._createAtlas(); - if (atlas.addSprite(sprite, imageSource)) { - _spritesInAtlasIndex[id] = this._atlasIndex; - return true; - } - return false; - } - - /** - * Remove a sprite from atlas. - * @param sprite - the sprite to remove - * @returns true if remove sprite success, otherwise false - */ - public removeSprite(sprite: Sprite): boolean { - if (!sprite) return false; - - const { _atlases } = this; - for (let i = _atlases.length - 1; i >= 0; --i) { - const atlas = _atlases[i]; - if(atlas.removeSprite(sprite)) { - delete this._spritesInAtlasIndex[i]; - return true; - } - } - - return false; - } - - /** - * Reset all atlases. - */ - public reset() { - const { _atlases } = this; - for (let i = 0, l = _atlases.length; i < l; ++i) { - _atlases[i].destroy(); - } - - _atlases.length = 0; - this._atlasIndex = -1; - this._spritesInAtlasIndex = {}; - } - - private _createAtlas(): DynamicTextAtlas { - this._atlasIndex++; - const { _textureSize } = this; - const atlas = new DynamicTextAtlas(this.engine, _textureSize, _textureSize); - this._atlases.push(atlas); - return atlas; - } -} diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index c68e21817e..ccd3486613 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -10,9 +10,6 @@ import { SpritePropertyDirtyFlag } from "../enums/SpriteDirtyFlag"; * 2D sprite. */ export class Sprite extends RefObject { - /** @internal Conversion of space units to pixel units. */ - static _pixelPerUnit: number = 100; - /** The name of sprite. */ name: string; @@ -259,13 +256,15 @@ export class Sprite extends RefObject { private _calDefaultSize(): void { if (this._texture) { const { _texture, _atlasRegion, _atlasRegionOffset, _region } = this; + const pixelsPerUnitReciprocal = 1.0 / Engine._pixelsPerUnit; this.width = - (((_texture.width * _atlasRegion.width) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * _region.width) / - Sprite._pixelPerUnit; + ((_texture.width * _atlasRegion.width) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * + _region.width * + pixelsPerUnitReciprocal; this.height = - (((_texture.height * _atlasRegion.height) / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * - _region.height) / - Sprite._pixelPerUnit; + ((_texture.height * _atlasRegion.height) / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * + _region.height * + pixelsPerUnitReciprocal; } } diff --git a/packages/core/src/2d/text/CharInfo.ts b/packages/core/src/2d/text/CharInfo.ts new file mode 100644 index 0000000000..a4696fd6c2 --- /dev/null +++ b/packages/core/src/2d/text/CharInfo.ts @@ -0,0 +1,19 @@ +/** + * @internal + */ +export interface CharInfo { + x: number; + y: number; + w: number; + h: number; + offsetX: number; + offsetY: number; + xAdvance: number; + u0: number; + v0: number; + u1: number; + v1: number; + ascent: number; + descent: number; + index: number; +} diff --git a/packages/core/src/2d/text/CharRenderData.ts b/packages/core/src/2d/text/CharRenderData.ts new file mode 100644 index 0000000000..e02d562e36 --- /dev/null +++ b/packages/core/src/2d/text/CharRenderData.ts @@ -0,0 +1,21 @@ +import { Vector2, Vector3 } from "@oasis-engine/math"; +import { Texture2D } from "../../texture"; +import { RenderData2D } from "../data/RenderData2D"; + +/** + * @internal + */ +export class CharRenderData { + static triangles: number[] = [0, 2, 1, 2, 0, 3]; + + texture: Texture2D; + localPositions: Vector3[]; + renderData: RenderData2D; + + constructor() { + const positions = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; + const uvs = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; + this.localPositions = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; + this.renderData = new RenderData2D(4, positions, uvs, CharRenderData.triangles, null); + } +} diff --git a/packages/core/src/2d/text/CharRenderDataPool.ts b/packages/core/src/2d/text/CharRenderDataPool.ts new file mode 100644 index 0000000000..ac4e89a9d5 --- /dev/null +++ b/packages/core/src/2d/text/CharRenderDataPool.ts @@ -0,0 +1,26 @@ +/** + * @internal + */ +export class CharRenderDataPool { + private _elements: T[] = []; + private _type: new () => T; + + constructor(type: new () => T, length: number) { + this._type = type; + const elements = this._elements; + for (let i = 0; i < length; ++i) { + elements[i] = new type(); + } + } + + get(): T { + if (this._elements.length > 0) { + return this._elements.pop(); + } + return new this._type(); + } + + put(data: T): void { + this._elements.push(data); + } +} diff --git a/packages/core/src/2d/text/Font.ts b/packages/core/src/2d/text/Font.ts index f56e36b27a..fc973a465d 100644 --- a/packages/core/src/2d/text/Font.ts +++ b/packages/core/src/2d/text/Font.ts @@ -1,5 +1,8 @@ import { RefObject } from "../../asset/RefObject"; import { Engine } from "../../Engine"; +import { Texture2D } from "../../texture"; +import { CharInfo } from "./CharInfo"; +import { FontAtlas } from "../atlas/FontAtlas"; /** * Font. @@ -10,21 +13,23 @@ export class Font extends RefObject { /** * Create a font from OS. * @param engine - Engine to which the font belongs - * @param fontName - The name of font + * @param name - The name of font * @returns The font object has been create */ - static createFromOS(engine: Engine, fontName: string = ""): Font { + static createFromOS(engine: Engine, name: string = ""): Font { const fontMap = Font._fontMap; - let font = fontMap[fontName]; + let font = fontMap[name]; if (font) { return font; } - font = new Font(engine, fontName); - fontMap[fontName] = font; + font = new Font(engine, name); + fontMap[name] = font; return font; } private _name: string = ""; + private _fontAtlases: Array = []; + private _lastIndex: number = -1; /** * The name of the font object. @@ -38,8 +43,85 @@ export class Font extends RefObject { this._name = name; } + /** + * @internal + */ + _uploadCharTexture(charInfo: CharInfo, imageSource: TexImageSource | OffscreenCanvas): void { + const fontAtlases = this._fontAtlases; + let lastIndex = this._lastIndex; + if (lastIndex === -1) { + this._createFontAtlas(); + lastIndex++ + } + let fontAtlas = fontAtlases[lastIndex]; + if (!fontAtlas.uploadCharTexture(charInfo, imageSource)) { + fontAtlas = this._createFontAtlas(); + fontAtlas.uploadCharTexture(charInfo, imageSource); + lastIndex++; + } + this._lastIndex = lastIndex; + } + + /** + * @internal + */ + _addCharInfo(char: string, charInfo: CharInfo) { + const lastIndex = this._lastIndex; + charInfo.index = lastIndex; + this._fontAtlases[lastIndex].addCharInfo(char, charInfo); + } + + /** + * @internal + */ + _getCharInfo(char: string): CharInfo { + const fontAtlases = this._fontAtlases; + for (let i = 0, n = fontAtlases.length; i < n; ++i) { + const fontAtlas = fontAtlases[i]; + const charInfo = fontAtlas.getCharInfo(char); + if (charInfo) { + return charInfo; + } + } + return null; + } + + /** + * @internal + */ + _getTextureByIndex(index: number): Texture2D { + const fontAtlas = this._fontAtlases[index]; + if (fontAtlas) { + return fontAtlas.texture; + } + return null; + } + + /** + * @internal + */ + _getLastIndex(): number { + return this._lastIndex; + } + /** * @override */ - protected _onDestroy(): void {} + _onDestroy(): void { + const fontAtlases = this._fontAtlases; + for (let i = 0, n = fontAtlases.length; i < n; ++i) { + fontAtlases[i].destroy(true); + } + fontAtlases.length = 0; + delete Font._fontMap[this._name]; + } + + private _createFontAtlas(): FontAtlas { + const { engine } = this; + const fontAtlas = new FontAtlas(engine); + const texture = new Texture2D(engine, 512, 512); + fontAtlas.texture = texture; + this._fontAtlases.push(fontAtlas); + return fontAtlas; + } } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index c292ac3ae3..0b24807043 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -1,38 +1,41 @@ import { BoundingBox, Color, Vector3 } from "@oasis-engine/math"; -import { BoolUpdateFlag } from "../../BoolUpdateFlag"; import { Camera } from "../../Camera"; import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager"; import { Entity } from "../../Entity"; -import { Renderer } from "../../Renderer"; -import { CompareFunction } from "../../shader/enums/CompareFunction"; -import { Texture2D } from "../../texture"; +import { CharRenderData } from "./CharRenderData"; import { FontStyle } from "../enums/FontStyle"; -import { SpriteMaskInteraction } from "../enums/SpriteMaskInteraction"; -import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { TextHorizontalAlignment, TextVerticalAlignment } from "../enums/TextAlignment"; import { OverflowMode } from "../enums/TextOverflow"; -import { Sprite } from "../sprite/Sprite"; -import { SpriteRenderer } from "../sprite/SpriteRenderer"; import { Font } from "./Font"; +import { Renderer } from "../../Renderer"; +import { SpriteMaskInteraction } from "../enums/SpriteMaskInteraction"; +import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; +import { CompareFunction } from "../../shader/enums/CompareFunction"; +import { ICustomClone } from "../../clone/ComponentCloner"; import { TextUtils } from "./TextUtils"; +import { CharRenderDataPool } from "./CharRenderDataPool"; +import { Engine } from "../../Engine"; +import { ListenerUpdateFlag } from "../../ListenerUpdateFlag"; /** * Renders a text for 2D graphics. */ -export class TextRenderer extends Renderer { - private static _tempVec3: Vector3 = new Vector3(); +export class TextRenderer extends Renderer implements ICustomClone { + private static _charRenderDataPool: CharRenderDataPool = new CharRenderDataPool(CharRenderData, 50); - /** @internal temp solution. */ - @ignoreClone - _customLocalBounds: BoundingBox = null; - /** @internal temp solution. */ + /** @internal */ + @assignmentClone + _charFont: Font = null; + /** @internal */ @ignoreClone - _customRootEntity: Entity = null; + _charRenderDatas: Array = []; @ignoreClone - private _sprite: Sprite = null; - @deepClone - private _positions: Vector3[] = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; + _dirtyFlag: number = DirtyFlag.Font | DirtyFlag.LocalPositionBounds | DirtyFlag.WorldPosition | DirtyFlag.WorldBounds; + /** @internal */ + @ignoreClone + _isWorldMatrixDirty: ListenerUpdateFlag; + @deepClone private _color: Color = new Color(1, 1, 1, 1); @assignmentClone @@ -41,6 +44,8 @@ export class TextRenderer extends Renderer { private _width: number = 0; @assignmentClone private _height: number = 0; + @ignoreClone + private _localBounds: BoundingBox = new BoundingBox(); @assignmentClone private _font: Font = null; @assignmentClone @@ -57,10 +62,6 @@ export class TextRenderer extends Renderer { private _enableWrapping: boolean = false; @assignmentClone private _overflowMode: OverflowMode = OverflowMode.Overflow; - @ignoreClone - private _dirtyFlag: number = DirtyFlag.Property; - @ignoreClone - private _isWorldMatrixDirty: BoolUpdateFlag; @assignmentClone private _maskInteraction: SpriteMaskInteraction = SpriteMaskInteraction.None; @assignmentClone @@ -90,7 +91,7 @@ export class TextRenderer extends Renderer { value = value || ""; if (this._text !== value) { this._text = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -104,7 +105,7 @@ export class TextRenderer extends Renderer { set width(value: number) { if (this._width !== value) { this._width = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -118,7 +119,7 @@ export class TextRenderer extends Renderer { set height(value: number) { if (this._height !== value) { this._height = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -132,7 +133,7 @@ export class TextRenderer extends Renderer { set font(value: Font) { if (this._font !== value) { this._font = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.Font); } } @@ -146,7 +147,7 @@ export class TextRenderer extends Renderer { set fontSize(value: number) { if (this._fontSize !== value) { this._fontSize = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.Font); } } @@ -160,7 +161,7 @@ export class TextRenderer extends Renderer { set fontStyle(value: FontStyle) { if (this.fontStyle !== value) { this._fontStyle = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.Font); } } @@ -174,7 +175,7 @@ export class TextRenderer extends Renderer { set lineSpacing(value: number) { if (this._lineSpacing !== value) { this._lineSpacing = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -188,7 +189,7 @@ export class TextRenderer extends Renderer { set horizontalAlignment(value: TextHorizontalAlignment) { if (this._horizontalAlignment !== value) { this._horizontalAlignment = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -202,7 +203,7 @@ export class TextRenderer extends Renderer { set verticalAlignment(value: TextVerticalAlignment) { if (this._verticalAlignment !== value) { this._verticalAlignment = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -216,7 +217,7 @@ export class TextRenderer extends Renderer { set enableWrapping(value: boolean) { if (this._enableWrapping !== value) { this._enableWrapping = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -230,7 +231,7 @@ export class TextRenderer extends Renderer { set overflowMode(value: OverflowMode) { if (this._overflowMode !== value) { this._overflowMode = value; - this._setDirtyFlagTrue(DirtyFlag.Property); + this._setDirtyFlagTrue(DirtyFlag.LocalPositionBounds); } } @@ -259,11 +260,29 @@ export class TextRenderer extends Renderer { this._maskLayer = value; } + /** + * The bounding volume of the TextRenderer. + */ + get bounds(): BoundingBox { + const isFontDirty = this._isContainDirtyFlag(DirtyFlag.Font); + const isLocalPositionBoundsDirty = this._isContainDirtyFlag(DirtyFlag.LocalPositionBounds); + const isWorldBoundsDirty = this._isContainDirtyFlag(DirtyFlag.WorldBounds); + if (isFontDirty || isLocalPositionBoundsDirty || isWorldBoundsDirty) { + isFontDirty && this._resetCharFont(); + isLocalPositionBoundsDirty && this._updateLocalData(); + isWorldBoundsDirty && this._updateBounds(this._bounds); + this._setDirtyFlagFalse(DirtyFlag.Font | DirtyFlag.LocalPositionBounds | DirtyFlag.WorldBounds); + } + return this._bounds; + } + constructor(entity: Entity) { super(entity); const { engine } = this; - this._isWorldMatrixDirty = entity.transform.registerWorldChangeFlag(); - this._sprite = new Sprite(engine); + this._isWorldMatrixDirty = entity.transform._registerWorldChangeListenser(); + this._isWorldMatrixDirty.listener = () => { + this._setDirtyFlagTrue(DirtyFlag.WorldPosition | DirtyFlag.WorldBounds); + }; this.font = Font.createFromOS(engine); this.setMaterial(engine._spriteDefaultMaterial); } @@ -277,47 +296,50 @@ export class TextRenderer extends Renderer { (this.enableWrapping && this.width <= 0) || (this.overflowMode === OverflowMode.Truncate && this.height <= 0) ) { - this._clearTexture(); return; } - const { _sprite: sprite } = this; - const isTextureDirty = this._isContainDirtyFlag(DirtyFlag.Property); - if (isTextureDirty) { - this._updateText(); - this._setDirtyFlagFalse(DirtyFlag.Property); + if (this._isContainDirtyFlag(DirtyFlag.MaskInteraction)) { + this._updateStencilState(); + this._setDirtyFlagFalse(DirtyFlag.MaskInteraction); } - if (this._isWorldMatrixDirty.flag || isTextureDirty) { - this._updatePosition(); - this._isWorldMatrixDirty.flag = false; + const isFontDirty = this._isContainDirtyFlag(DirtyFlag.Font); + if (isFontDirty) { + this._resetCharFont(); + this._setDirtyFlagFalse(DirtyFlag.Font); } - if (this._isContainDirtyFlag(DirtyFlag.MaskInteraction)) { - this._updateStencilState(); - this._setDirtyFlagFalse(DirtyFlag.MaskInteraction); + if (this._isContainDirtyFlag(DirtyFlag.LocalPositionBounds) || isFontDirty) { + this._updateLocalData(); + this._setDirtyFlagFalse(DirtyFlag.LocalPositionBounds); } - this.shaderData.setTexture(SpriteRenderer._textureProperty, sprite.texture); - const spriteElementPool = this._engine._spriteElementPool; - const spriteElement = spriteElementPool.getFromPool(); - spriteElement.setValue( - this, - this._positions, - sprite._uv, - sprite._triangles, - this.color, - this.getMaterial(), - camera - ); - camera._renderPipeline.pushPrimitive(spriteElement); + if (this._isContainDirtyFlag(DirtyFlag.WorldPosition) || isFontDirty) { + this._updatePosition(); + this._setDirtyFlagFalse(DirtyFlag.WorldPosition); + } + + const charRenderDatas = this._charRenderDatas; + for (let i = 0, n = charRenderDatas.length; i < n; ++i) { + const charRenderData = charRenderDatas[i]; + const spriteElement = this._engine._spriteElementPool.getFromPool(); + spriteElement.setValue(this, charRenderData.renderData, this.getMaterial(), charRenderData.texture); + camera._renderPipeline.pushPrimitive(spriteElement); + } } /** * @internal */ _onDestroy(): void { - this.engine._dynamicTextAtlasManager.removeSprite(this._sprite); + // Clear render data. + const charRenderDatas = this._charRenderDatas; + for (let i = 0, n = charRenderDatas.length; i < n; ++i) { + TextRenderer._charRenderDataPool.put(charRenderDatas[i]); + } + charRenderDatas.length = 0; + this._isWorldMatrixDirty.destroy(); super._onDestroy(); } @@ -330,88 +352,31 @@ export class TextRenderer extends Renderer { } /** - * @override + * @internal */ - protected _updateBounds(worldBounds: BoundingBox): void { - if (this._customLocalBounds && this._customRootEntity) { - const worldMatrix = this._customRootEntity.transform.worldMatrix; - BoundingBox.transform(this._customLocalBounds, worldMatrix, worldBounds); - } else { - const worldMatrix = this._entity.transform.worldMatrix; - BoundingBox.transform(this._sprite.bounds, worldMatrix, worldBounds); - } - } - - private _isContainDirtyFlag(type: number): boolean { + _isContainDirtyFlag(type: number): boolean { return (this._dirtyFlag & type) != 0; } - private _setDirtyFlagTrue(type: number): void { + /** + * @internal + */ + _setDirtyFlagTrue(type: number): void { this._dirtyFlag |= type; } - private _setDirtyFlagFalse(type: number): void { + /** + * @internal + */ + _setDirtyFlagFalse(type: number): void { this._dirtyFlag &= ~type; } - private _updateText(): void { - const { width: originWidth, height: originHeight, enableWrapping, overflowMode } = this; - const fontStr = TextUtils.getNativeFontString(this._font.name, this._fontSize, this._fontStyle); - const textMetrics = TextUtils.measureText( - this.text, - originWidth, - originHeight, - this.lineSpacing, - enableWrapping, - overflowMode, - fontStr - ); - TextUtils.updateText(textMetrics, fontStr, this.horizontalAlignment, this.verticalAlignment); - this._updateTexture(); - } - - private _updateTexture(): void { - const trimData = TextUtils.trimCanvas(); - const { width, height } = trimData; - const canvas = TextUtils.updateCanvas(width, height, trimData.data); - this._clearTexture(); - const { _sprite: sprite, horizontalAlignment, verticalAlignment } = this; - - // Handle the case that width or height of text is larger than real width or height. - const { pixelsPerUnit, pivot } = sprite; - switch (horizontalAlignment) { - case TextHorizontalAlignment.Left: - pivot.x = ((this.width * pixelsPerUnit) / width) * 0.5; - break; - case TextHorizontalAlignment.Right: - pivot.x = 1 - ((this.width * pixelsPerUnit) / width) * 0.5; - break; - case TextHorizontalAlignment.Center: - pivot.x = 0.5; - break; - } - switch (verticalAlignment) { - case TextVerticalAlignment.Top: - pivot.y = 1 - ((this.height * pixelsPerUnit) / height) * 0.5; - break; - case TextVerticalAlignment.Bottom: - pivot.y = ((this.height * pixelsPerUnit) / height) * 0.5; - break; - case TextVerticalAlignment.Center: - pivot.y = 0.5; - break; - } - sprite.pivot = pivot; - - // If add fail, set texture for sprite. - if (!this.engine._dynamicTextAtlasManager.addSprite(sprite, canvas)) { - const texture = new Texture2D(this.engine, width, height); - texture.setImageSource(canvas); - texture.generateMipmaps(); - sprite.texture = texture; - } - // Update sprite data. - sprite._updateMesh(); + /** + * @override + */ + protected _updateBounds(worldBounds: BoundingBox): void { + BoundingBox.transform(this._localBounds, this._entity.transform.worldMatrix, worldBounds); } private _updateStencilState(): void { @@ -438,30 +403,155 @@ export class TextRenderer extends Renderer { } } + private _resetCharFont(): void { + const lastCharFont = this._charFont; + if (lastCharFont) { + lastCharFont._addRefCount(-1); + lastCharFont.destroy(); + } + this._charFont = Font.createFromOS( + this.engine, + TextUtils.getNativeFontHash(this.font.name, this.fontSize, this.fontStyle) + ); + this._charFont._addRefCount(1); + } + private _updatePosition(): void { - const localPositions = this._sprite._positions; - const localVertexPos = TextRenderer._tempVec3; const worldMatrix = this.entity.transform.worldMatrix; - - const { _positions } = this; - for (let i = 0, n = _positions.length; i < n; i++) { - const curVertexPos = localPositions[i]; - localVertexPos.set(curVertexPos.x, curVertexPos.y, 0); - Vector3.transformToVec3(localVertexPos, worldMatrix, _positions[i]); + const charRenderDatas = this._charRenderDatas; + for (let i = 0, n = charRenderDatas.length; i < n; ++i) { + const { localPositions, renderData } = charRenderDatas[i]; + for (let j = 0; j < 4; ++j) { + Vector3.transformToVec3(localPositions[j], worldMatrix, renderData.positions[j]); + } } } - private _clearTexture(): void { - const { _sprite } = this; - // Remove sprite from dynamic atlas. - this.engine._dynamicTextAtlasManager.removeSprite(_sprite); - this.shaderData.setTexture(SpriteRenderer._textureProperty, null); - _sprite.atlasRegion = _sprite.region; + private _updateLocalData(): void { + const { color, horizontalAlignment, verticalAlignment, _charRenderDatas: charRenderDatas } = this; + const { min, max } = this._localBounds; + min.set(0, 0, 0); + max.set(0, 0, 0); + const { _pixelsPerUnit } = Engine; + const pixelsPerUnitReciprocal = 1.0 / _pixelsPerUnit; + const charFont = this._charFont; + const rendererWidth = this.width * _pixelsPerUnit; + const halfRendererWidth = rendererWidth * 0.5; + const rendererHeight = this.height * _pixelsPerUnit; + + const textMetrics = this.enableWrapping + ? TextUtils.measureTextWithWrap(this) + : TextUtils.measureTextWithoutWrap(this); + const { height, lines, lineWidths, lineHeight, lineMaxSizes } = textMetrics; + const charRenderDataPool = TextRenderer._charRenderDataPool; + const halfLineHeight = lineHeight * 0.5; + const linesLen = lines.length; + + let startY = 0; + const topDiff = lineHeight * 0.5 - lineMaxSizes[0].ascent; + const bottomDiff = lineHeight * 0.5 - lineMaxSizes[linesLen - 1].descent - 1; + switch (verticalAlignment) { + case TextVerticalAlignment.Top: + startY = rendererHeight * 0.5 - halfLineHeight + topDiff; + break; + case TextVerticalAlignment.Center: + startY = height * 0.5 - halfLineHeight - (bottomDiff - topDiff) * 0.5; + break; + case TextVerticalAlignment.Bottom: + startY = height - rendererHeight * 0.5 - halfLineHeight - bottomDiff; + break; + } + + let renderDataCount = 0; + let minX = Number.MAX_SAFE_INTEGER; + let minY = Number.MAX_SAFE_INTEGER; + let maxX = Number.MIN_SAFE_INTEGER; + let maxY = Number.MIN_SAFE_INTEGER; + let lastLineIndex = linesLen - 1; + for (let i = 0; i < linesLen; ++i) { + const line = lines[i]; + const lineWidth = lineWidths[i]; + + let startX = 0; + switch (horizontalAlignment) { + case TextHorizontalAlignment.Left: + startX = -halfRendererWidth; + break; + case TextHorizontalAlignment.Center: + startX = -lineWidth * 0.5; + break; + case TextHorizontalAlignment.Right: + startX = halfRendererWidth - lineWidth; + break; + } + + for (let j = 0, m = line.length - 1; j <= m; ++j) { + const char = line[j]; + const charInfo = charFont._getCharInfo(char); + + if (charInfo.h > 0) { + const charRenderData = charRenderDatas[renderDataCount] || charRenderDataPool.get(); + const { renderData, localPositions } = charRenderData; + charRenderData.texture = charFont._getTextureByIndex(charInfo.index); + renderData.color = color; + + const { uvs } = renderData; + const { w, u0, v0, u1, v1, ascent, descent } = charInfo; + + const left = startX * pixelsPerUnitReciprocal; + const right = (startX + w) * pixelsPerUnitReciprocal; + const top = (startY + ascent) * pixelsPerUnitReciprocal; + const bottom = (startY - descent + 1) * pixelsPerUnitReciprocal; + // Top-left. + localPositions[0].set(left, top, 0); + uvs[0].set(u0, v0); + // Top-right. + localPositions[1].set(right, top, 0); + uvs[1].set(u1, v0); + // Bottom-right. + localPositions[2].set(right, bottom, 0); + uvs[2].set(u1, v1); + // Bottom-left. + localPositions[3].set(left, bottom, 0); + uvs[3].set(u0, v1); + + charRenderDatas[renderDataCount] = charRenderData; + renderDataCount++; + + i === 0 && (maxY = Math.max(maxY, top)); + i === lastLineIndex && (minY = Math.min(minY, bottom)); + j === 0 && (minX = Math.min(minX, left)); + j === m && (maxX = Math.max(maxX, right)); + } + startX += charInfo.xAdvance; + } + + startY -= lineHeight; + } + + min.set(minX, minY, 0); + max.set(maxX, maxY, 0); + + // Revert excess render data to pool. + const lastRenderDataCount = charRenderDatas.length; + if (lastRenderDataCount > renderDataCount) { + for (let i = renderDataCount; i < lastRenderDataCount; ++i) { + charRenderDataPool.put(charRenderDatas[i]); + } + charRenderDatas.length = renderDataCount; + } + + charFont._getLastIndex() > 0 && + charRenderDatas.sort((a, b) => { + return a.texture.instanceId - b.texture.instanceId; + }); } } -enum DirtyFlag { - Property = 0x1, - MaskInteraction = 0x2, - All = 0x3 +export enum DirtyFlag { + Font = 0x1, + LocalPositionBounds = 0x2, + WorldPosition = 0x4, + WorldBounds = 0x8, + MaskInteraction = 0x10 } diff --git a/packages/core/src/2d/text/TextUtils.ts b/packages/core/src/2d/text/TextUtils.ts index a3592aea97..0c2425c95e 100644 --- a/packages/core/src/2d/text/TextUtils.ts +++ b/packages/core/src/2d/text/TextUtils.ts @@ -1,34 +1,16 @@ -import { Vector2 } from "@oasis-engine/math"; +import { Engine } from "../../Engine"; +import { CharInfo } from "./CharInfo"; import { FontStyle } from "../enums/FontStyle"; -import { TextHorizontalAlignment, TextVerticalAlignment } from "../enums/TextAlignment"; import { OverflowMode } from "../enums/TextOverflow"; - -/** - * @internal - * TextContext. - */ -export interface TextContext { - canvas: HTMLCanvasElement | OffscreenCanvas; - context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D; -} - -/** - * @internal - * TextMetrics. - */ -export interface TextMetrics { - width: number; - height: number; - lines: Array; - lineWidths: Array; - lineHeight: number; -} +import { Font } from "./Font"; +import { TextRenderer } from "./TextRenderer"; /** * @internal * TextUtils includes some helper function for text. */ export class TextUtils { + /** @internal */ static _genericFontFamilies: Array = [ "serif", "sans-serif", @@ -45,18 +27,14 @@ export class TextUtils { private static _measureBaseline: string = "M"; private static _heightMultiplier: number = 2; private static _baselineMultiplier: number = 1.4; - private static _maxWidth: number = 2048; - private static _maxHeight: number = 2048; - private static _pixelsPerUnit: number = 128; - private static _fontSizeCache: Record = {}; + private static _fontSizeInfoCache: Record = {}; private static _textContext: TextContext = null; - private static _tempVec2: Vector2 = new Vector2(); /** * The instance function to get an object includes 2d context and canvas. * @returns the TextContext object */ - public static textContext(): TextContext { + static textContext(): TextContext { let { _textContext: textContext } = TextUtils; if (!textContext) { let canvas: HTMLCanvasElement | OffscreenCanvas; @@ -74,117 +52,116 @@ export class TextUtils { /** * Measure the font. - * @param font - the string of the font - * @returns the font size + * @param fontString - the string of the font + * @returns the font size info */ - public static measureFont(font: string): number { - const { _fontSizeCache: fontSizeCache } = TextUtils; - let fontSize = fontSizeCache[font]; - if (fontSize) { - return fontSize; - } - - const { canvas, context } = TextUtils.textContext(); - context.font = font; - const measureString = TextUtils._measureString; - const width = Math.ceil(context.measureText(measureString).width); - let baseline = Math.ceil(context.measureText(TextUtils._measureBaseline).width); - const height = baseline * TextUtils._heightMultiplier; - baseline = (TextUtils._baselineMultiplier * baseline) | 0; - - canvas.width = width; - canvas.height = height; - - context.font = font; - context.fillStyle = "#000"; - context.clearRect(0, 0, width, height); - context.textBaseline = "alphabetic"; - context.fillStyle = "#f00"; - context.fillText(measureString, 0, baseline); - - const imgData = context.getImageData(0, 0, width, height).data; - const lineDataCount = width * 4; - let stop = false; - let i = 0; - let offset = 0; - - for (i = 0; i < baseline; ++i) { - offset = i * lineDataCount; - for (let j = 0; j < lineDataCount; j += 4) { - if (imgData[offset + j] !== 0) { - stop = true; - break; - } - } - if (stop) { - break; - } + static measureFont(fontString: string): FontSizeInfo { + const { _fontSizeInfoCache: fontSizeInfoCache } = TextUtils; + let info = fontSizeInfoCache[fontString]; + if (info) { + return info; } - const ascent = baseline - i; - stop = false; + info = TextUtils._measureFontOrChar(fontString); + fontSizeInfoCache[fontString] = info; + return info; + } - for (i = height - 1; i >= baseline; --i) { - offset = i * lineDataCount; - for (let j = 0; j < lineDataCount; j += 4) { - if (imgData[offset + j] !== 0) { - stop = true; - break; - } - } - if (stop) { - break; - } + /** + * Get native font string. + * @param fontName - The font name + * @param fontSize - The font size + * @param style - The font style + * @returns The native font string + */ + static getNativeFontString(fontName: string, fontSize: number, style: FontStyle): string { + let str = style & FontStyle.Bold ? "bold " : ""; + style & FontStyle.Italic && (str += "italic "); + // Check if font already contains strings + if (!/([\"\'])[^\'\"]+\1/.test(fontName) && TextUtils._genericFontFamilies.indexOf(fontName) == -1) { + fontName = `"${fontName}"`; } + str += `${fontSize}px ${fontName}`; + return str; + } - const descent = i - baseline + 1; - fontSize = ascent + descent; - fontSizeCache[font] = fontSize; - return fontSize; + static measureChar(char: string, fontString: string): CharInfo { + return TextUtils._measureFontOrChar(fontString, char); } - /** - * Measure the text. - * @param text - rendering string - * @param originWidth - the width of the TextRenderer - * @param originHeight - the height of the TextRenderer - * @param lineSpacing - the space between two lines - * @param enableWrapping - whether wrap text to next line when exceeds the width of the container - * @param overflowMode - the overflow mode - * @param fontString - the font string - * @returns the TextMetrics object - */ - public static measureText( - text: string, - originWidth: number, - originHeight: number, - lineSpacing: number, - enableWrapping: boolean, - overflowMode: OverflowMode, - fontString: string - ): TextMetrics { - const { _pixelsPerUnit } = TextUtils; - const fontSize = TextUtils.measureFont(fontString); - const context = TextUtils.textContext().context; - const lines = TextUtils._wordWrap(text, originWidth, enableWrapping, fontString); - const lineCount = lines.length; + static measureTextWithWrap(renderer: TextRenderer): TextMetrics { + const { fontSize, fontStyle } = renderer; + const { name } = renderer.font; + const fontString = TextUtils.getNativeFontString(name, fontSize, fontStyle); + const charFont = renderer._charFont; + const fontSizeInfo = TextUtils.measureFont(fontString); + const subTexts = renderer.text.split(/(?:\r\n|\r|\n)/); + const lines = new Array(); const lineWidths = new Array(); - const lineHeight = fontSize + lineSpacing * _pixelsPerUnit; - context.font = fontString; - // Calculate max width of all lines. + const lineMaxSizes = new Array(); + const { _pixelsPerUnit } = Engine; + const lineHeight = fontSizeInfo.size + renderer.lineSpacing * _pixelsPerUnit; + const wrapWidth = renderer.width * _pixelsPerUnit; let width = 0; - for (let i = 0; i < lineCount; ++i) { - const lineWidth = Math.ceil(context.measureText(lines[i]).width); - if (lineWidth > width) { - width = lineWidth; + + for (let i = 0, n = subTexts.length; i < n; ++i) { + const subText = subTexts[i]; + let chars = ""; + let charsWidth = 0; + let maxAscent = -1; + let maxDescent = -1; + + for (let j = 0, m = subText.length; j < m; ++j) { + const char = subText[j]; + const charInfo = TextUtils._getCharInfo(char, fontString, charFont); + const { w, offsetY } = charInfo; + const halfH = charInfo.h * 0.5; + const ascent = halfH + offsetY; + const descent = halfH - offsetY; + if (charsWidth + w > wrapWidth) { + if (charsWidth === 0) { + lines.push(char); + lineWidths.push(w); + lineMaxSizes.push({ + ascent, + descent, + size: ascent + descent + }); + } else { + lines.push(chars); + lineWidths.push(charsWidth); + lineMaxSizes.push({ + ascent: maxAscent, + descent: maxDescent, + size: maxAscent + maxDescent + }); + chars = char; + charsWidth = charInfo.xAdvance; + maxAscent = ascent; + maxDescent = descent; + } + } else { + chars += char; + charsWidth += charInfo.xAdvance; + maxAscent < ascent && (maxAscent = ascent); + maxDescent < descent && (maxDescent = descent); + } + } + + if (charsWidth > 0) { + lines.push(chars); + lineWidths.push(charsWidth); + lineMaxSizes.push({ + ascent: maxAscent, + descent: maxDescent, + size: maxAscent + maxDescent + }); } - lineWidths.push(lineWidth); } - // Reset width and height. - let height = originHeight * _pixelsPerUnit; - if (overflowMode === OverflowMode.Overflow) { - height = Math.min(lineHeight * lineCount, TextUtils._maxHeight); + let height = renderer.height * _pixelsPerUnit; + if (renderer.overflowMode === OverflowMode.Overflow) { + height = lineHeight * lines.length; } return { @@ -192,139 +169,84 @@ export class TextUtils { height, lines, lineWidths, - lineHeight + lineHeight, + lineMaxSizes }; } - /** - * Trim canvas. - * @returns the width and height after trim, and the image data - */ - public static trimCanvas(): { width: number; height: number; data?: ImageData } { - // https://gist.github.com/remy/784508 - - const { canvas, context } = TextUtils.textContext(); - let { width, height } = canvas; - - const imageData = context.getImageData(0, 0, width, height).data; - const len = imageData.length; - - let top = -1; - let bottom = -1; - let left = width; - let right = -1; - let data = null; - let x; - let y; - - for (let i = 0; i < len; i += 4) { - if (imageData[i + 3] !== 0) { - const idx = i / 4; - x = idx % width; - y = ~~(idx / width); - - if (top === -1) { - top = y; - } - - if (x < left) { - left = x; - } - - if (x > right) { - right = x; - } - - if (y > bottom) { - bottom = y; - } - } + static measureTextWithoutWrap(renderer: TextRenderer): TextMetrics { + const { fontSize, fontStyle } = renderer; + const { name } = renderer.font; + const fontString = TextUtils.getNativeFontString(name, fontSize, fontStyle); + const charFont = renderer._charFont; + const fontSizeInfo = TextUtils.measureFont(fontString); + const lines = renderer.text.split(/(?:\r\n|\r|\n)/); + const lineCount = lines.length; + const lineWidths = new Array(); + const lineMaxSizes = new Array(); + const { _pixelsPerUnit } = Engine; + const lineHeight = fontSizeInfo.size + renderer.lineSpacing * _pixelsPerUnit; + let width = 0; + let height = renderer.height * _pixelsPerUnit; + if (renderer.overflowMode === OverflowMode.Overflow) { + height = lineHeight * lineCount; } - if (top !== -1) { - top = Math.max(0, top - 1); - bottom = Math.min(height - 1, bottom + 1); - left = Math.max(0, left - 1); - right = Math.min(width - 1, right + 1); - width = right - left + 1; - height = bottom - top + 1; - data = context.getImageData(left, top, width, height); + for (let i = 0; i < lineCount; ++i) { + const line = lines[i]; + let curWidth = 0; + let maxAscent = -1; + let maxDescent = -1; + + for (let j = 0, m = line.length; j < m; ++j) { + const charInfo = TextUtils._getCharInfo(line[j], fontString, charFont); + curWidth += charInfo.xAdvance; + const { offsetY } = charInfo; + const halfH = charInfo.h * 0.5; + const ascent = halfH + offsetY; + const descent = halfH - offsetY; + maxAscent < ascent && (maxAscent = ascent); + maxDescent < descent && (maxDescent = descent); + } + lineWidths[i] = curWidth; + lineMaxSizes[i] = { + ascent: maxAscent, + descent: maxDescent, + size: maxAscent + maxDescent + }; + if (curWidth > width) { + width = curWidth; + } } return { width, height, - data + lines, + lineWidths, + lineHeight, + lineMaxSizes }; } /** - * Get native font string. + * Get native font hash. * @param fontName - The font name * @param fontSize - The font size * @param style - The font style - * @returns The native font string + * @returns The native font hash */ - public static getNativeFontString(fontName: string, fontSize: number, style: FontStyle): string { - let str = style & FontStyle.Bold ? "bold " : ""; - style & FontStyle.Italic && (str += "italic "); + static getNativeFontHash(fontName: string, fontSize: number, style: FontStyle): string { + let str = style & FontStyle.Bold ? "bold" : ""; + style & FontStyle.Italic && (str += "italic"); // Check if font already contains strings if (!/([\"\'])[^\'\"]+\1/.test(fontName) && TextUtils._genericFontFamilies.indexOf(fontName) == -1) { - fontName = `"${fontName}"`; + fontName = `${fontName}`; } - str += `${fontSize}px ${fontName}`; + str += `${fontSize}px${fontName}`; return str; } - /** - * Update text. - * @param textMetrics - the text metrics object - * @param fontStr - the font string - * @param horizontalAlignment - the horizontal alignment - * @param verticalAlignment - the vertical alignment - */ - public static updateText( - textMetrics: TextMetrics, - fontStr: string, - horizontalAlignment: TextHorizontalAlignment, - verticalAlignment: TextVerticalAlignment - ): void { - const { canvas, context } = TextUtils.textContext(); - const { width, height } = textMetrics; - // reset canvas's width and height. - canvas.width = width; - canvas.height = height; - // clear canvas. - context.font = fontStr; - context.clearRect(0, 0, width, height); - // set canvas font info. - context.textBaseline = "middle"; - context.fillStyle = "#fff"; - - // draw lines. - const { lines, lineHeight, lineWidths } = textMetrics; - const halfLineHeight = lineHeight * 0.5; - for (let i = 0, l = lines.length; i < l; ++i) { - const lineWidth = lineWidths[i]; - const pos = TextUtils._tempVec2; - TextUtils._calculateLinePosition( - width, - height, - lineWidth, - lineHeight, - i, - l, - horizontalAlignment, - verticalAlignment, - pos - ); - const { x, y } = pos; - if (y + lineHeight >= 0 && y < height) { - context.fillText(lines[i], x, y + halfLineHeight); - } - } - } - /** * Update canvas with the data. * @param width - the new width of canvas @@ -332,7 +254,7 @@ export class TextUtils { * @param data - the new data of canvas * @returns the canvas after update */ - public static updateCanvas(width: number, height: number, data: ImageData): HTMLCanvasElement | OffscreenCanvas { + static updateCanvas(width: number, height: number, data: ImageData): HTMLCanvasElement | OffscreenCanvas { const { canvas, context } = TextUtils.textContext(); canvas.width = width; canvas.height = height; @@ -340,87 +262,124 @@ export class TextUtils { return canvas; } - private static _wordWrap(text: string, width: number, enableWrapping: boolean, fontString: string): Array { - const { context } = TextUtils.textContext(); - const { _maxWidth: maxWidth } = TextUtils; - const widthInPixel = width * TextUtils._pixelsPerUnit; - const wrapWidth = Math.min(widthInPixel, maxWidth); - const wrappedSubTexts = new Array(); - const subTexts = text.split(/(?:\r\n|\r|\n)/); + private static _measureFontOrChar(fontString: string, char: string = ""): FontSizeInfo | CharInfo { + const { canvas, context } = TextUtils.textContext(); context.font = fontString; + const measureString = char || TextUtils._measureString; + const width = context.measureText(measureString).width; + let baseline = Math.ceil(context.measureText(TextUtils._measureBaseline).width); + const height = baseline * TextUtils._heightMultiplier; + baseline = (TextUtils._baselineMultiplier * baseline) | 0; - for (let i = 0, n = subTexts.length; i < n; ++i) { - const subText = subTexts[i]; - const subWidth = Math.ceil(context.measureText(subText).width); - const needWrap = enableWrapping || subWidth > maxWidth; - if (needWrap) { - if (subWidth <= wrapWidth) { - wrappedSubTexts.push(subText); - } else { - let chars = ""; - let charsWidth = 0; - for (let j = 0, m = subText.length; j < m; ++j) { - const char = subText[j]; - const charWidth = Math.ceil(context.measureText(char).width); - if (charsWidth + charWidth > wrapWidth) { - // The width of text renderer is shorter than current char. - if (charsWidth === 0) { - wrappedSubTexts.push(char); - } else { - wrappedSubTexts.push(chars); - chars = char; - charsWidth = charWidth; - } - } else { - chars += char; - charsWidth += charWidth; - } - } - if (charsWidth > 0) { - wrappedSubTexts.push(chars); - } + canvas.width = width; + canvas.height = height; + + context.font = fontString; + context.fillStyle = "#000"; + context.clearRect(0, 0, width, height); + context.textBaseline = "middle"; + context.fillStyle = "#fff"; + context.fillText(measureString, 0, baseline); + + const imageData = context.getImageData(0, 0, width, height).data; + const len = imageData.length; + + let top = -1; + let bottom = -1; + let y; + let ascent = 0; + let descent = 0; + let size = 0; + + const integerW = canvas.width; + for (let i = 0; i < len; i += 4) { + if (imageData[i + 3] !== 0) { + const idx = i / 4; + y = ~~(idx / integerW); + + if (top === -1) { + top = y; + } + + if (y > bottom) { + bottom = y; } - } else { - wrappedSubTexts.push(subText); } } - return wrappedSubTexts; - } + if (top !== -1 && bottom !== -1) { + ascent = baseline - top; + descent = bottom - baseline + 1; + size = ascent + descent; + } + const sizeInfo = { ascent, descent, size }; - private static _calculateLinePosition( - width: number, - height: number, - lineWidth: number, - lineHeight: number, - index: number, - length: number, - horizontalAlignment: TextHorizontalAlignment, - verticalAlignment: TextVerticalAlignment, - out: Vector2 - ): void { - switch (verticalAlignment) { - case TextVerticalAlignment.Top: - out.y = index * lineHeight; - break; - case TextVerticalAlignment.Bottom: - out.y = height - (length - index) * lineHeight; - break; - default: - out.y = 0.5 * height - 0.5 * length * lineHeight + index * lineHeight; - break; + if (char) { + if (size > 0) { + const data = context.getImageData(0, top, width, size); + TextUtils.updateCanvas(width, size, data); + } + return { + x: 0, + y: 0, + w: width, + h: size, + offsetX: 0, + offsetY: (ascent - descent) * 0.5, + xAdvance: width, + u0: 0, + v0: 0, + u1: 0, + v1: 0, + ascent, + descent, + index: 0 + }; + } else { + return sizeInfo; } + } - switch (horizontalAlignment) { - case TextHorizontalAlignment.Left: - out.x = 0; - break; - case TextHorizontalAlignment.Right: - out.x = width - lineWidth; - break; - default: - out.x = (width - lineWidth) * 0.5; - break; + private static _getCharInfo(char: string, fontString: string, font: Font): CharInfo { + let charInfo = font._getCharInfo(char); + if (!charInfo) { + charInfo = TextUtils.measureChar(char, fontString); + font._uploadCharTexture(charInfo, TextUtils.textContext().canvas); + font._addCharInfo(char, charInfo); } + + return charInfo; } } + +/** + * @internal + * TextContext. + */ +export interface TextContext { + canvas: HTMLCanvasElement | OffscreenCanvas; + context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D; +} + +/** + * @internal + * FontSizeInfo. + */ +export interface FontSizeInfo { + ascent: number; + descent: number; + size: number; +} + +/** + * @internal + * TextMetrics. + */ +export interface TextMetrics { + width: number; + height: number; + lines: Array; + lineWidths: Array; + lineHeight: number; + lineMaxSizes?: Array; +} diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index c795ccf46d..9102f14c1f 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -1,5 +1,4 @@ import { ColorSpace } from "."; -import { DynamicTextAtlasManager } from "./2d/dynamic-atlas/DynamicTextAtlasManager"; import { ResourceManager } from "./asset/ResourceManager"; import { Event, EventDispatcher, Logger, Time } from "./base"; import { Canvas } from "./Canvas"; @@ -44,6 +43,8 @@ ShaderPool.init(); export class Engine extends EventDispatcher { /** @internal */ static _gammaMacro: ShaderMacro = Shader.getMacroByName("OASIS_COLORSPACE_GAMMA"); + /** @internal Conversion of space units to pixel units for 2D. */ + static _pixelsPerUnit: number = 100; /** Physics manager of Engine. */ readonly physicsManager: PhysicsManager; @@ -75,8 +76,6 @@ export class Engine extends EventDispatcher { _spriteMaskManager: SpriteMaskManager; /** @internal */ _macroCollection: ShaderMacroCollection = new ShaderMacroCollection(); - /** @internal */ - _dynamicTextAtlasManager: DynamicTextAtlasManager = new DynamicTextAtlasManager(this); protected _canvas: Canvas; diff --git a/packages/core/src/RenderPipeline/SpriteBatcher.ts b/packages/core/src/RenderPipeline/SpriteBatcher.ts index 3e6919424f..1f3cbd311c 100644 --- a/packages/core/src/RenderPipeline/SpriteBatcher.ts +++ b/packages/core/src/RenderPipeline/SpriteBatcher.ts @@ -32,9 +32,8 @@ export class SpriteBatcher extends Basic2DBatcher { return false; } - // Compare renderer property - const textureProperty = SpriteBatcher._textureProperty; - if (preRenderer.shaderData.getTexture(textureProperty) !== curRenderer.shaderData.getTexture(textureProperty)) { + // Compare texture + if (preElement.texture !== curElement.texture) { return false; } @@ -106,6 +105,8 @@ export class SpriteBatcher extends Basic2DBatcher { return; } + renderer.shaderData.setTexture(SpriteBatcher._textureProperty, spriteElement.texture); + program.bind(); program.groupingOtherUniformBlock(); program.uploadAll(program.sceneUniformBlock, sceneData); diff --git a/packages/core/src/RenderPipeline/SpriteElement.ts b/packages/core/src/RenderPipeline/SpriteElement.ts index 4b46ec8213..953a81f20b 100644 --- a/packages/core/src/RenderPipeline/SpriteElement.ts +++ b/packages/core/src/RenderPipeline/SpriteElement.ts @@ -1,15 +1,18 @@ import { RenderData2D } from "../2d/data/RenderData2D"; import { Material } from "../material/Material"; import { Renderer } from "../Renderer"; +import { Texture2D } from "../texture"; export class SpriteElement { component: Renderer; renderData: RenderData2D; material: Material; + texture: Texture2D; - setValue(component: Renderer, renderDate: RenderData2D, material: Material): void { + setValue(component: Renderer, renderDate: RenderData2D, material: Material, texture: Texture2D = null): void { this.component = component; this.renderData = renderDate; this.material = material; + this.texture = texture; } } diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index a0633b932c..154ba8fd74 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -3,6 +3,7 @@ import { BoolUpdateFlag } from "./BoolUpdateFlag"; import { deepClone, ignoreClone } from "./clone/CloneManager"; import { Component } from "./Component"; import { Entity } from "./Entity"; +import { ListenerUpdateFlag } from "./ListenerUpdateFlag"; import { UpdateFlagManager } from "./UpdateFlagManager"; /** @@ -545,6 +546,13 @@ export class Transform extends Component { return this._updateFlagManager.createFlag(BoolUpdateFlag); } + /** + * @intenral + */ + _registerWorldChangeListenser(): ListenerUpdateFlag { + return this._updateFlagManager.createFlag(ListenerUpdateFlag); + } + /** * @internal */ From 5879282c7712063c79553609aa45678213fa3225 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Fri, 8 Jul 2022 21:25:34 +0800 Subject: [PATCH 27/33] v0.8.0-alpha.2 --- lerna.json | 2 +- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- tests/package.json | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index 66ade2fb62..09c1671ea0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index 62f17743da..f7000d4a7e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.1" + "@oasis-engine/math": "0.8.0-alpha.2" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.1" + "@oasis-engine/design": "0.8.0-alpha.2" } } diff --git a/packages/design/package.json b/packages/design/package.json index b7bba317af..679be13481 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.1" + "@oasis-engine/math": "0.8.0-alpha.2" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 68378da0f0..9c8e32ca54 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.1" + "@oasis-engine/core": "0.8.0-alpha.2" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index d1f387ca0e..dfbda483de 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.1", - "@oasis-engine/draco": "0.8.0-alpha.1", - "@oasis-engine/math": "0.8.0-alpha.1", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.1" + "@oasis-engine/core": "0.8.0-alpha.2", + "@oasis-engine/draco": "0.8.0-alpha.2", + "@oasis-engine/math": "0.8.0-alpha.2", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.2" } } diff --git a/packages/math/package.json b/packages/math/package.json index 5280ab2086..6fbaf9897f 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index 98f80c2ff4..045578977e 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.1", - "@oasis-engine/loader": "0.8.0-alpha.1", - "@oasis-engine/math": "0.8.0-alpha.1", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.1" + "@oasis-engine/core": "0.8.0-alpha.2", + "@oasis-engine/loader": "0.8.0-alpha.2", + "@oasis-engine/math": "0.8.0-alpha.2", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.2" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index caf24f482c..92bad23578 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.1", - "oasis-engine": "0.8.0-alpha.1" + "@oasis-engine/design": "0.8.0-alpha.2", + "oasis-engine": "0.8.0-alpha.2" } } diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 7dc52bf351..187b7dd08f 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.1", - "oasis-engine": "0.8.0-alpha.1" + "@oasis-engine/design": "0.8.0-alpha.2", + "oasis-engine": "0.8.0-alpha.2" } } diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 040b174baa..3906c8aabc 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,10 +18,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.1", - "@oasis-engine/math": "0.8.0-alpha.1" + "@oasis-engine/core": "0.8.0-alpha.2", + "@oasis-engine/math": "0.8.0-alpha.2" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.1" + "@oasis-engine/design": "0.8.0-alpha.2" } } diff --git a/tests/package.json b/tests/package.json index 3e30b50724..e595f42df0 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,7 +1,7 @@ { "name": "@oasis-engine/tests", "private": true, - "version": "0.8.0-alpha.1", + "version": "0.8.0-alpha.2", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", From 64f1c624ebdaef50299682d2af35a11860c44787 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Fri, 8 Jul 2022 21:27:29 +0800 Subject: [PATCH 28/33] v0.8.0-alpha.3 --- lerna.json | 2 +- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- tests/package.json | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index 09c1671ea0..e1654e6caa 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index f7000d4a7e..34874fbd28 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.2" + "@oasis-engine/math": "0.8.0-alpha.3" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.2" + "@oasis-engine/design": "0.8.0-alpha.3" } } diff --git a/packages/design/package.json b/packages/design/package.json index 679be13481..6a588a4e53 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.2" + "@oasis-engine/math": "0.8.0-alpha.3" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 9c8e32ca54..1bb8d5d8e8 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.2" + "@oasis-engine/core": "0.8.0-alpha.3" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index dfbda483de..997a6c2d32 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.2", - "@oasis-engine/draco": "0.8.0-alpha.2", - "@oasis-engine/math": "0.8.0-alpha.2", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.2" + "@oasis-engine/core": "0.8.0-alpha.3", + "@oasis-engine/draco": "0.8.0-alpha.3", + "@oasis-engine/math": "0.8.0-alpha.3", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.3" } } diff --git a/packages/math/package.json b/packages/math/package.json index 6fbaf9897f..7ed47020b2 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index 045578977e..ca810ff938 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.2", - "@oasis-engine/loader": "0.8.0-alpha.2", - "@oasis-engine/math": "0.8.0-alpha.2", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.2" + "@oasis-engine/core": "0.8.0-alpha.3", + "@oasis-engine/loader": "0.8.0-alpha.3", + "@oasis-engine/math": "0.8.0-alpha.3", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.3" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index 92bad23578..0fac80c16f 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.2", - "oasis-engine": "0.8.0-alpha.2" + "@oasis-engine/design": "0.8.0-alpha.3", + "oasis-engine": "0.8.0-alpha.3" } } diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 187b7dd08f..e463dc72a6 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.2", - "oasis-engine": "0.8.0-alpha.2" + "@oasis-engine/design": "0.8.0-alpha.3", + "oasis-engine": "0.8.0-alpha.3" } } diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 3906c8aabc..8285884b52 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,10 +18,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.2", - "@oasis-engine/math": "0.8.0-alpha.2" + "@oasis-engine/core": "0.8.0-alpha.3", + "@oasis-engine/math": "0.8.0-alpha.3" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.2" + "@oasis-engine/design": "0.8.0-alpha.3" } } diff --git a/tests/package.json b/tests/package.json index e595f42df0..cbce095724 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,7 +1,7 @@ { "name": "@oasis-engine/tests", "private": true, - "version": "0.8.0-alpha.2", + "version": "0.8.0-alpha.3", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", From 3b34c763598fd417431ac1789b68669f26e5829f Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 11 Jul 2022 16:51:47 +0800 Subject: [PATCH 29/33] Optimization performance for `TextRenderer` to update world positions (#861) * refactor(text): optimization performance for `TextRenderer` to update world positions --- packages/core/src/2d/text/TextRenderer.ts | 48 ++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 0b24807043..c851eb9d73 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -22,6 +22,8 @@ import { ListenerUpdateFlag } from "../../ListenerUpdateFlag"; */ export class TextRenderer extends Renderer implements ICustomClone { private static _charRenderDataPool: CharRenderDataPool = new CharRenderDataPool(CharRenderData, 50); + private static _tempVec30: Vector3 = new Vector3(); + private static _tempVec31: Vector3 = new Vector3(); /** @internal */ @assignmentClone @@ -417,13 +419,49 @@ export class TextRenderer extends Renderer implements ICustomClone { } private _updatePosition(): void { - const worldMatrix = this.entity.transform.worldMatrix; + const { transform } = this.entity; + const e = transform.worldMatrix.elements; const charRenderDatas = this._charRenderDatas; + + // prettier-ignore + const e0 = e[0], e1 = e[1], e2 = e[2]; + // prettier-ignore + const e4 = e[4], e5 = e[5], e6 = e[6]; + // prettier-ignore + const e12 = e[12], e13 = e[13], e14 = e[14]; + + const up = TextRenderer._tempVec31.set(e4, e5, e6); + const right = TextRenderer._tempVec30.set(e0, e1, e2); + for (let i = 0, n = charRenderDatas.length; i < n; ++i) { - const { localPositions, renderData } = charRenderDatas[i]; - for (let j = 0; j < 4; ++j) { - Vector3.transformToVec3(localPositions[j], worldMatrix, renderData.positions[j]); - } + const charRenderData = charRenderDatas[i]; + const { localPositions } = charRenderData; + const { positions } = charRenderData.renderData; + + const { x: topLeftX, y: topLeftY } = localPositions[0]; + const bottomRight = localPositions[2]; + + // Top-Left + const worldPosition0 = positions[0]; + worldPosition0.x = topLeftX * e0 + topLeftY * e4 + e12; + worldPosition0.y = topLeftX * e1 + topLeftY * e5 + e13; + worldPosition0.z = topLeftX * e2 + topLeftY * e6 + e14; + + // Right offset + const worldPosition1 = positions[1]; + Vector3.scale(right, bottomRight.x - topLeftX, worldPosition1); + + // Top-Right + Vector3.add(worldPosition0, worldPosition1, worldPosition1); + + // Up offset + const worldPosition2 = positions[2]; + Vector3.scale(up, bottomRight.y - topLeftY, worldPosition2); + + // Bottom-Left + Vector3.add(worldPosition0, worldPosition2, positions[3]); + // Bottom-Right + Vector3.add(worldPosition1, worldPosition2, worldPosition2); } } From 8497a5233ac532fc4a4d220a549911fbec1b7fc0 Mon Sep 17 00:00:00 2001 From: AZhan Date: Mon, 11 Jul 2022 17:55:26 +0800 Subject: [PATCH 30/33] Fix `InputManager` bug (#863) * fix: `pointer` position bug * fix: `pointerMovingDelta` value bug * fix: input `onPointerXX` bug not follow `Camera` cullingMask --- packages/core/src/input/pointer/Pointer.ts | 2 - .../core/src/input/pointer/PointerManager.ts | 114 +++++++++--------- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/packages/core/src/input/pointer/Pointer.ts b/packages/core/src/input/pointer/Pointer.ts index 3539654b80..f9e374941e 100644 --- a/packages/core/src/input/pointer/Pointer.ts +++ b/packages/core/src/input/pointer/Pointer.ts @@ -17,8 +17,6 @@ export class Pointer { /** @internal */ _uniqueID: number; - /** @internal */ - _needUpdate: boolean = true; /** * @internal diff --git a/packages/core/src/input/pointer/PointerManager.ts b/packages/core/src/input/pointer/PointerManager.ts index b453bf297e..122a09795e 100644 --- a/packages/core/src/input/pointer/PointerManager.ts +++ b/packages/core/src/input/pointer/PointerManager.ts @@ -53,6 +53,7 @@ export class PointerManager implements IInput { private _keyEventCount: number = 0; private _needOverallPointers: boolean = false; private _hadListener: boolean = false; + private _lastPositionFrameCount: number = 0; /** * Create a PointerManager. @@ -216,7 +217,6 @@ export class PointerManager implements IInput { pointer = pointerPool[i] = new Pointer(i); } pointer._uniqueID = pointerId; - pointer._needUpdate = true; pointer.position.set(x, y); pointer.phase = phase; pointers.splice(i, 0, pointer); @@ -231,7 +231,6 @@ export class PointerManager implements IInput { private _updatePointer(pointerIndex: number, x: number, y: number, phase: PointerPhase): void { const updatedPointer = this._pointers[pointerIndex]; updatedPointer.position.set(x, y); - updatedPointer._needUpdate = true; updatedPointer.phase = phase; } @@ -245,79 +244,71 @@ export class PointerManager implements IInput { _downList: downList } = this; let activePointerCount = pointers.length; + const pixelRatioW = this._canvas.width / this._htmlCanvas.clientWidth; + const pixelRatioH = this._canvas.height / this._htmlCanvas.clientHeight; const nativeEventsLen = nativeEvents.length; - if (nativeEventsLen > 0) { - for (let i = 0; i < nativeEventsLen; i++) { - const evt = nativeEvents[i]; - const pointerButton: PointerButton = evt.button | PointerButton.Primary; - const pointerIndex = this._getIndexByPointerID(evt.pointerId); - switch (evt.type) { - case "pointerdown": - if (pointerIndex === -1) { - this._addPointer(evt.pointerId, evt.offsetX, evt.offsetY, PointerPhase.Down); - activePointerCount++; - } else { - this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Down); - } - activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Down); - downList.add(pointerButton); - downMap[pointerButton] = frameCount; - break; - case "pointerup": - if (pointerIndex >= 0) { - this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Up); - activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Up); - } - upList.add(pointerButton); - upMap[pointerButton] = frameCount; - break; - case "pointermove": - if (pointerIndex === -1) { - this._addPointer(evt.pointerId, evt.offsetX, evt.offsetY, PointerPhase.Move); - activePointerCount++; - } else { - this._updatePointer(pointerIndex, evt.offsetX, evt.offsetY, PointerPhase.Move); - } - break; - case "pointerout": - if (pointerIndex >= 0) { - this._removePointer(pointerIndex); - --activePointerCount === 0 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Leave); - this._needOverallPointers = true; - } - break; - } + for (let i = 0; i < nativeEventsLen; i++) { + const evt = nativeEvents[i]; + const pointerButton: PointerButton = evt.button | PointerButton.Primary; + const pointerIndex = this._getIndexByPointerID(evt.pointerId); + switch (evt.type) { + case "pointerdown": + if (pointerIndex === -1) { + this._addPointer(evt.pointerId, evt.offsetX * pixelRatioW, evt.offsetY * pixelRatioH, PointerPhase.Down); + activePointerCount++; + } else { + this._updatePointer(pointerIndex, evt.offsetX * pixelRatioW, evt.offsetY * pixelRatioH, PointerPhase.Down); + } + activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Down); + downList.add(pointerButton); + downMap[pointerButton] = frameCount; + break; + case "pointerup": + if (pointerIndex >= 0) { + this._updatePointer(pointerIndex, evt.offsetX * pixelRatioW, evt.offsetY * pixelRatioH, PointerPhase.Up); + activePointerCount === 1 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Up); + } + upList.add(pointerButton); + upMap[pointerButton] = frameCount; + break; + case "pointermove": + if (pointerIndex === -1) { + this._addPointer(evt.pointerId, evt.offsetX * pixelRatioW, evt.offsetY * pixelRatioH, PointerPhase.Move); + activePointerCount++; + } else { + this._updatePointer(pointerIndex, evt.offsetX * pixelRatioW, evt.offsetY * pixelRatioH, PointerPhase.Move); + } + break; + case "pointerout": + if (pointerIndex >= 0) { + this._removePointer(pointerIndex); + --activePointerCount === 0 && (keyEventList[this._keyEventCount++] = PointerKeyEvent.Leave); + this._needOverallPointers = true; + } + break; } - this._buttons = nativeEvents[nativeEventsLen - 1].buttons; } + this._buttons = nativeEvents[nativeEventsLen - 1].buttons; const pointerCount = pointers.length; if (pointerCount > 0) { - const { _canvas: canvas, _currentPosition: currentPosition, _htmlCanvas: htmlCanvas } = this; + const { _currentPosition: currentPosition } = this; const { x: lastX, y: lastY } = currentPosition; - const pixelRatioWidth = canvas.width / htmlCanvas.clientWidth; - const pixelRatioHeight = canvas.height / htmlCanvas.clientHeight; if (activePointerCount === 0) { // Get the pointer coordinates when leaving, and use it to correctly dispatch the click event. const lastNativeEvent = nativeEvents[nativeEventsLen - 1]; - currentPosition.set(lastNativeEvent.offsetX * pixelRatioWidth, lastNativeEvent.offsetY * pixelRatioHeight); + currentPosition.set(lastNativeEvent.offsetX * pixelRatioW, lastNativeEvent.offsetY * pixelRatioH); } else { currentPosition.set(0, 0); for (let i = 0; i < pointerCount; i++) { - const pointer = pointers[i]; - const { position } = pointer; - if (pointer._needUpdate) { - position.set(position.x * pixelRatioWidth, position.y * pixelRatioHeight); - pointer._needUpdate = false; - } - currentPosition.add(position); + currentPosition.add(pointers[i].position); } currentPosition.scale(1 / pointerCount); } // Update pointer moving delta. - // Todo: Need to consider if the last coordinate is(0, 0). - if (lastX !== 0 || lastY !== 0) { + if (this._lastPositionFrameCount === frameCount - 1) { this._movingDelta.set(currentPosition.x - lastX, currentPosition.y - lastY); } + this._lastPositionFrameCount = frameCount; } nativeEvents.length = 0; } @@ -337,7 +328,14 @@ export class PointerManager implements IInput { if (x >= vpX && y >= vpY && x - vpX <= vpW && y - vpY <= vpH) { point.set((x - vpX) / vpW, (y - vpY) / vpH); // TODO: Only check which colliders have listened to the input. - if (this._engine.physicsManager.raycast(camera.viewportPointToRay(point, ray), hitResult)) { + if ( + this._engine.physicsManager.raycast( + camera.viewportPointToRay(point, ray), + Number.MAX_VALUE, + camera.cullingMask, + hitResult + ) + ) { return hitResult.entity; } else if (camera.clearFlags & CameraClearFlags.Color) { return null; From 1640447d4323d1ccb1ca2232c0bdf3abe3807cd4 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 11 Jul 2022 18:49:40 +0800 Subject: [PATCH 31/33] fix(2d): `SpriteRenderer` can not show error (#865) --- packages/core/src/RenderPipeline/SpriteBatcher.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/RenderPipeline/SpriteBatcher.ts b/packages/core/src/RenderPipeline/SpriteBatcher.ts index 1f3cbd311c..b13775f6f3 100644 --- a/packages/core/src/RenderPipeline/SpriteBatcher.ts +++ b/packages/core/src/RenderPipeline/SpriteBatcher.ts @@ -105,7 +105,7 @@ export class SpriteBatcher extends Basic2DBatcher { return; } - renderer.shaderData.setTexture(SpriteBatcher._textureProperty, spriteElement.texture); + spriteElement.texture && renderer.shaderData.setTexture(SpriteBatcher._textureProperty, spriteElement.texture); program.bind(); program.groupingOtherUniformBlock(); From 31fc74e6daa736743acf4929822b9bad3a54e1c6 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Mon, 11 Jul 2022 18:51:56 +0800 Subject: [PATCH 32/33] v0.8.0-alpha.4 --- lerna.json | 2 +- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- tests/package.json | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index e1654e6caa..a60a9fdae4 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index 34874fbd28..d54e83dee1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.3" + "@oasis-engine/math": "0.8.0-alpha.4" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.3" + "@oasis-engine/design": "0.8.0-alpha.4" } } diff --git a/packages/design/package.json b/packages/design/package.json index 6a588a4e53..d7e8ed5422 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.3" + "@oasis-engine/math": "0.8.0-alpha.4" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 1bb8d5d8e8..8d8cc32f28 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.3" + "@oasis-engine/core": "0.8.0-alpha.4" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index 997a6c2d32..e033017f50 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.3", - "@oasis-engine/draco": "0.8.0-alpha.3", - "@oasis-engine/math": "0.8.0-alpha.3", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.3" + "@oasis-engine/core": "0.8.0-alpha.4", + "@oasis-engine/draco": "0.8.0-alpha.4", + "@oasis-engine/math": "0.8.0-alpha.4", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.4" } } diff --git a/packages/math/package.json b/packages/math/package.json index 7ed47020b2..60ea3a8a95 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index ca810ff938..c259bf497e 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.3", - "@oasis-engine/loader": "0.8.0-alpha.3", - "@oasis-engine/math": "0.8.0-alpha.3", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.3" + "@oasis-engine/core": "0.8.0-alpha.4", + "@oasis-engine/loader": "0.8.0-alpha.4", + "@oasis-engine/math": "0.8.0-alpha.4", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.4" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index 0fac80c16f..b777c75d39 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.3", - "oasis-engine": "0.8.0-alpha.3" + "@oasis-engine/design": "0.8.0-alpha.4", + "oasis-engine": "0.8.0-alpha.4" } } diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index e463dc72a6..15fb97564e 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.3", - "oasis-engine": "0.8.0-alpha.3" + "@oasis-engine/design": "0.8.0-alpha.4", + "oasis-engine": "0.8.0-alpha.4" } } diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 8285884b52..4c1e4c6641 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,10 +18,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.3", - "@oasis-engine/math": "0.8.0-alpha.3" + "@oasis-engine/core": "0.8.0-alpha.4", + "@oasis-engine/math": "0.8.0-alpha.4" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.3" + "@oasis-engine/design": "0.8.0-alpha.4" } } diff --git a/tests/package.json b/tests/package.json index cbce095724..586cef77e3 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,7 +1,7 @@ { "name": "@oasis-engine/tests", "private": true, - "version": "0.8.0-alpha.3", + "version": "0.8.0-alpha.4", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js", From 6707b998dc8e7c07625fed4f9bfe314b87d89562 Mon Sep 17 00:00:00 2001 From: GuoLei1990 Date: Mon, 11 Jul 2022 18:53:24 +0800 Subject: [PATCH 33/33] v0.8.0-alpha.5 --- lerna.json | 2 +- packages/core/package.json | 6 +++--- packages/design/package.json | 4 ++-- packages/draco/package.json | 4 ++-- packages/loader/package.json | 10 +++++----- packages/math/package.json | 2 +- packages/oasis-engine/package.json | 10 +++++----- packages/physics-lite/package.json | 6 +++--- packages/physics-physx/package.json | 6 +++--- packages/rhi-webgl/package.json | 8 ++++---- tests/package.json | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index a60a9fdae4..c75d1b3715 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "npmClient": "npm", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "bootstrap": { "hoist": true }, diff --git a/packages/core/package.json b/packages/core/package.json index d54e83dee1..85558992ef 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/core", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.4" + "@oasis-engine/math": "0.8.0-alpha.5" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.4" + "@oasis-engine/design": "0.8.0-alpha.5" } } diff --git a/packages/design/package.json b/packages/design/package.json index d7e8ed5422..bd173e4bf8 100755 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/design", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ ], "types": "types/index.d.ts", "dependencies": { - "@oasis-engine/math": "0.8.0-alpha.4" + "@oasis-engine/math": "0.8.0-alpha.5" } } diff --git a/packages/draco/package.json b/packages/draco/package.json index 8d8cc32f28..608067f63d 100644 --- a/packages/draco/package.json +++ b/packages/draco/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/draco", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -17,6 +17,6 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.4" + "@oasis-engine/core": "0.8.0-alpha.5" } } diff --git a/packages/loader/package.json b/packages/loader/package.json index e033017f50..235abec405 100755 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/loader", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.4", - "@oasis-engine/draco": "0.8.0-alpha.4", - "@oasis-engine/math": "0.8.0-alpha.4", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.4" + "@oasis-engine/core": "0.8.0-alpha.5", + "@oasis-engine/draco": "0.8.0-alpha.5", + "@oasis-engine/math": "0.8.0-alpha.5", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.5" } } diff --git a/packages/math/package.json b/packages/math/package.json index 60ea3a8a95..5349df8f2b 100755 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/math", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/oasis-engine/package.json b/packages/oasis-engine/package.json index c259bf497e..3922f8cefb 100755 --- a/packages/oasis-engine/package.json +++ b/packages/oasis-engine/package.json @@ -1,6 +1,6 @@ { "name": "oasis-engine", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,9 +18,9 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.4", - "@oasis-engine/loader": "0.8.0-alpha.4", - "@oasis-engine/math": "0.8.0-alpha.4", - "@oasis-engine/rhi-webgl": "0.8.0-alpha.4" + "@oasis-engine/core": "0.8.0-alpha.5", + "@oasis-engine/loader": "0.8.0-alpha.5", + "@oasis-engine/math": "0.8.0-alpha.5", + "@oasis-engine/rhi-webgl": "0.8.0-alpha.5" } } diff --git a/packages/physics-lite/package.json b/packages/physics-lite/package.json index b777c75d39..8c537c72e2 100644 --- a/packages/physics-lite/package.json +++ b/packages/physics-lite/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-lite", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.4", - "oasis-engine": "0.8.0-alpha.4" + "@oasis-engine/design": "0.8.0-alpha.5", + "oasis-engine": "0.8.0-alpha.5" } } diff --git a/packages/physics-physx/package.json b/packages/physics-physx/package.json index 15fb97564e..934cda8d06 100644 --- a/packages/physics-physx/package.json +++ b/packages/physics-physx/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/physics-physx", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -19,7 +19,7 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/design": "0.8.0-alpha.4", - "oasis-engine": "0.8.0-alpha.4" + "@oasis-engine/design": "0.8.0-alpha.5", + "oasis-engine": "0.8.0-alpha.5" } } diff --git a/packages/rhi-webgl/package.json b/packages/rhi-webgl/package.json index 4c1e4c6641..94f9b7004c 100755 --- a/packages/rhi-webgl/package.json +++ b/packages/rhi-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@oasis-engine/rhi-webgl", - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -18,10 +18,10 @@ "types/**/*" ], "dependencies": { - "@oasis-engine/core": "0.8.0-alpha.4", - "@oasis-engine/math": "0.8.0-alpha.4" + "@oasis-engine/core": "0.8.0-alpha.5", + "@oasis-engine/math": "0.8.0-alpha.5" }, "devDependencies": { - "@oasis-engine/design": "0.8.0-alpha.4" + "@oasis-engine/design": "0.8.0-alpha.5" } } diff --git a/tests/package.json b/tests/package.json index 586cef77e3..4f5b9efaf5 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,7 +1,7 @@ { "name": "@oasis-engine/tests", "private": true, - "version": "0.8.0-alpha.4", + "version": "0.8.0-alpha.5", "license": "MIT", "main": "dist/main.js", "module": "dist/module.js",