module BABYLON.Debug { /** * Used to show the physics impostor around the specific mesh */ export class PhysicsViewer { /** @hidden */ protected _impostors: Array> = []; /** @hidden */ protected _meshes: Array> = []; /** @hidden */ protected _scene: Nullable; /** @hidden */ protected _numMeshes = 0; /** @hidden */ protected _physicsEnginePlugin: Nullable; private _renderFunction: () => void; private _debugBoxMesh: Mesh; private _debugSphereMesh: Mesh; private _debugMaterial: StandardMaterial; /** * Creates a new PhysicsViewer * @param scene defines the hosting scene */ constructor(scene: Scene) { this._scene = scene || Engine.LastCreatedScene; let physicEngine = this._scene.getPhysicsEngine(); if (physicEngine) { this._physicsEnginePlugin = physicEngine.getPhysicsPlugin(); } } /** @hidden */ protected _updateDebugMeshes(): void { var plugin = this._physicsEnginePlugin; for (var i = 0; i < this._numMeshes; i++) { let impostor = this._impostors[i]; if (!impostor) { continue; } if (impostor.isDisposed) { this.hideImpostor(this._impostors[i--]); } else { let mesh = this._meshes[i]; if (mesh && plugin) { plugin.syncMeshWithImpostor(mesh, impostor); } } } } /** * Renders a specified physic impostor * @param impostor defines the impostor to render */ public showImpostor(impostor: PhysicsImpostor): void { if (!this._scene) { return; } for (var i = 0; i < this._numMeshes; i++) { if (this._impostors[i] == impostor) { return; } } var debugMesh = this._getDebugMesh(impostor, this._scene); if (debugMesh) { this._impostors[this._numMeshes] = impostor; this._meshes[this._numMeshes] = debugMesh; if (this._numMeshes === 0) { this._renderFunction = this._updateDebugMeshes.bind(this); this._scene.registerBeforeRender(this._renderFunction); } this._numMeshes++; } } /** * Hides a specified physic impostor * @param impostor defines the impostor to hide */ public hideImpostor(impostor: Nullable) { if (!impostor || !this._scene) { return; } var removed = false; for (var i = 0; i < this._numMeshes; i++) { if (this._impostors[i] == impostor) { let mesh = this._meshes[i]; if (!mesh) { continue; } this._scene.removeMesh(mesh); mesh.dispose(); this._numMeshes--; if (this._numMeshes > 0) { this._meshes[i] = this._meshes[this._numMeshes]; this._impostors[i] = this._impostors[this._numMeshes]; this._meshes[this._numMeshes] = null; this._impostors[this._numMeshes] = null; } else { this._meshes[0] = null; this._impostors[0] = null; } removed = true; break; } } if (removed && this._numMeshes === 0) { this._scene.unregisterBeforeRender(this._renderFunction); } } private _getDebugMaterial(scene: Scene): Material { if (!this._debugMaterial) { this._debugMaterial = new StandardMaterial('', scene); this._debugMaterial.wireframe = true; } return this._debugMaterial; } private _getDebugBoxMesh(scene: Scene): AbstractMesh { if (!this._debugBoxMesh) { this._debugBoxMesh = MeshBuilder.CreateBox('physicsBodyBoxViewMesh', { size: 1 }, scene); this._debugBoxMesh.renderingGroupId = 1; this._debugBoxMesh.rotationQuaternion = Quaternion.Identity(); this._debugBoxMesh.material = this._getDebugMaterial(scene); scene.removeMesh(this._debugBoxMesh); } return this._debugBoxMesh.createInstance('physicsBodyBoxViewInstance'); } private _getDebugSphereMesh(scene: Scene): AbstractMesh { if (!this._debugSphereMesh) { this._debugSphereMesh = MeshBuilder.CreateSphere('physicsBodySphereViewMesh', { diameter: 1 }, scene); this._debugSphereMesh.renderingGroupId = 1; this._debugSphereMesh.rotationQuaternion = Quaternion.Identity(); this._debugSphereMesh.material = this._getDebugMaterial(scene); scene.removeMesh(this._debugSphereMesh); } return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance'); } private _getDebugMesh(impostor: PhysicsImpostor, scene: Scene): Nullable { var mesh: Nullable = null; if (impostor.type == PhysicsImpostor.BoxImpostor) { mesh = this._getDebugBoxMesh(scene); impostor.getBoxSizeToRef(mesh.scaling); } else if (impostor.type == PhysicsImpostor.SphereImpostor) { mesh = this._getDebugSphereMesh(scene); var radius = impostor.getRadius(); mesh.scaling.x = radius * 2; mesh.scaling.y = radius * 2; mesh.scaling.z = radius * 2; } return mesh; } /** Releases all resources */ public dispose() { for (var i = 0; i < this._numMeshes; i++) { this.hideImpostor(this._impostors[i]); } if (this._debugBoxMesh) { this._debugBoxMesh.dispose(); } if (this._debugSphereMesh) { this._debugSphereMesh.dispose(); } if (this._debugMaterial) { this._debugMaterial.dispose(); } this._impostors.length = 0; this._scene = null; this._physicsEnginePlugin = null; } } }