UNPKG

nadesiko3

Version:
1,672 lines (1,634 loc) 56.5 kB
/** * PluginWeykTurtle3D * 3d turtle graphics plugin */ import type { NakoSystem as NakoSystemBase } from '../core/src/plugin_api.mjs' import { ThreeUtil } from './plugin_three.mjs' import type { THREENS } from './plugin_three.mjs' declare global { interface Navigator { nako3: { addPluginObject: (name: string, obj: object) => {} } } interface Window { THREE?: THREENS.THREE } } interface NakoSystem extends NakoSystemBase { tags: { weykturtle3d?: WeykTurtle3DSystem } } type CallbackType<T> = (a:T) => void type NumericArray3 = [ number, number, number ] type NakoRumtimeName = 'wnako'|'cnako' interface NakoVariables { type: 'const'|'var' value: any } interface NakoFunction { type: 'func' josi: []|string[][] asyncFn?: boolean pure?: boolean fn: any return_none?: boolean } interface NakoMeta { type: 'const' value: { pluginName: string description: string pluginVersion: string nakoRuntime: NakoRumtimeName[] nakoVersion: string } } interface NakoPluginObject { [ index: string]: NakoVariables|NakoFunction|NakoMeta } class DrawLineEventArgs { v1: THREENS.Vector3 v2: THREENS.Vector3 width: number color: THREENS.Color constructor (v1: THREENS.Vector3, v2: THREENS.Vector3, width: number, color: THREENS.Color) { this.v1 = v1 this.v2 = v2 this.width = width this.color = color } } interface Turtle3DEventMap { modelChanged: CustomEvent<void> drawLine: CustomEvent<DrawLineEventArgs> } interface Turtle3D extends EventTarget { addEventListener<K extends keyof Turtle3DEventMap>( type: K, listener: ((this: Turtle3D, evt: Turtle3DEventMap[K]) => any) | null, options?: boolean | EventListenerOptions,): void addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void dispatchEvent<K extends keyof Turtle3DEventMap>(evt: Turtle3DEventMap[K]): boolean removeListener<K extends keyof Turtle3DEventMap>( type: K, listener: (this: Turtle3D, evt: Turtle3DEventMap[K]) => any, options?: boolean | EventListenerOptions,): void removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void } class CommandPromise { resolve: (result:any) => void reject: (err:Error) => void command: Command constructor (command: Command, resolve: (result: any) => void, reject: (err: Error) => void) { this.command = command this.resolve = resolve this.reject = reject } } class Command { } class CommandHome extends Command { cmd: string = 'home' mode: 'set'|'jump' constructor (mode: 'set'|'jump') { super() this.mode = mode } } class CommandJump extends Command { cmd: string = 'jump' v: THREENS.Vector3 constructor (v: THREENS.Vector3) { super() this.v = v } } class CommandMoveAbsolute extends Command { cmd: string = 'move' v: THREENS.Vector3 constructor (v: THREENS.Vector3) { super() this.v = v } } class CommandAngle extends Command { cmd: string = 'angle' angle: THREENS.EulerArray constructor (angle: THREENS.EulerArray) { super() this.angle = angle } } type MoveDirection = 'f'|'b'|'u'|'d'|'l'|'r' type RotateDirection = 'u'|'d'|'l'|'r' type RollDirection = 'l'|'r' class CommandMoveDirection extends Command { cmd: string = 'slide' direction: MoveDirection length: number constructor (dir: MoveDirection, l: number) { super() this.direction = dir this.length = l } } class CommandRotate extends Command { cmd: string = 'rotate' direction: RotateDirection angle: number constructor (dir: RotateDirection, a: number) { super() this.direction = dir this.angle = a } } class CommandRoll extends Command { cmd: string = 'roll' direction: RollDirection angle: number constructor (dir: RollDirection, a: number) { super() this.direction = dir this.angle = a } } class CommandPenEnable extends Command { cmd: string = 'pen' subcmd: string = 'enable' enable: boolean constructor (enable: boolean) { super() this.enable = enable } } class CommandPenColor extends Command { cmd: string = 'pen' subcmd: string = 'color' color: THREENS.Color constructor (color: THREENS.Color) { super() this.color = color } } class CommandPenWidth extends Command { cmd: string = 'pen' subcmd: string = 'width' width: number constructor (width: number) { super() this.width = width } } class CommandVisible extends Command { cmd: string = 'attr' subcmd: string = 'visible' visible: boolean constructor (visible: boolean) { super() this.visible = visible } } class CommandModel extends Command { cmd: string = 'attr' subcmd: string = 'model' model: any constructor (model: any) { super() this.model = model } } class Turtle3D extends EventTarget { private three: THREENS.THREE id: number obj: THREENS.Object3D disposal: boolean home: { position: THREENS.Vector3, quaternion: THREENS.Quaternion } color: THREENS.Color lineWidth: number flagDown: boolean flagLoaded: boolean f_visible: boolean macros: CommandPromise[] constructor(three: THREENS.THREE, id: number) { super() this.three = three this.id = id const modelBase = new three.Group() this.obj = modelBase this.home = { position: new three.Vector3(0, 0, 0), quaternion: new three.Quaternion() } this.color = new three.Color(0xffffff) this.disposal = false this.lineWidth = 4 this.flagDown = true this.flagLoaded = false this.f_visible = true this.macros = [] this.home.position.copy(modelBase.position) this.home.quaternion.copy(modelBase.quaternion) } clear (): void { // 未実行ジョブのPromiseを全て完了にする for (const job of this.macros) { job.resolve(0) } this.macros = [] // ジョブをクリア // かめのモデルをカメから削除 this.discardModel() this.f_visible = true this.obj.visible = true } discardModel (): void { if (this.disposal) { ThreeUtil.disposeChildObject(this.obj) this.disposal = false } else { this.obj.remove(this.obj.children[0]) } this.flagLoaded = false } loadTurtle (model: THREENS.Object3D|string) { if (this.isObject3D(model)) { this.discardModel() this.obj.add(model) this.disposal = false this.flagLoaded = true this.raiseModelChanged() return } const url = model if (url.length === 0) { this.discardModel() this.obj.add(this.createDefaultTurtle()) this.disposal = true this.flagLoaded = true this.raiseModelChanged() return } const loader = new this.three.ObjectLoader() loader.load(url, (obj: THREENS.Object3D) => { this.discardModel() this.obj.add(obj) this.disposal = true this.flagLoaded = true this.raiseModelChanged() }, (xhr: XMLHttpRequest) => { // nothing }, (xhr: XMLHttpRequest) => { this.discardModel() this.f_visible = false this.obj.visible = false this.raiseModelChanged() }) } doMacro (noWait: boolean): boolean { if (!this.flagLoaded && !noWait) { return true } const que = this.macros.shift() if (typeof que === 'undefined') { return false } const m = que instanceof CommandPromise ? que.command : que if (m instanceof CommandJump) { // 起点を移動する this.obj.position.copy(m.v) } else if (m instanceof CommandMoveAbsolute) { const v1 = this.obj.position.clone() const v2 = m.v // 線を引く this.line(v1, v2) // カメの角度を変更 this.obj.lookAt(v2) const headup90 = new this.three.Quaternion() const axisX = new this.three.Vector3(1, 0, 0) headup90.setFromAxisAngle(axisX, Math.PI / 2) this.obj.quaternion.multiply(headup90) // カメを移動 this.obj.position.copy(v2) } else if (m instanceof CommandMoveDirection) { const dir = m.direction const l = m.length * ((dir === 'b') ? -1 : 1) const v1 = this.obj.position.clone() const v2 =new this.three.Vector3(0, l, 0) if (dir === 'f' || dir === 'b') { v2.applyQuaternion(this.obj.quaternion) } else { // u const modifier = new this.three.Quaternion() const target = this.obj.quaternion.clone() if (dir === 'u' || dir === 'd') { const axis = new this.three.Vector3(1, 0, 0) if (dir === 'u') { modifier.setFromAxisAngle(axis, (-90) * Math.PI / 180) } else { // dir === 'd' modifier.setFromAxisAngle(axis, 90 * Math.PI / 180) } } else { // dir === 'l' || dir === 'r' const axis = new this.three.Vector3(0, 0, 1) if (dir === 'l') { modifier.setFromAxisAngle(axis, 90 * Math.PI / 180) } else { // dir === 'r' modifier.setFromAxisAngle(axis, (-90) * Math.PI / 180) } } target.multiply(modifier) v2.applyQuaternion(target) } v2.add(v1) this.line(v1, v2) this.obj.position.copy(v2) } else if (m instanceof CommandHome) { const mode = m.mode switch (mode) { case 'set': this.home.position.copy(this.obj.position) this.home.quaternion.copy(this.obj.quaternion) break case 'jump': this.obj.position.copy(this.home.position) this.obj.quaternion.copy(this.home.quaternion) break } } else if (m instanceof CommandRotate) { const dir = m.direction const rv = m.angle * (dir === 'l' || dir === 'd' ? 1 : -1) const target = new this.three.Quaternion() let axis:THREENS.Vector3 if (dir === 'l' || dir === 'r') { axis = new this.three.Vector3(0, 0, 1) } else { axis = new this.three.Vector3(1, 0, 0) } target.setFromAxisAngle(axis, (rv % 360) * Math.PI / 180) this.obj.quaternion.multiply(target) } else if (m instanceof CommandRoll) { const dir = m.direction const rv = m.angle * (dir === 'r' ? 1 : -1) const axis = new this.three.Vector3(0, 1, 0) const target = new this.three.Quaternion() target.setFromAxisAngle(axis, (rv % 360) * Math.PI / 180) this.obj.quaternion.multiply(target) } else if (m instanceof CommandPenColor) { this.color = m.color } else if (m instanceof CommandPenWidth) { this.lineWidth = m.width } else if (m instanceof CommandPenEnable) { this.flagDown = m.enable } else if (m instanceof CommandVisible) { this.f_visible = m.visible if (this.f_visible) { this.obj.visible = true } else { this.obj.visible = false } } else if (m instanceof CommandModel) { this.flagLoaded = false this.loadTurtle(m.model) } else if (m instanceof CommandAngle) { const euler = new this.three.Euler() euler.fromArray(m.angle) // eslint-disable-next-line no-unused-vars const dir = new this.three.Quaternion() this.obj.quaternion.setFromEuler(euler) } if (que instanceof CommandPromise) { que.resolve(0) } return (this.macros.length > 0) } private createDefaultTurtle (): THREENS.Object3D { const vertices = new Float32Array([ 0.0, 1.0, 0.0, -0.6, -1.0, 0.0, 0.0, -0.5, 0.0, 0.6, -1.0, 0.0, 0.0, 0.0, 0.5, 0.0, 1.0, 0.0, -0.6, -1.0, 0.0, 0.0, -0.5, 0.0, 0.6, -1.0, 0.0, 0.0, 0.0, -0.5, 0.0, 1.0, 0.0, -0.6, -1.0, 0.0, 0.0, -0.5, 0.0, 0.6, -1.0, 0.0 ]) const colors = new Float32Array([ 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 ]) const indices = [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 4, 6, 4, 7, 4, 8, 9, 10, 9, 11, 9, 12, 9, 13 ] const obj = new this.three.Group() const material = new this.three.LineBasicMaterial({ vertexColors: true }) const geometry = new this.three.BufferGeometry() geometry.setIndex(indices) geometry.setAttribute('position', new this.three.BufferAttribute(vertices, 3)) geometry.setAttribute('color', new this.three.BufferAttribute(colors, 3)) geometry.computeBoundingSphere() const lineSegments = new this.three.LineSegments(geometry, material) lineSegments.scale.set(30.0, 30.0, 30.0) obj.add(lineSegments) return obj } private raiseModelChanged (): void { const evt = new CustomEvent<void>('modelChanged') this.dispatchEvent(evt) } private raiseDrawLine(v1: THREENS.Vector3, v2: THREENS.Vector3, width: number, color: THREENS.Color) : void { const args = new DrawLineEventArgs(v1, v2, width, color) const evt = new CustomEvent<DrawLineEventArgs>('drawLine', { detail: args }) this.dispatchEvent(evt) } private line (v1: THREENS.Vector3, v2: THREENS.Vector3) { if (!this.flagDown) { return } this.raiseDrawLine(v1, v2, this.lineWidth, this.color) } private isObject3D (obj: any): obj is THREENS.Object3D { return obj instanceof this.three.Object3D } } class WeykTurtle3DSystem { private static instance: WeykTurtle3DSystem private instanceCount: number sys: NakoSystem three: null|THREENS.THREE containerid: string camera: number target: number _renderer: THREENS.Renderer|null _scene: THREENS.Scene|null _lines: THREENS.Line|null _camera: THREENS.Camera|null _controls: THREENS.Controls|null _camerahelper: THREENS.CameraHelper|null _axishelper: THREENS.AxesHelper|null turtles: Turtle3D[] flagSetTimer: boolean _prevUpdatedTime: number static getInstance(sys: NakoSystem) { if (WeykTurtle3DSystem.instance === undefined) { WeykTurtle3DSystem.instance = new WeykTurtle3DSystem(sys); } const i = WeykTurtle3DSystem.instance; i.instanceCount += 1; return WeykTurtle3DSystem.instance; } constructor(sys: NakoSystem) { this.instanceCount = 0 this.three = null this.sys = sys this.containerid = '' this.camera = -1 this.target = -1 this._renderer = null this._scene = null this._lines = null this._camera = null this._controls = null this._camerahelper = null this._axishelper = null this.turtles = [] this.flagSetTimer = false this._prevUpdatedTime = 0 } clearAll () { this.disposeAllTurtle() this.disposeAllLine() const scene = this._scene if (scene && this._lines) { scene.remove(this._lines) scene.add(this._lines) if (this._camerahelper !== null) { this._camerahelper.visible = false scene.remove(this._camerahelper) scene.add(this._camerahelper) } if (this._axishelper !== null) { this._axishelper.visible = false scene.remove(this._axishelper) scene.add(this._axishelper) } this.initTurtle() } } disposeAllTurtle () { // カメをクリア for (const tt of this.turtles) { tt.clear() } this.turtles = [] this.target = -1 this.camera = -1 this.flagSetTimer = false } disposeAllLine () { // 引いた線を線用のバッファからクリア if (this._lines !== null) { ThreeUtil.disposeChildObject(this._lines) } } private getThree(): THREENS.THREE { if (!this.three) { throw new Error('ThreeJSの準備される前に使用しようとしました') } return this.three } createTurtle (modelUrl: string): number { // カメの情報を sys._turtle リストに追加 const three = this.getThree() const id = this.turtles.length const tt = new Turtle3D(three, id) tt.addEventListener('modelChanged', (e) => { const redraw = !!this.sys.__getSysVar('T3D自動描画') if (redraw) { this.doDraw(true) } }) tt.addEventListener('drawLine', (e) => { this.drawLine(e.detail.v1, e.detail.v2, e.detail.width, e.detail.color) }) this.turtles.push(tt) this.target = id tt.loadTurtle(modelUrl) const scene = this.getScene() scene.add(tt.obj) return id } initTurtle (): void { if (this.turtles.length === 0) { if (this._renderer === null) { this.initRenderer() } const three = this.getThree() // カメを1つ生成する const index = this.createTurtle('') // 生成したカメをカメラ用カメとして設定する const tt = this.turtles[index] tt.obj.position.set(0, 0, 1000) const axis = new three.Vector3(0, 0, -1).normalize() const angle = 0 tt.obj.quaternion.setFromAxisAngle(axis, angle) tt.home.position.copy(tt.obj.position) tt.home.quaternion.copy(tt.obj.quaternion) tt.f_visible = false tt.obj.visible = false this.camera = index this.target = -1 } } getCur (): Turtle3D { if (this.turtles.length === 0) { throw Error('最初に『T3Dカメ作成』命令を呼び出してください。') } if (this.target < 0 || this.target >= this.turtles.length) { throw Error('指定された番号のカメはいません。') } return this.turtles[this.target] } queCurrentTurtle (cmd: Command): Promise<number> { const tt = this.getCur() const promise = new Promise<number>((resolve,reject) => { const que = new CommandPromise(cmd, resolve, reject) tt.macros.push(que) this.animationStart() }) return promise } doDraw (beforeClear: boolean) { if (this.camera === -1) { return } if (!this._scene) { return } this.getRenderer() if (!this._renderer) { return } this.getCamera() if (!this._camera) { return } const camera = this.turtles[this.camera] if (this._controls === null) { this._camera.position.copy(camera.obj.position) this._camera.quaternion.copy(camera.obj.quaternion) } if (this._camerahelper !== null) { this._camerahelper.update() } if (this._controls !== null) { this._controls.update() camera.obj.position.copy(this._camera.position) camera.obj.quaternion.copy(this._camera.quaternion) } if (beforeClear) { this._renderer.clear() } this._renderer.render(this._scene, this._camera) } setCameraHelper (flag: boolean) { const three = this.getThree() if (flag) { if (this._camerahelper === null) { if (this._scene && this._camera) { if (typeof three.CameraHelper === 'undefined') { throw Error('カメラヘルパの機能が見当たりません。') } const cameraHelper = new three.CameraHelper(this._camera) this._camerahelper = cameraHelper this._scene.add(cameraHelper) } } this._camerahelper!.visible = true } else { if (this._camerahelper !== null) { this._camerahelper.visible = false } } } setAxisHelper (flag: boolean) { const three = this.getThree() if (flag) { if (this._axishelper === null) { if (this._scene) { if (typeof three.AxisHelper === 'undefined') { throw Error('AXISヘルパの機能が見当たりません。') } const axisHelper = new three.AxisHelper(1000) this._axishelper = axisHelper this._scene.add(axisHelper) } } this._axishelper!.visible = true } else { if (this._axishelper !== null) { this._axishelper.visible = false } } } getScene (): THREENS.Scene { const three = this.getThree() if (this._scene === null) { this._scene = new three.Scene() } return this._scene } getCamera (): THREENS.Camera { const three = this.getThree() if (this._camera === null) { const camera = new three.PerspectiveCamera(60, 1.0, 1, 65000) this.resetCamera(camera) this._camera = camera } return this._camera } resetCamera (camera: THREENS.Camera):void { const three = this.getThree() camera.position.set(0, 0, 1000) if (this._renderer !== null) { const rect = new three.Vector2() this._renderer.getSize(rect) if ('aspect' in camera) { camera.aspect = rect.width / rect.height } } camera.up = new three.Vector3(0, 1, 0) camera.lookAt(new three.Vector3(0, 0, 0)) } initTrutle3dEnv (renderer: THREENS.WebGLRenderer) { renderer.setClearColor(0x000000, 1.0) renderer.autoClear = false const scene = this.getScene() // eslint-disable-next-line no-unused-vars const camera = this.getCamera() if (scene && this._lines) { scene.add(this._lines) if (this.turtles.length === 0) { this.initTurtle() } } } initRenderer ():THREENS.WebGLRenderer { // 描画先をセットする let to = this.sys.__getSysVar('T3Dカメ描画先') if (typeof to === 'string') { to = document.querySelector(to) || document.getElementById(to) } if (!to) { throw new Error('[ERROR] T3Dカメ描画先が見当たりません。') } const renderer = this.setRenderer(to) this.setupRenderer() return renderer } setRenderer (to: Element|HTMLCanvasElement|THREENS.WebGLRenderer):THREENS.WebGLRenderer { const three = this.getThree() let renderer: null|THREENS.WebGLRenderer = null if (to instanceof three.WebGLRenderer) { renderer = to } else if (to instanceof HTMLCanvasElement) { renderer = new three.WebGLRenderer({ antialias: false, alpha: true, canvas:to }) if (renderer === null) { throw new Error('レンダラを作成できません') } renderer.setSize( to.width, to.height ) } else if (to instanceof Element) { renderer = new three.WebGLRenderer({ antialias: false, alpha: true }) if (renderer === null) { throw new Error('レンダラを作成できません') } renderer.setSize(to.clientWidth, to.clientHeight ); to.appendChild(renderer.domElement) } else [ // never ] renderer!.setPixelRatio(window.devicePixelRatio) this._renderer = renderer return this._renderer! } clearRenderer () { this._renderer = null if (this._controls) { this._controls.enabled = false this._controls = null } } setupRenderer () { if (this._renderer) { this.initTrutle3dEnv(this._renderer) } } getRenderer (): THREENS.Renderer { if (this._renderer === null) { this.initRenderer() } return this._renderer! } setupControl (controlConstrucor: THREENS.Controls): THREENS.Controls { if (typeof controlConstrucor === 'undefined') { throw new Error('指定されたコンコントロールが見当たりません。') } if (this._controls !== null) { if (this._controls instanceof controlConstrucor) { return this._controls } else { throw new Error('既にコントロールを適用しています。コントロールの変更はできません。') } } const renderer = this.getRenderer() const camera = this.getCamera() // eslint-disable-next-line new-cap const controls = new controlConstrucor(camera, renderer.domElement) controls.enabled = true this._controls = controls return this._controls } drawLine (v1: THREENS.Vector3, v2: THREENS.Vector3, width: number, color: THREENS.Color):void { const three = this.getThree() const geometry = new three.BufferGeometry() const vertices = new three.Float32BufferAttribute(6, 3) vertices.copyArray([v1.x, v1.y, v1.z, v2.x, v2.y, v2.z]) const material = new three.LineBasicMaterial({ color: color, linewidth: width }) geometry.setAttribute('position', vertices) const line = new three.Line(geometry, material) if (this._lines) { this._lines.add(line) } } doMacroAllTurtles (): boolean { let hasNext = false for (const tt of this.turtles) { if (tt.doMacro(this.isNoWait())) { hasNext = true } } return hasNext } animationStart ():void { const wait = this.getWait() const macrorun = !!this.sys.__getSysVar('T3D自動実行') if (!macrorun) { return } if (this.isNoWait()) { this.animation() return } if (this.flagSetTimer) { return } this.flagSetTimer = true this.animationFrame(() => this.animation()) } getWait (): number { return this.sys.__getSysVar('T3Dカメ速度') } isNoWait (): boolean { return this.sys.__getSysVar('T3Dカメ速度') === 0 } animation () { const redraw = !!this.sys.__getSysVar('T3D自動描画') const macrorun = !!this.sys.__getSysVar('T3D自動実行') const hasNext = this.animationTick() if (redraw) { this.doDraw(true) } if ((hasNext || this._controls !== null) && macrorun) { this.animationFrame(() => this.animation()) } else { this.flagSetTimer = false } } animationTick () { const now = Date.now() const noWait = this.isNoWait() // ノーウエイトではない場合の時間待ち処理 if (!noWait) { const elapsedMs = now - this._prevUpdatedTime const wait = this.getWait() if (wait > 0 && elapsedMs < wait) { return true } } this._prevUpdatedTime = now let hasNext:boolean if (noWait) { while (this.doMacroAllTurtles()) { // no-op } hasNext = false } else { hasNext = this.doMacroAllTurtles() } return hasNext } animationFrame (callback: () => void, element?: Element) { window.setTimeout(callback, 1000 / 60) } ck (): THREENS.THREE { if (this.three === null) { if (this.sys.__getSysVar('THREE') !== null) { this.three = this.sys.__getSysVar('THREE') } else if (typeof window.THREE !== 'undefined') { this.three = window.THREE } } if (this.three === null) { throw new Error('three.module.jsが読み込まれていません') } if (this.sys.__getSysVar('THREE') === null) { this.sys.__setSysVar('THREE', this.three) } if (this._lines === null) { this._lines = new this.three.Group() } return this.three } static getTurtle3D(sys: NakoSystem): WeykTurtle3DSystem { if (!sys.tags.weykturtle3d) { throw new Error('プラグインの初期化が行われていません') } return sys.tags.weykturtle3d } static getEnv(sys: NakoSystem):[ WeykTurtle3DSystem, THREENS.THREE ] { const turtle3d = WeykTurtle3DSystem.getTurtle3D(sys) const three = turtle3d.ck() return [turtle3d, three] } } const PluginWeykTurtle3D: NakoPluginObject = { 'meta': { type: 'const', value: { pluginName: 'plugin_weykturtle3d', // プラグインの名前 description: '3Dでタートルグラフィックス描画プラグイン', // プラグインの説明 pluginVersion: '3.6.0', // プラグインのバージョン nakoRuntime: ['wnako'], // 対象ランタイム nakoVersion: '3.6.0' // 要求なでしこバージョン } }, '初期化': { type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { if (sys.tags.weykturtle3d) { return } const turtle3dSystem = WeykTurtle3DSystem.getInstance(sys) sys.tags.weykturtle3d = turtle3dSystem // オブジェクトを初期化 sys.__setSysVar('THREE', null) } }, // @3Dタートルグラフィックス・ライブラリとプラグイン 'THREE': {type: 'const', value: ''}, // @THREE 'T3DベースURL': {type: 'var', value: 'https://cdn.jsdelivr.net/npm/three@0.127.0'}, // @T3DべーすURL 'T3Dライブラリ読込': { // @ThreeJSのライブラリを動的に読み込む // @T3Dらいぶらりよみこむ type: 'func', josi: [], asyncFn: true, pure: true, fn: async function (sys: NakoSystem): Promise<boolean> { const turtle3d = WeykTurtle3DSystem.getTurtle3D(sys) if (turtle3d.three === null && sys.__getSysVar('THREE') === null) { const baseUrl = sys.__getSysVar('T3DベースURL') const moduleUrl = baseUrl === '' ? 'three' : ( baseUrl + '/build/three.module.js' ) const promise = import(/* webpackIgnore: true */ moduleUrl) promise.then(module => { turtle3d.three = Object.assign({}, module) turtle3d.ck() return true }) promise.catch(err => { return false }) return await promise } else { turtle3d.ck() return true } }, return_none: false }, 'T3Dライブラリ読込後': { // @ThreeJSのライブラリを動的に読み込む // @T3Dらいぶらりよみこみご type: 'func', josi: [['に']], pure: true, fn: function (callback: CallbackType<boolean>, sys: NakoSystem):void { const turtle3d = WeykTurtle3DSystem.getTurtle3D(sys) if (turtle3d.three === null && sys.__getSysVar('THREE') === null) { const baseUrl = sys.__getSysVar('T3DベースURL') const moduleUrl = baseUrl === '' ? 'three' : ( baseUrl + '/build/three.module.js' ) const promise = import(/* webpackIgnore: true */ moduleUrl) promise.then(module => { turtle3d.three = Object.assign({}, module) turtle3d.ck() callback(true) }) promise.catch(err => { callback(false) }) } else { turtle3d.ck() callback(true) } }, return_none: true }, 'T3Dプラグイン読込': { // @ThreeJSのプラグインを動的に読み込む // @T3Dぷらぐいんよみこむ type: 'func', josi: [['を']], asyncFn: true, pure: true, fn: async function (plugins: string[], sys: NakoSystem):Promise<void> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) const l = plugins.length if (l === 0) { return } const baseUrl = sys.__getSysVar('T3DベースURL') const totalPromise = new Promise<void> ((resolve, reject) => { const callbacks = (function (total) { let countTotal = 0 let countSuccess = 0 return function (success: boolean) { countTotal += 1 if (success) { countSuccess += 1 } if (countTotal === total) { if (countTotal === countSuccess) { resolve() } else { reject() } } } })(l) for (const name of plugins) { const pluginUrl = baseUrl === '' ? name : ( baseUrl + '/examples/jsm/' + name ) const promise = import(/* webpackIgnore: true */ pluginUrl) promise.then(module => { Object.assign<THREENS.THREE, any>(three, module) callbacks(true) }) promise.catch(err => { callbacks(false) }) } }) return totalPromise }, return_none: true }, 'T3Dプラグイン読込後': { // @ThreeJSのプラグインを動的に読み込む // @T3Dぷらぐいんよみこみご type: 'func', josi: [['に'], ['を']], pure: true, fn: function (callback: CallbackType<void> , plugins: string[], sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) const l = plugins.length if (l === 0) { callback() return } const baseUrl = sys.__getSysVar('T3DベースURL') const callbacks = (function (callback, total) { let count = 0 return function (success: boolean) { count+=1 if (count === total) { callback() } } })(callback, l) for (let i=0;i < l;i++) { const name = plugins[i] const pluginUrl = baseUrl === '' ? name : ( baseUrl + '/examples/jsm/' + name ) const promise = import(/* webpackIgnore: true */ pluginUrl) promise.then(module => { Object.assign<THREENS.THREE, any>(three, module) callbacks(true) }) promise.catch(err => { callbacks(false) }) } }, return_none: true }, // @3Dタートルグラフィックス・カメ操作 'T3Dカメ作成': { // @タートルグラフィックスを開始してカメのIDを返す // @T3Dかめさくせい type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): number { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.initTurtle() const modelUrl = sys.__getSysVar('T3DカメモデルURL') const id = turtle3d.createTurtle(modelUrl) return id }, return_none: false }, 'T3Dカメ操作対象設定': { // @IDを指定して操作対象となるカメを変更する // @T3Dかめそうさたいしょうせってい type: 'func', josi: [['に', 'へ', 'の']], pure: true, fn: function (id: number, sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.target = id }, return_none: true }, 'T3Dカメ描画先': { type: 'var', value: 'turtle3d_div' }, // @T3Dかめびょうがさき 'T3DカメモデルURL': { type: 'var', value: '' }, // @T3DかめもでるURL 'T3Dカメモデル変更': { // @カメのモデルをURLに変更する // @T3Dかめもでるへんこう type: 'func', josi: [['に', 'へ']], pure: true, fn: function (url: string, sys: NakoSystem):Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandModel(url)) }, return_none: false }, 'T3Dカメ速度': { type: 'const', value: 100 }, // @T3Dかめそくど 'T3Dカメ速度設定': { // @カメの動作速度Vに設定(大きいほど遅い) // @T3Dかめそくどせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (v: number, sys: NakoSystem):void { sys.__setSysVar('T3Dカメ速度', v) }, return_none: true }, 'T3Dカメ移動': { // @カメの位置を[x,y,z]へ移動する // @T3Dかめいどう type: 'func', josi: [['に', 'へ']], pure: true, fn: function (xyz: NumericArray3, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveAbsolute(new three.Vector3(xyz[0], xyz[1], xyz[2]))) }, return_none: false }, 'T3Dカメ原点設定': { // @カメの原点を現在の位置・向きに設定する // @T3Dかめげんてんせってい type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandHome('set')) }, return_none: false }, 'T3Dカメ原点移動': { // @カメを原点の位置・向きに移動する(描画はしない) // @T3Dかめげんてんいどう type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandHome('jump')) }, return_none: false }, 'T3Dカメ起点移動': { // @カメの描画起点位置を[x,y,z]へ移動する // @T3Dかめきてんいどう type: 'func', josi: [['に', 'へ']], pure: true, fn: function (xyz: NumericArray3, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandJump(new three.Vector3(xyz[0], xyz[1], xyz[2]))) }, return_none: false }, 'T3Dカメ進': { // @カメの位置をLだけ進める // @T3Dかめすすむ type: 'func', josi: [['だけ']], pure: true, fn: function (l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveDirection('f', l)) }, return_none: false }, 'T3Dカメ戻': { // @カメの位置をLだけ戻す // @T3Dかめもどる type: 'func', josi: [['だけ']], pure: true, fn: function (l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveDirection('b', l)) }, return_none: false }, 'T3Dカメ上平行移動': { // @カメの位置を上にLだけ進める // @T3Dかめうえへいこういどう type: 'func', josi: [['だけ']], pure: true, fn: function (l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveDirection('u', l)) }, return_none: false }, 'T3Dカメ下平行移動': { // @カメの位置を下にLだけ進める // @T3Dかめしたへいこういどう type: 'func', josi: [['だけ']], pure: true, fn: function (l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveDirection('d', l)) }, return_none: false }, 'T3Dカメ左平行移動': { // @カメの位置を左にLだけ進める // @T3Dかめひだりへいこういどう type: 'func', josi: [['だけ']], pure: true, fn: function (l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveDirection('l', l)) }, return_none: false }, 'T3Dカメ右平行移動': { // @カメの位置を右にLだけ進める // @T3Dかめみぎへいこういどう type: 'func', josi: [['だけ']], pure: true, fn: function (l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandMoveDirection('r', l)) }, return_none: false }, 'T3Dカメ動': { // @カメの位置をDIRにLだけ進める // @T3Dかめうごく type: 'func', josi: [['へ', 'に'], ['だけ']], pure: true, fn: function (dir:string, l: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) let cmd:MoveDirection if (dir === '前' || dir === 'FORWARD' || dir === 'まえ') { cmd = 'f' } else if (dir === '後' || dir === 'BACK' || dir === 'うしろ' || dir === 'BACKWARD' || dir === 'あと') { cmd = 'b' } else if (dir === '上' || dir === 'UP' || dir === 'うえ') { cmd = 'u' } else if (dir === '下' || dir === 'DOWN' || dir === 'した') { cmd = 'd' } else if (dir === '右' || dir === 'RIGHT' || dir === 'みぎ') { cmd = 'r' } else if (dir === '左' || dir === 'LEFT' || dir === 'ひだり') { cmd = 'l' } else { throw Error('方向の指定が正しくありません。前後上下左右のいずれかで指定してください。') } return turtle3d.queCurrentTurtle(new CommandMoveDirection(cmd, l)) }, return_none: false }, 'T3Dカメ角度設定': { // @カメの向きをオイラー([x,y,z,XYZ])にて設定する // @T3Dかめかくどせってい type: 'func', josi: [['に', 'へ', 'の']], pure: true, fn: function (angle: THREENS.EulerArray, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandAngle(angle)) }, return_none: false }, 'T3Dカメ右回転': { // @カメの向きをAだけ右に向ける // @T3Dかめみぎかいてん type: 'func', josi: [['だけ']], pure: true, fn: function (a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandRotate('r', a)) }, return_none: false }, 'T3Dカメ左回転': { // @カメの向きをAだけ左に向ける // @T3Dかめひだりかいてん type: 'func', josi: [['だけ']], pure: true, fn: function (a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandRotate('l', a)) }, return_none: false }, 'T3Dカメ上回転': { // @カメの向きをAだけ上に向ける // @T3Dかめうえかいてん type: 'func', josi: [['だけ']], pure: true, fn: function (a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandRotate('u', a)) }, return_none: false }, 'T3Dカメ下回転': { // @カメの向きをAだけ下に向ける // @T3Dかめしたかいてん type: 'func', josi: [['だけ']], pure: true, fn: function (a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandRotate('d', a)) }, return_none: false }, 'T3Dカメ回転': { // @カメの向きをAだけDIRに向ける // @T3Dかめかいてん type: 'func', josi: [['へ', 'に'], ['だけ']], pure: true, fn: function (dir: string, a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) let cmd:RotateDirection if (dir === '上' || dir === 'UP' || dir === 'うえ') { cmd = 'u' } else if (dir === '下' || dir === 'DOWN' || dir === 'した') { cmd = 'd' } else if (dir === '右' || dir === 'RIGHT' || dir === 'みぎ') { cmd = 'r' } else if (dir === '左' || dir === 'LEFT' || dir === 'ひだり') { cmd = 'l' } else { throw Error('方向の指定が正しくありません。上下左右のいずれかで指定してください。') } return turtle3d.queCurrentTurtle(new CommandRotate(cmd, a)) }, return_none: false }, 'T3Dカメ右ロール': { // @カメをAだけ右に傾ける // @T3Dかめみぎろーる type: 'func', josi: [['だけ']], pure: true, fn: function (a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandRoll('r', a)) }, return_none: false }, 'T3Dカメ左ロール': { // @カメのAだけ左に傾ける // @T3Dかめひだりろーる type: 'func', josi: [['だけ']], pure: true, fn: function (a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandRoll('l', a)) }, return_none: false }, 'T3Dカメ傾': { // @カメをAだけDIRに傾ける // @T3Dかめかたむける type: 'func', josi: [['に', 'へ'], ['だけ']], pure: true, fn: function (dir: string, a: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) let cmd:RollDirection if (dir === '右' || dir === 'RIGHT' || dir === 'みぎ') { cmd = 'r' } else if (dir === '左' || dir === 'LEFT' || dir === 'ひだり') { cmd = 'l' } else { throw Error('向きの指定が正しくありません。左右のどちらかで指定してください。') } return turtle3d.queCurrentTurtle(new CommandRoll(cmd, a)) }, return_none: false }, 'T3Dカメペン色設定': { // @カメのペン描画色をCに設定する // @T3Dかめぺんいろせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (c: number|THREENS.Color, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (typeof c === 'number') { c = new three.Color(c) } return turtle3d.queCurrentTurtle(new CommandPenColor(c)) }, return_none: false }, 'T3Dカメペンサイズ設定': { // @カメペンのサイズをWに設定する // @T3Dかめぺんさいずせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (w: number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandPenWidth(w)) }, return_none: false }, 'T3Dカメペン設定': { // @カメペンを使うかどうかをV(オン/オフ)に設定する // @T3Dかめぺんせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (w: boolean|number, sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandPenEnable(!!w)) }, return_none: false }, 'T3Dカメ全消去': { // @表示しているカメと描画内容を全部消去する // @T3Dかめぜんしょうきょ type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.clearAll() }, return_none: true }, 'T3Dカメ非表示': { // @カメのモデルを非表示にする。描画に影響しない。 // @T3Dかめひひょうじ type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandVisible(false)) }, return_none: false }, 'T3Dカメ表示': { // @非表示にしたカメのモデルを表示する。 // @T3Dかめひょうじ type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): Promise<number> { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.queCurrentTurtle(new CommandVisible(true)) }, return_none: false }, 'T3D視点カメ設定': { // @指定したカメを視点として使用する // @T3Dしてんかめせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (n: number, sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (n < 0 || n >= turtle3d.turtles.length) { throw Error('指定された番号のカメはいません。') } turtle3d.camera = n turtle3d.animationStart() }, return_none: true }, // @3Dタートルグラフィックス・基本機能 'T3D自動描画': {type: 'var', value: true}, // @T3Dじどうびょうが 'T3D自動実行': {type: 'var', value: true}, // @T3Dじどうじっこう 'T3D描画準備': { // @指定したDOMのIDに対する描画を準備し、描画オブジェクトを返す // @T3Dびょうがじゅんび type: 'func', josi: [['に', 'へ']], pure: true, fn: function (to: string|Element|null, sys: NakoSystem):THREENS.WebGLRenderer { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (typeof to === 'string') { to = document.querySelector(to) || document.getElementById(to) } if (!to) { throw new Error('T3D描画準備に指定した描画先に誤りがあります') } const renderer = turtle3d.setRenderer(to) turtle3d.setupRenderer() return renderer }, return_none: false }, 'T3D描画': { // @現在の状態を描画する // @T3Dびょうが type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.doDraw(true) }, return_none: true }, 'T3D上書描画': { // @現在の状態を元イメージをクリアせずに描画する // @T3Dうわがきびょうが type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.doDraw(false) }, return_none: true }, 'T3D実行': { // @各カメの動きを経過時間等に従い実行する // @T3Dじっこう type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.animationTick() }, return_none: true }, 'T3D背景色設定': { // @canvasをクリアする際の背景色を設定する // @T3Dはいけいしょくせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (c: number, sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) const renderer = turtle3d.getRenderer() renderer.setClearColor(c) turtle3d.animationStart() }, return_none: true }, 'T3D背景透過設定': { // @canvasをクリアする際の背景のアルファ値を設定する // @T3Dはいけいとうかせってい type: 'func', josi: [['に', 'へ']], pure: true, fn: function (a: number, sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) const renderer = turtle3d.getRenderer() renderer.setClearAlpha(a) turtle3d.animationStart() }, return_none: true }, 'T3DJSON取得': { // @描画した線のJSON形式で取得する // @T3DJSONしゅとく type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): null|string { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (!turtle3d._lines) { return null } return JSON.stringify(turtle3d._lines.toJSON()) }, return_none: false }, 'T3Dレンダラ破棄': { // @内部で使用しているレンダラを捨てる // @T3Dれんだらはき type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) turtle3d.clearRenderer() }, return_none: true }, 'T3D内部レンダラ取得': { // @本プラグイン内部で使用しているレンダラを返す // @T3Dないぶれんだらしゅとく type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): THREENS.WebGLRenderer { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.getRenderer() }, return_none: false }, 'T3D内部シーン取得': { // @本プラグイン内部で使用しているシーンを返す // @T3Dないぶしーんしゅとく type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): THREENS.Scene { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.getScene() }, return_none: false }, 'T3D内部カメラ取得': { // @本プラグイン内部で使用しているカメラを返す // @T3Dないぶかめらしゅとく type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): THREENS.Camera { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d.getCamera() }, return_none: false }, 'T3D内部線描画参照取得': { // @本プラグイン内部で保持している描いた線のデータの参照を返す // @T3Dないぶせんびょうがさんしょうしゅとく type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): null|THREENS.Group { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) return turtle3d._lines }, return_none: false }, 'T3D内部線描画取出': { // @本プラグイン内部で保持している描いた線のデータを取り出して返す // @T3Dないぶせんびょうがとりだし type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): null|THREENS.Group { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) const lines = turtle3d._lines turtle3d._lines = new three.Group() turtle3d.animationStart() return lines }, return_none: false }, 'T3D待': { // @Promiseの終了を待って結果を返す // @T3Dまつ type: 'func', josi: [['を']], asyncFn: true, pure: true, fn: function (p: Promise<any>, sys: NakoSystem): Promise<any> { return p }, return_none: false }, // @3Dタートルグラフィックス・ヘルパ機能 'T3Dオービットコントロール設定': { // オービットコントロールを組み込む // @T3Dおーびっとこんとろーるせってい type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem): null|THREENS.OrbitControls { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (typeof three.OrbitControls !== 'undefined') { return turtle3d.setupControl(three.OrbitControls) as THREENS.OrbitControls } return null }, return_none: false }, 'T3Dコントロール有効': { // @組み込んだコントロールを有効にする // @T3Dこんとろーるゆうこう type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (turtle3d._controls) { turtle3d._controls.enabled = true } }, return_none: true }, 'T3Dコントロール無効': { // @組み込んだコントロールを無効にする // @T3Dこんとろーるむこう type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem):void { const [ turtle3d, three ] = WeykTurtle3DSystem.getEnv(sys) if (turtle3d._controls) { turtle3d._controls.enabled = false } }, return_none: true }, 'T3Dカメラヘルパ表示': { // @カメラヘルパーを表示する // @