/** * @author Yannick Deubel (https://github.com/yandeu) * @copyright Copyright (c) 2020 Yannick Deubel; Project Url: https://github.com/enable3d/enable3d * @description This is a modified version of the original code from Kevin Lee */ /** * @author Kevin Lee (https://github.com/InfiniteLee) * @copyright Copyright (c) 2019 Kevin Lee; Project Url: https://github.com/InfiniteLee/ammo-debug-drawer * @license {@link https://github.com/InfiniteLee/ammo-debug-drawer/blob/master/LICENSE|MPL-2.0} */ import { BufferAttribute, BufferGeometry, LineBasicMaterial, LineSegments, Scene, StaticDrawUsage } from 'three' const AmmoDebugConstants = { NoDebug: 0, DrawWireframe: 1, DrawAabb: 2, DrawFeaturesText: 4, DrawContactPoints: 8, NoDeactivation: 16, NoHelpText: 32, DrawText: 64, ProfileTimings: 128, EnableSatComparison: 256, DisableBulletLCP: 512, EnableCCD: 1024, DrawConstraints: 1 << 11, //2048 DrawConstraintLimits: 1 << 12, //4096 FastWireframe: 1 << 13, //8192 DrawNormals: 1 << 14, //16384 DrawOnTop: 1 << 15, //32768 MAX_DEBUG_DRAW_MODE: 0xffffffff } /** * An implementation of the btIDebugDraw interface in Ammo.js, for debug rendering of Ammo shapes */ class DebugDrawer { constructor(scene, world, options = {}) { this.scene = scene; this.world = world; this.options = options; this.debugDrawMode = options.debugDrawMode || AmmoDebugConstants.DrawWireframe; const drawOnTop = this.debugDrawMode & AmmoDebugConstants.DrawOnTop || false; const maxBufferSize = options.maxBufferSize || 1000000; this.geometry = new BufferGeometry() const vertices = new Float32Array(maxBufferSize * 3) const colors = new Float32Array(maxBufferSize * 3) /* I do not know the difference, just using the first one. export const StaticDrawUsage: Usage; export const DynamicDrawUsage: Usage; export const StreamDrawUsage: Usage; export const StaticReadUsage: Usage; export const DynamicReadUsage: Usage; export const StreamReadUsage: Usage; export const StaticCopyUsage: Usage; export const DynamicCopyUsage: Usage; export const StreamCopyUsage: Usage; */ this.geometry.setAttribute('position', new BufferAttribute(vertices, 3).setUsage(StaticDrawUsage)) this.geometry.setAttribute('color', new BufferAttribute(colors, 3).setUsage(StaticDrawUsage)) this.index = 0 const material = new LineBasicMaterial({ vertexColors: true, depthTest: !drawOnTop }); this.mesh = new LineSegments(this.geometry, material); if (drawOnTop) this.mesh.renderOrder = 999; this.mesh.frustumCulled = false; this.enabled = false; this.debugDrawer = new Ammo.DebugDrawer(); this.debugDrawer.drawLine = this.drawLine.bind(this); this.debugDrawer.drawContactPoint = this.drawContactPoint.bind(this); this.debugDrawer.reportErrorWarning = this.reportErrorWarning.bind(this); this.debugDrawer.draw3dText = this.draw3dText.bind(this); this.debugDrawer.setDebugMode = this.setDebugMode.bind(this); this.debugDrawer.getDebugMode = this.getDebugMode.bind(this); this.world.setDebugDrawer(this.debugDrawer); } enable() { this.enabled = true; this.scene.add(this.mesh); } disable() { this.enabled = false; this.scene.remove(this.mesh); } update() { if (!this.enabled) { return; } if (this.index != 0) { // @ts-ignore this.geometry.attributes.position.needsUpdate = true; // @ts-ignore this.geometry.attributes.color.needsUpdate = true; } this.index = 0; this.world.debugDrawWorld(); this.geometry.setDrawRange(0, this.index); } drawLine(from, to, color) { // @ts-ignore const heap = Ammo.HEAPF32; const r = heap[(color + 0) / 4]; const g = heap[(color + 4) / 4]; const b = heap[(color + 8) / 4]; const fromX = heap[(from + 0) / 4]; const fromY = heap[(from + 4) / 4]; const fromZ = heap[(from + 8) / 4]; this.geometry.attributes.position.setXYZ(this.index, fromX, fromY, fromZ); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); const toX = heap[(to + 0) / 4]; const toY = heap[(to + 4) / 4]; const toZ = heap[(to + 8) / 4]; this.geometry.attributes.position.setXYZ(this.index, toX, toY, toZ); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); } //TODO: figure out how to make lifeTime work drawContactPoint(pointOnB, normalOnB, distance, _lifeTime, color) { // @ts-ignore const heap = Ammo.HEAPF32; const r = heap[(color + 0) / 4]; const g = heap[(color + 4) / 4]; const b = heap[(color + 8) / 4]; const x = heap[(pointOnB + 0) / 4]; const y = heap[(pointOnB + 4) / 4]; const z = heap[(pointOnB + 8) / 4]; this.geometry.attributes.position.setXYZ(this.index, x, y, z); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); const dx = heap[(normalOnB + 0) / 4] * distance; const dy = heap[(normalOnB + 4) / 4] * distance; const dz = heap[(normalOnB + 8) / 4] * distance; this.geometry.attributes.position.setXYZ(this.index, x + dx, y + dy, z + dz); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); } reportErrorWarning(warningString) { // eslint-disable-next-line no-prototype-builtins if (Ammo.hasOwnProperty('Pointer_stringify')) { // @ts-ignore console.warn(Ammo.Pointer_stringify(warningString)); } else if (!this.warnedOnce) { this.warnedOnce = true; console.warn("Cannot print warningString, please rebuild Ammo.js using 'debug' flag"); } } draw3dText(_location, _textString) { //TODO console.warn('TODO: draw3dText'); } setDebugMode(debugMode) { this.debugDrawMode = debugMode; } getDebugMode() { return this.debugDrawMode; } } export default DebugDrawer