Home Reference Source Repository

js/SceneKit/SCNView.js

  1. 'use strict'
  2.  
  3. //import _HTMLCanvasElement from '../util/HTMLCanvasElement'
  4. import CGPoint from '../CoreGraphics/CGPoint'
  5. import CGRect from '../CoreGraphics/CGRect'
  6. import CGSize from '../CoreGraphics/CGSize'
  7. import GCController from '../GameController/GCController'
  8. import SCNRenderer from './SCNRenderer'
  9. //import SCNTechniqueSupport from './SCNTechniqueSupport'
  10. //import SCNScene from './SCNScene'
  11. import SCNRenderingAPI from './SCNRenderingAPI'
  12. import SCNAntialiasingMode from './SCNAntialiasingMode'
  13. //import SCNNode from './SCNNode'
  14. //import SCNCamera from './SCNCamera'
  15. //import SCNMatrix4 from './SCNMatrix4'
  16. //import SCNMatrix4MakeTranslation from './SCNMatrix4MakeTranslation'
  17. import SCNVector4 from './SCNVector4'
  18. import SKColor from '../SpriteKit/SKColor'
  19. /*global window*/
  20.  
  21. const _Option = {
  22. preferLowPowerDevice: 'SCNPreferLowPowerDeviceKey',
  23. preferredDevice: 'SCNPreferredDeviceKey',
  24. preferredRenderingAPI: 'SCNPreferredRenderingAPIKey'
  25. }
  26.  
  27. const _KeyCode = new Map([
  28. ['KeyA', 0x00],
  29. ['KeyS', 0x01],
  30. ['KeyD', 0x02],
  31. ['KeyF', 0x03],
  32. ['KeyH', 0x04],
  33. ['KeyG', 0x05],
  34. ['KeyZ', 0x06],
  35. ['KeyX', 0x07],
  36. ['KeyC', 0x08],
  37. ['KeyV', 0x09],
  38. ['IntlBackslash', 0x0A],
  39. ['KeyB', 0x0B],
  40. ['KeyQ', 0x0C],
  41. ['KeyW', 0x0D],
  42. ['KeyE', 0x0E],
  43. ['KeyR', 0x0F],
  44. ['KeyY', 0x10],
  45. ['KeyT', 0x11],
  46. ['Digit1', 0x12],
  47. ['Digit2', 0x13],
  48. ['Digit3', 0x14],
  49. ['Digit4', 0x15],
  50. ['Digit6', 0x16],
  51. ['Digit5', 0x17],
  52. ['Equal', 0x18], // '^' in JIS keyboard
  53. ['Digit9', 0x19],
  54. ['Digit7', 0x1A],
  55. ['Minus', 0x1B],
  56. ['Digit8', 0x1C],
  57. ['Digit0', 0x1D],
  58. ['BracketRight', 0x1E], // '[' in JIS keyboard
  59. ['KeyO', 0x1F],
  60. ['KeyU', 0x20],
  61. ['BracietLeft', 0x21], // '@' in JIS keyboard
  62. ['KeyI', 0x22],
  63. ['KeyP', 0x23],
  64. ['Enter', 0x24],
  65. ['KeyL', 0x25],
  66. ['KeyJ', 0x26],
  67. ['Quote', 0x27], // ':' in JIS keyboard
  68. ['KeyK', 0x28],
  69. ['Semicolon', 0x29],
  70. ['Backslash', 0x2A], // ']' in JIS keyboard
  71. ['Comma', 0x2B],
  72. ['Slash', 0x2C],
  73. ['KeyN', 0x2D],
  74. ['KeyM', 0x2E],
  75. ['Period', 0x2F],
  76. ['Tab', 0x30],
  77. ['Space', 0x31],
  78. ['Backquote', 0x32],
  79. ['Delete', 0x33],
  80. ['NumpadEnter', 0x34],
  81. ['Escape', 0x35],
  82. ['OSRight', 0x36],
  83. ['MetaRight', 0x36],
  84. ['OSLeft', 0x37],
  85. ['MetaLeft', 0x37],
  86. ['ShiftLeft', 0x38],
  87. ['CapsLock', 0x39],
  88. ['AltLeft', 0x3A],
  89. ['ControlLeft', 0x3B],
  90. ['ShiftRight', 0x3C],
  91. ['AltRight', 0x3D],
  92. ['ControlRight', 0x3E],
  93. ['Fn', 0x3F], // impossible to catch the key event for function key
  94. ['F17', 0x40],
  95. ['NumpadDecimal', 0x41],
  96. // 0x42: unknown
  97. ['NumpadMultiply', 0x43],
  98. // 0x44: unknown
  99. ['NumpadAdd', 0x45],
  100. // 0x46: unknown
  101. ['NumLock', 0x47],
  102. ['AudioVolumeUp', 0x48],
  103. ['AudioVolumeDown', 0x49],
  104. ['AudioVolumeMute', 0x4A],
  105. ['NumpadDivide', 0x4B],
  106. ['NumpadEnter', 0x4C],
  107. // 0x4D: unknown
  108. ['NumpadSubtract', 0x4E],
  109. ['F18', 0x4F],
  110. ['F19', 0x50],
  111. ['NumpadEqual', 0x51],
  112. ['Numpad0', 0x52],
  113. ['Numpad1', 0x53],
  114. ['Numpad2', 0x54],
  115. ['Numpad3', 0x55],
  116. ['Numpad4', 0x56],
  117. ['Numpad5', 0x57],
  118. ['Numpad6', 0x58],
  119. ['Numpad7', 0x59],
  120. ['F20', 0x5A],
  121. ['Numpad8', 0x5B],
  122. ['Numpad9', 0x5C],
  123. ['IntlYen', 0x5D], // JIS_Yen
  124. ['IntlRo', 0x5E], // JIS_Underscore
  125. ['NumpadComma', 0x5F],
  126. ['F5', 0x60],
  127. ['F6', 0x61],
  128. ['F7', 0x62],
  129. ['F3', 0x63],
  130. ['F8', 0x64],
  131. ['F9', 0x65],
  132. ['Lang2', 0x66], // JIS_Eisu. It could be ''
  133. ['F11', 0x67],
  134. ['Lang1', 0x68], // JIS_Kana. It could be 'KanaMode'
  135. ['F13', 0x69],
  136. ['F16', 0x6A],
  137. ['F14', 0x6B],
  138. // 0x6C: unknown
  139. ['F10', 0x6D],
  140. // 0x6E: unknown
  141. ['F12', 0x6F],
  142. // 0x70: unknown
  143. ['F15', 0x71],
  144. ['Help', 0x72],
  145. ['Insert', 0x72],
  146. ['Home', 0x73],
  147. ['PageUp', 0x74],
  148. ['Delete', 0x75],
  149. ['F4', 0x76],
  150. ['End', 0x77],
  151. ['F2', 0x78],
  152. ['PageDown', 0x79],
  153. ['F1', 0x7A],
  154. ['ArrowLeft', 0x7B],
  155. ['ArrowRight', 0x7C],
  156. ['ArrowDown', 0x7D],
  157. ['ArrowUp', 0x7E]
  158. ])
  159.  
  160. /**
  161. * A view for displaying 3D SceneKit content.
  162. * @access public
  163. * @implements {SCNSceneRenderer}
  164. * @implements {SCNTechniqueSupport}
  165. * @see https://developer.apple.com/documentation/scenekit/scnview
  166. */
  167. export default class SCNView {
  168.  
  169. // Initializing a SceneKit View
  170.  
  171. /**
  172. * Initializes and returns a newly allocated SceneKit view object with the specified frame rectangle and options.
  173. * @access public
  174. * @constructor
  175. * @param {CGRect} frame - The frame rectangle for the view, measured in points and specified in the coordinate system of its superview.
  176. * @param {?Map<string, Object>} [options = null] - Rendering options for the view. See SCNView.
  177. * @returns {void}
  178. * @see https://developer.apple.com/documentation/scenekit/scnview/1524215-init
  179. */
  180. constructor(frame, options = null) {
  181. //super()
  182.  
  183. // Specifying a Scene
  184.  
  185. /**
  186. * The scene to be displayed in the view.
  187. * @access private
  188. * @type {?SCNScene}
  189. * @see https://developer.apple.com/documentation/scenekit/scnview/1523904-scene
  190. */
  191. this._scene = null
  192.  
  193.  
  194. // Configuring a View
  195.  
  196. /**
  197. * The background color of the view.
  198. * @type {SKColor}
  199. * @see https://developer.apple.com/documentation/scenekit/scnview/1523088-backgroundcolor
  200. */
  201. this._backgroundColor = SKColor.white
  202.  
  203. /**
  204. * A Boolean value that determines whether the user can manipulate the current point of view that is used to render the scene.
  205. * @type {boolean}
  206. * @see https://developer.apple.com/documentation/scenekit/scnview/1523171-allowscameracontrol
  207. */
  208. this.allowsCameraControl = false
  209.  
  210. /**
  211. * The antialiasing mode used for rendering the view’s scene.
  212. * @type {SCNAntialiasingMode}
  213. * @see https://developer.apple.com/documentation/scenekit/scnview/1524085-antialiasingmode
  214. */
  215. this.antialiasingMode = SCNAntialiasingMode.multisampling4X
  216.  
  217. /**
  218. * The animation frame rate that the view uses to render its scene.
  219. * @type {number}
  220. * @see https://developer.apple.com/documentation/scenekit/scnview/1621205-preferredframespersecond
  221. */
  222. this.preferredFramesPerSecond = 0
  223.  
  224.  
  225. // Working with a View’s OpenGL ES Context
  226.  
  227. /**
  228. * The OpenGL ES context that the view uses to render its contents.
  229. * @type {?EAGLContext}
  230. * @see https://developer.apple.com/documentation/scenekit/scnview/1621072-eaglcontext
  231. */
  232. //this.eaglContext = null
  233.  
  234.  
  235. // Working with a View’s OpenGL Context
  236.  
  237. /**
  238. * The OpenGL context that the view uses to render its contents.
  239. * @type {?NSOpenGLContext}
  240. * @see https://developer.apple.com/documentation/scenekit/scnview/1522850-openglcontext
  241. */
  242. //this.openGLContext = null
  243.  
  244. /**
  245. * @access private
  246. * @type {WebGL2RenderingContext}
  247. */
  248. this._context = null
  249.  
  250. /**
  251. * The view’s OpenGL pixel format.
  252. * @type {?NSOpenGLPixelFormat}
  253. * @see https://developer.apple.com/documentation/scenekit/scnview/1523612-pixelformat
  254. */
  255. this.pixelFormat = null
  256.  
  257. ////////////////////////////////////////////////
  258. // SCNSceneRenderer
  259. ////////////////////////////////////////////////
  260.  
  261. /**
  262. * Required. The graphics technology SceneKit uses to render the scene.
  263. * @access private
  264. * @type {SCNRenderingAPI}
  265. */
  266. this._renderingAPI = SCNRenderingAPI.webGL
  267.  
  268. // Participating in the Scene Rendering Process
  269.  
  270. /**
  271. * Required. A delegate object that receives messages about SceneKit’s rendering process.
  272. * @access private
  273. * @type {?SCNSceneRendererDelegate}
  274. */
  275. this._delegate = null
  276.  
  277. // Customizing Scene Rendering with Metal
  278.  
  279. //this._currentRenderCommandEncoder = null
  280. this._device = null // MTLIGAccelDevice
  281. //this._commandQueue = null // MTLIGAccessCommandQueue
  282. //this._colorPixelFormat = null // MTLPixelFormat
  283. //this._depthPixelFormat = null // MTLPixelFormat
  284. //this._stencilPixelFormat = null // MTLPixelFormat
  285.  
  286. // Rendering Sprite Kit Content over a Scene
  287.  
  288. /**
  289. * Required. A Sprite Kit scene to be rendered on top of the SceneKit content.
  290. * @type {?SKScene}
  291. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1524051-overlayskscene
  292. */
  293. //this.overlaySKScene = null
  294.  
  295. // Working With Positional Audio
  296.  
  297. /**
  298. * Required. The node representing the listener’s position in the scene for use with positional audio effects.
  299. * @type {?SCNNode}
  300. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523747-audiolistener
  301. */
  302. //this.audioListener = null
  303.  
  304. //this._audioEnvironmentNode = null
  305. //this._audioEngine = null
  306.  
  307. // Instance Properties
  308.  
  309. /**
  310. * Required.
  311. * @type {number}
  312. * @deprecated
  313. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522854-currenttime
  314. */
  315. //this.currentTime = 0
  316.  
  317.  
  318. ////////////////////////////////////////////////
  319. // SCNTechniqueSupport
  320. ////////////////////////////////////////////////
  321.  
  322. // Specifying a Technique
  323.  
  324. /**
  325. * Required. The technique SceneKit uses when rendering the object.
  326. * @type {?SCNTechnique}
  327. * @see https://developer.apple.com/documentation/scenekit/scntechniquesupport/1520496-technique
  328. */
  329. this.technique = null
  330.  
  331. // for JavaScript
  332.  
  333. /**
  334. * @access private
  335. * @type {CGRect}
  336. */
  337. this._frame = frame
  338.  
  339. /**
  340. * @access private
  341. * @type {HTMLCanvasElement}
  342. */
  343. this._canvas = document.createElement('canvas')
  344. this._canvas.tabIndex = 1 // to get keydown/up events, it needs to set tabIndex
  345. if(typeof frame === 'undefined'){
  346. frame = CGRect.rectWithXYWidthHeight(0, 0, 300, 300)
  347. }
  348. this._canvas.style.width = frame.width
  349. this._canvas.style.height = frame.height
  350.  
  351. /**
  352. * @access private
  353. * @type {number}
  354. */
  355. this._canvasWidth = 0
  356.  
  357. /**
  358. * @access private
  359. * @type {number}
  360. */
  361. this._canvasHeight = 0
  362.  
  363. /**
  364. * @access private
  365. * @type {number}
  366. */
  367. this._currentSystemTime = 0
  368.  
  369. /**
  370. * @access private
  371. * @type {number}
  372. */
  373. this._elapsedTime = 0
  374.  
  375. /**
  376. * @access private
  377. * @type {number}
  378. */
  379. this._previousSystemTimeMs = 0
  380.  
  381. /**
  382. * @access private
  383. * @type {number}
  384. */
  385. this._sumElapsedTimeMs = 0
  386.  
  387. /**
  388. * @access private
  389. * @type {number}
  390. */
  391. this._sumFrames = 0
  392.  
  393. /**
  394. * @access private
  395. * @type {number}
  396. */
  397. this._lastFpsCalculationTimeMs = 0
  398.  
  399. /**
  400. * @access private
  401. * @type {number}
  402. */
  403. this._fpsCalculationSpanMs = 2000
  404.  
  405. /**
  406. * @access private
  407. * @type {number}
  408. */
  409. this._fps = 0
  410.  
  411. /**
  412. * @access private
  413. * @type {SCNSceneRenderer}
  414. */
  415. this._renderer = new SCNRenderer()
  416. //this._renderer.scene = this._scene
  417. //if(this._scene !== null){
  418. // this._scene._physicsWorld._renderer = this._renderer
  419. //}
  420.  
  421. /**
  422. * @access private
  423. * @type {function(function(timestamp: number))}
  424. */
  425. this._requestAnimationFrame = window.requestAnimationFrame ||
  426. window.webkitRequestAnimationFrame ||
  427. window.mozRequestAnimationFrame ||
  428. window.oRequestAnimationFrame ||
  429. window.msRequestAnimationFrame ||
  430. ((callback) => { window.setTimeout(callback, 1000 / 60) })
  431.  
  432. const preferLowPowerDevice = options ? options[SCNView.Option.preferLowPowerDevice] : null
  433. const preferredDevice = options ? options[SCNView.Option.preferredDevice] : null
  434. const preferredRenderingAPI = options ? options[SCNView.Option.preferredRenderingAPI] : null
  435. const opt = {
  436. alpha: true,
  437. depth: true,
  438. stencil: true,
  439. antialias: true,
  440. premultipliedAlpha: true,
  441. preserveDrawingBuffer: false,
  442. preferLowPowerToHighPerformance: Boolean(preferLowPowerDevice),
  443. failIfMajorPerformanceCaveat: false
  444. }
  445.  
  446. //const contextNames = ['webgl2', 'webgl', 'webkit-3d', 'moz-webgl', 'experimental-webgl']
  447. const contextNames = ['webgl2']
  448. for(const name of contextNames){
  449. try{
  450. this._context = this._canvas.getContext(name, opt)
  451. }catch(e){ /* just ignore and try the next name */ }
  452. if(this._context){
  453. break
  454. }
  455. }
  456. if(!this._context){
  457. throw new Error('can\'t create WebGL context')
  458. }
  459. this._context.viewport(frame.minX, frame.minY, frame.width, frame.height)
  460.  
  461. this._renderer._setContext(this._context)
  462. this._renderer._backgroundColor = this._backgroundColor
  463. this._renderer._viewRect = frame
  464.  
  465. this._mouseIsDown = false
  466. this._mouseDownX = 0
  467. this._mouseDownY = 0
  468.  
  469. // add event listeners
  470. this._canvas.addEventListener('mousedown', (e) => {
  471. const ev = this._createEvent(e)
  472. this._mouseIsDown = true
  473. this._mouseDownX = e.clientX
  474. this._mouseDownY = e.clientY
  475. if(this.allowsCameraControl){
  476. this._baseCameraPosition = this._renderer._getCameraPosition()
  477. this._baseCameraOrientation = this._renderer._getCameraOrientation()
  478. this._baseCameraDistance = this._renderer._getCameraDistance()
  479. }
  480. this.mouseDownWith(ev)
  481. })
  482. this._canvas.addEventListener('mousemove', (e) => {
  483. const ev = this._createEvent(e)
  484. this.mouseMovedWith(ev)
  485. if(this._mouseIsDown){
  486. if(this.allowsCameraControl){
  487. const mx = e.clientX
  488. const my = e.clientY
  489. const dx = mx - this._mouseDownX
  490. const dy = my - this._mouseDownY
  491. const d = Math.sqrt(dx * dx + dy * dy)
  492. const rotScale = 0.01
  493. if(d > 0){
  494. const r = -d * 0.5 * rotScale
  495. const sinr = Math.sin(r) / d
  496. const q = new SCNVector4(dy * sinr, dx * sinr, 0, Math.cos(r))
  497. const orientation = this._baseCameraOrientation.cross(q)
  498. this._renderer._setDefaultCameraOrientation(orientation)
  499. }
  500. this._renderer._switchToDefaultCamera()
  501. }
  502. this.mouseDraggedWith(ev)
  503. }
  504. })
  505. document.addEventListener('mouseup', (e) => {
  506. if(this._mouseIsDown){
  507. this._mouseIsDown = false
  508. const ev = this._createEvent(e)
  509. this.mouseUpWith(ev)
  510. this._preventDefault(ev)
  511. }
  512. })
  513. this._canvas.addEventListener('mouseover', (e) => {
  514. const ev = this._createEvent(e)
  515. this._preventDefault(ev)
  516. })
  517. this._canvas.addEventListener('mouseout', (e) => {
  518. const ev = this._createEvent(e)
  519. this.mouseExitedWith(ev)
  520. this._preventDefault(ev)
  521. })
  522. this._canvas.addEventListener('mousewheel', (e) => {
  523. const ev = this._createEvent(e)
  524. this.scrollWheelWith(ev)
  525. this._preventDefault(ev)
  526. })
  527. // For Firefox
  528. this._canvas.addEventListener('DOMMouseScroll', (e) => {
  529. const ev = this._createEvent(e)
  530. this.scrollWheelWith(ev)
  531. this._preventDefault(ev)
  532. })
  533.  
  534. this._canvas.addEventListener('keydown', (e) => {
  535. const ev = this._createEvent(e)
  536.  
  537. this.keyDownWith(ev)
  538. this._preventDefault(ev)
  539. })
  540. this._canvas.addEventListener('keyup', (e) => {
  541. const ev = this._createEvent(e)
  542.  
  543. this.keyUpWith(ev)
  544. this._preventDefault(ev)
  545. })
  546. }
  547.  
  548. connectedCallback() {
  549. }
  550.  
  551. disconnectedCallback() {
  552. }
  553.  
  554. attributeChangedCallback() {
  555. }
  556.  
  557. /**
  558. * @access private
  559. * @returns {void}
  560. */
  561. _resizeCanvas() {
  562. const w = this._canvas.clientWidth
  563. const h = this._canvas.clientHeight
  564. if(this._frame && this._frame.width === w && this._frame.height === h){
  565. return
  566. }
  567. this._frame = CGRect.rectWithXYWidthHeight(0, 0, w, h)
  568. this._canvas.width = w
  569. this._canvas.height = h
  570. this._context.viewport(0, 0, w, h)
  571. this._renderer._viewRect = this._frame
  572.  
  573. this.setFrameSize(this._frame.size)
  574. }
  575.  
  576. /**
  577. *
  578. * @access public
  579. * @param {HTMLElement} element - parent element to append this view
  580. * @returns {void}
  581. */
  582. appendTo(element) {
  583. element.appendChild(this._canvas)
  584.  
  585. // update canvas size
  586. if(typeof this._frame === 'undefined'){
  587. this._canvas.style.width = '100%'
  588. this._canvas.style.height = '100%'
  589. if(this._canvas.clientHeight <= 0){
  590. this._canvas.style.height = 300
  591. }
  592. }
  593. this._resizeCanvas()
  594. if(typeof window !== 'undefined'){
  595. window.addEventListener('resize', () => {
  596. this._resizeCanvas()
  597. })
  598. }
  599. }
  600.  
  601. get backgroundColor() {
  602. return this._backgroundColor
  603. }
  604. set backgroundColor(newValue) {
  605. this._backgroundColor = newValue
  606. //this._context.clearColor(newValue.r, newValue.g, newValue.b, newValue.a)
  607. this._renderer._backgroundColor = newValue
  608. }
  609.  
  610. /**
  611. * Required. A Boolean value that determines whether the scene is playing.
  612. * @type {boolean}
  613. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523401-isplaying
  614. */
  615. get isPlaying() {
  616. return this._renderer.isPlaying
  617. }
  618.  
  619. /**
  620. * Required. A Boolean value that determines whether the scene is playing.
  621. * @type {boolean}
  622. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523401-isplaying
  623. */
  624. set isPlaying(newValue) {
  625. if(newValue){
  626. this.play()
  627. }else{
  628. this.pause()
  629. }
  630. }
  631.  
  632. // Specifying a Scene
  633.  
  634. /**
  635. * The scene to be displayed in the view.
  636. * @access private
  637. * @type {?SCNScene}
  638. * @see https://developer.apple.com/documentation/scenekit/scnview/1523904-scene
  639. */
  640. get scene() {
  641. return this._scene
  642. }
  643.  
  644. /**
  645. * The scene to be displayed in the view.
  646. * @access private
  647. * @type {?SCNScene}
  648. * @see https://developer.apple.com/documentation/scenekit/scnview/1523904-scene
  649. */
  650. set scene(newValue) {
  651. // FIXME: it should not be changed while drawing
  652. this._scene = newValue
  653. this._renderer.scene = this._scene
  654. if(this._scene === null){
  655. return
  656. }
  657. this._scene._physicsWorld._renderer = this._renderer
  658. this._updateTransform()
  659. this._scene.rootNode._resetPhysicsTransformRecursively()
  660. }
  661.  
  662.  
  663. // Playing Action and Animation in a View’s Scene
  664.  
  665. /**
  666. * Pauses playback of the view’s scene.
  667. * @access public
  668. * @param {?Object} sender - The object requesting the action (used when connecting a control in Interface Builder). SceneKit ignores this parameter.
  669. * @returns {void}
  670. * @desc This method has no effect if the scene is already paused.
  671. * @see https://developer.apple.com/documentation/scenekit/scnview/1522825-pause
  672. */
  673. pause(sender) {
  674. if(!this._isPlaying){
  675. return
  676. }
  677. this._isPlaying = false
  678. }
  679.  
  680. /**
  681. * Resumes playback of the view’s scene.
  682. * @access public
  683. * @param {?Object} sender - The object requesting the action (used when connecting a control in Interface Builder). SceneKit ignores this parameter.
  684. * @returns {void}
  685. * @desc This method has no effect if the scene is not paused.
  686. * @see https://developer.apple.com/documentation/scenekit/scnview/1523699-play
  687. */
  688. play(sender) {
  689. if(this._isPlaying){
  690. return
  691. }
  692. this._isPlaying = true
  693.  
  694. this.__requestAnimationFrame()
  695. }
  696.  
  697. /**
  698. * Stops playback of the view’s scene and resets the scene time to its start time.
  699. * @access public
  700. * @param {?Object} sender - The object requesting the action (used when connecting a control in Interface Builder). SceneKit ignores this parameter.
  701. * @returns {void}
  702. * @see https://developer.apple.com/documentation/scenekit/scnview/1524132-stop
  703. */
  704. stop(sender) {
  705. this._isPlaying = false
  706. }
  707.  
  708. // Capturing a View Snapshot
  709.  
  710. /**
  711. * Renders the view’s scene into a new image object.
  712. * @access public
  713. * @returns {Image} -
  714. * @desc This method is thread-safe and may be called at any time.
  715. * @see https://developer.apple.com/documentation/scenekit/scnview/1524031-snapshot
  716. */
  717. snapshot() {
  718. return null
  719. }
  720.  
  721. // Structures
  722. /**
  723. * @type {Object} Option
  724. * @property {string} preferLowPowerDevice An option for whether to select low-power-usage devices for Metal rendering.
  725. * @property {string} preferredDevice The device to use for Metal rendering.
  726. * @property {string} preferredRenderingAPI The rendering API to use for rendering the view (for example, Metal or OpenGL).
  727. * @see https://developer.apple.com/documentation/scenekit/scnview.option
  728. */
  729. static get Option() {
  730. return _Option
  731. }
  732.  
  733. ////////////////////////////////////////////////
  734. // SCNSceneRenderer
  735. ////////////////////////////////////////////////
  736.  
  737. // Presenting a Scene
  738.  
  739. /**
  740. * Required. Displays the specified scene with an animated transition.
  741. * @access public
  742. * @param {SCNScene} scene - The new scene to be displayed.
  743. * @param {SKTransition} transition - An object that specifies the duration and style of the animated transition.
  744. * @param {?SCNNode} pointOfView - The node to use as the pointOfView property when displaying the new scene.
  745. * @param {?function(): void} [completionHandler = null] - A block that SceneKit calls after the transition animation has completed.This block takes no parameters and has no return value.
  746. * @returns {void}
  747. * @desc Use this method to change the scene displayed in a SceneKit view (or other renderer) with an animated transition. For details on transition styles, see SKTransition.
  748. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523028-present
  749. */
  750. presentWithIncomingPointOfView(scene, transition, pointOfView, completionHandler = null) {
  751. }
  752.  
  753. // Managing Scene Display
  754.  
  755. /**
  756. * Required. The node from which the scene’s contents are viewed for rendering.
  757. * @type {?SCNNode}
  758. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523982-pointofview
  759. */
  760. get pointOfView() {
  761. return this._renderer.pointOfView
  762. }
  763.  
  764. set pointOfView(newValue) {
  765. this._renderer.pointOfView = newValue
  766. }
  767.  
  768. /**
  769. * Required. A Boolean value that determines whether SceneKit automatically adds lights to a scene.
  770. * @type {boolean}
  771. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523812-autoenablesdefaultlighting
  772. */
  773. get autoenablesDefaultLighting() {
  774. return this._renderer.autoenablesDefaultLighting
  775. }
  776.  
  777. set autoenablesDefaultLighting(newValue) {
  778. this._renderer.autoenablesDefaultLighting = newValue
  779. }
  780.  
  781. /**
  782. * Required. A Boolean value that determines whether SceneKit applies jittering to reduce aliasing artifacts.
  783. * @type {boolean}
  784. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1524026-isjitteringenabled
  785. */
  786. get isJitteringEnabled() {
  787. return this._renderer.isJitteringEnabled
  788. }
  789. set isJitteringEnabled(newValue) {
  790. this._renderer.isJitteringEnabled = newValue
  791. }
  792.  
  793. /**
  794. * Required. A Boolean value that determines whether SceneKit displays rendering performance statistics in an accessory view.
  795. * @type {boolean}
  796. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522763-showsstatistics
  797. */
  798. get showsStatistics() {
  799. return this._renderer.showsStatistics
  800. }
  801.  
  802. set showsStatistics(newValue) {
  803. this._renderer.showsStatistics = newValue
  804. }
  805.  
  806. /**
  807. * Required. Options for drawing overlay content in a scene that can aid debugging.
  808. * @type {SCNDebugOptions}
  809. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523281-debugoptions
  810. */
  811. get debugOptions() {
  812. return this._renderer.debugOptions
  813. }
  814.  
  815. set debugOptions(newValue) {
  816. this._renderer.debugOptions = newValue
  817. }
  818.  
  819. /**
  820. * Required. The current scene time.
  821. * @type {number}
  822. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522680-scenetime
  823. */
  824. get sceneTime() {
  825. return this._renderer.sceneTime
  826. }
  827.  
  828. set sceneTime(newValue) {
  829. this._renderer.sceneTime = newValue
  830. }
  831.  
  832. /**
  833. * Required. A Boolean value that determines whether SceneKit restarts the scene time after all animations in the scene have played.
  834. * @type {boolean}
  835. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522878-loops
  836. */
  837. get loops() {
  838. return this._renderer.loops
  839. }
  840.  
  841. set loops(newValue) {
  842. this._renderer.loops = newValue
  843. }
  844.  
  845. /**
  846. * Required. The graphics technology SceneKit uses to render the scene.
  847. * @type {SCNRenderingAPI}
  848. * @desc You choose a graphics technology when initializing a scene renderer:When initializing a SCNView object, use the init(frame:options:) initializer and the preferredRenderingAPI key. Alternatively, create a view in Interface Builder and use the Rendering API control in the inspector. During initialization, the view will attempt to use the preferred API, but will fall back to a different API if the preferred one is not supported on the current hardware.To create a SCNRenderer object that renders into your own OpenGL contect, use the init(context:options:) initializer. To create a renderer for use in your own Metal workflow, use the init(device:options:) initializer.The rendering technology used by a SCNLayer object is determined by Core Animation.After initializing a renderer, this property reflects the rendering technology in use.
  849. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522616-renderingapi
  850. */
  851. get renderingAPI() {
  852. return this._renderingAPI
  853. }
  854.  
  855. // Participating in the Scene Rendering Process
  856.  
  857. /**
  858. * Required. A delegate object that receives messages about SceneKit’s rendering process.
  859. * @type {?SCNSceneRendererDelegate}
  860. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522671-delegate
  861. */
  862. get delegate() {
  863. return this._delegate
  864. }
  865.  
  866. /**
  867. * Required. A delegate object that receives messages about SceneKit’s rendering process.
  868. * @type {?SCNSceneRendererDelegate}
  869. * @param {?SCNSceneRendererDelegate} newValue -
  870. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522671-delegate
  871. */
  872. set delegate(newValue) {
  873. // FIXME: delegate should not be changed while drawing
  874. this._delegate = newValue
  875. }
  876.  
  877. // Preloading Renderer Resources
  878.  
  879. /**
  880. * Required. Prepares a SceneKit object for rendering.
  881. * @access public
  882. * @param {Object} object - An SCNScene, SCNNode, SCNGeometry, or SCNMaterial instance.
  883. * @param {?function(): boolean} [block = null] - A block that SceneKit calls periodically while preparing the object. The block takes no parameters.Your block should return false to tell SceneKit to continue preparing the object, or true to cancel preparation.Pass nil for this parameter if you do not need an opportunity to cancel preparing the object.
  884. * @returns {boolean} -
  885. * @desc By default, SceneKit lazily loads resources onto the GPU for rendering. This approach uses memory and GPU bandwidth efficiently, but can lead to stutters in an otherwise smooth frame rate when you add large amounts of new content to an animated scene. To avoid such issues, use this method to prepare content for drawing before adding it to the scene. You can call this method on a secondary thread to prepare content asynchronously. SceneKit prepares all content associated with the object parameter you provide. If you provide an SCNMaterial object, SceneKit loads any texture images assigned to its material properties. If you provide an SCNGeometry object, SceneKit loads all materials attached to the geometry, as well as its vertex data. If you provide an SCNNode or SCNScene object, SceneKit loads all geometries and materials associated with the node and all its child nodes, or with the entire node hierarchy of the scene.You can use the block parameter to cancel preparation if content is no longer needed. For example, in a game you might use this method to preload areas of the game world the player is soon to enter, but if the player character dies before entering those areas, you can return true from the block to cancel preloading.You can observe the progress of this operation with the Progress class. For details, see Progress.
  886. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522798-prepare
  887. */
  888. prepareShouldAbortBlock(object, block = null) {
  889. return false
  890. }
  891.  
  892. /**
  893. * Required. Prepares the specified SceneKit objects for rendering, using a background thread.
  894. * @access public
  895. * @param {Object[]} objects - An array of containing one or more SCNScene, SCNNode, SCNGeometry, or SCNMaterial instances.
  896. * @param {?function(arg1: boolean): void} [completionHandler = null] - A block that SceneKit calls when object preparation fails or completes.The block takes the following parameter:successtrue if all content was successfully prepared for rendering; otherwise, false.
  897. * @returns {void}
  898. * @desc By default, SceneKit lazily loads resources onto the GPU for rendering. This approach uses memory and GPU bandwidth efficiently, but can lead to stutters in an otherwise smooth frame rate when you add large amounts of new content to an animated scene. To avoid such issues, use this method to prepare content for drawing before adding it to the scene. SceneKit uses a secondary thread to prepare content asynchronously.SceneKit prepares all content associated with the objects you provide. If you provide an SCNMaterial object, SceneKit loads any texture images assigned to its material properties. If you provide an SCNGeometry object, SceneKit loads all materials attached to the geometry, as well as its vertex data. If you provide an SCNNode or SCNScene object, SceneKit loads all geometries and materials associated with the node and all its child nodes, or with the entire node hierarchy of the scene.You can observe the progress of this operation with the Progress class. For details, see Progress.
  899. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523375-prepare
  900. */
  901. prepare(objects, completionHandler = null) {
  902. }
  903.  
  904. // Working With Projected Scene Contents
  905.  
  906. /**
  907. * Required. Searches the renderer’s scene for objects corresponding to a point in the rendered image.
  908. * @access public
  909. * @param {CGPoint} point -
  910. * @param {?Map<SCNHitTestOption, Object>} [options = null] - A dictionary of options affecting the search. See Hit Testing Options Keys for acceptable values.
  911. * @returns {SCNHitTestResult[]} -
  912. * @desc A 2D point in the rendered screen coordinate space can refer to any point along a line segment in the 3D scene coordinate space. Hit-testing is the process of finding elements of a scene located along this line segment. For example, you can use this method to find the geometry corresponding to a click event in a SceneKit view.
  913. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522929-hittest
  914. */
  915. hitTest(point, options = null) {
  916. const x = (point.x - this._frame.minX) / this._frame.width * 2.0 - 1.0
  917. const y = (point.y - this._frame.minY) / this._frame.height * 2.0 - 1.0
  918. return this._renderer.hitTest(new CGPoint(x, -y), options)
  919. }
  920.  
  921. /**
  922. * Required. Returns a Boolean value indicating whether a node might be visible from a specified point of view.
  923. * @access public
  924. * @param {SCNNode} node - The node whose visibility is to be tested.
  925. * @param {SCNNode} pointOfView - A node defining a point of view, as used by the pointOfView property.
  926. * @returns {boolean} -
  927. * @desc Any node containing a camera or spotlight may serve as a point of view (see the pointOfView property for details). Such a node defines a viewing frustum—a portion of the scene’s coordinate space, shaped like a truncated pyramid, that encloses all points visible from that point of view.Use this method to test whether a node lies within the viewing frustum defined by another node (which may or may not be the scene renderer’s current pointOfView node). For example, in a game scene containing multiple camera nodes, you could use this method to determine which camera is currently best for viewing a moving player character.Note that this method does not perform occlusion testing. That is, it returns true if the tested node lies within the specified viewing frustum regardless of whether that node’s contents are obscured by other geometry.
  928. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522647-isnode
  929. */
  930. isNodeInsideFrustumOf(node, pointOfView) {
  931. return false
  932. }
  933.  
  934. /**
  935. * Required. Returns all nodes that might be visible from a specified point of view.
  936. * @access public
  937. * @param {SCNNode} pointOfView - A node defining a point of view, as used by the pointOfView property.
  938. * @returns {SCNNode[]} -
  939. * @desc Any node containing a camera or spotlight may serve as a point of view (see the pointOfView property for details). Such a node defines a viewing frustum—a portion of the scene’s coordinate space, shaped like a truncated pyramid, that encloses all points visible from that point of view.Use this method find all nodes whose content lies within the viewing frustum defined by another node (which may or may not be the scene renderer’s current pointOfView node).Note that this method does not perform occlusion testing. That is, the returned array includes any node that lies within the specified viewing frustum regardless of whether that node’s contents are obscured by other geometry.
  940. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522942-nodesinsidefrustum
  941. */
  942. nodesInsideFrustumOf(pointOfView) {
  943. return null
  944. }
  945.  
  946. /**
  947. * Required. Projects a point from the 3D world coordinate system of the scene to the 2D pixel coordinate system of the renderer.
  948. * @access public
  949. * @param {SCNVector3} point - A point in the world coordinate system of the renderer’s scene.
  950. * @returns {SCNVector3} -
  951. * @desc The z-coordinate of the returned point describes the depth of the projected point relative to the near and far clipping planes of the renderer’s viewing frustum (defined by its pointOfView node). Projecting a point on the near clipping plane returns a point whose z-coordinate is 0.0; projecting a point on the far clipping plane returns a point whose z-coordinate is 1.0.
  952. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1524089-projectpoint
  953. */
  954. projectPoint(point) {
  955. return null
  956. }
  957.  
  958. /**
  959. * Required. Unprojects a point from the 2D pixel coordinate system of the renderer to the 3D world coordinate system of the scene.
  960. * @access public
  961. * @param {SCNVector3} point - A point in the screen-space (view, layer, or GPU viewport) coordinate system of the scene renderer.
  962. * @returns {SCNVector3} -
  963. * @desc The z-coordinate of the point parameter describes the depth at which to unproject the point relative to the near and far clipping planes of the renderer’s viewing frustum (defined by its pointOfView node). Unprojecting a point whose z-coordinate is 0.0 returns a point on the near clipping plane; unprojecting a point whose z-coordinate is 1.0 returns a point on the far clipping plane.A 2D point in the rendered screen coordinate space can refer to any point along a line segment in the 3D scene coordinate space. To test for scene contents along this line—for example, to find the geometry corresponding to the location of a click event in a view—use the hitTest(_:options:) method.
  964. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522631-unprojectpoint
  965. */
  966. unprojectPoint(point) {
  967. return null
  968. }
  969.  
  970. // Customizing Scene Rendering with Metal
  971.  
  972. /**
  973. * Required. The Metal render command encoder in use for the current SceneKit rendering pass.
  974. * @type {?MTLRenderCommandEncoder}
  975. * @desc Use this render command encoder to encode additional rendering commands before or after SceneKit draws its own content.This property is valid only during the SceneKit rendering loop—that is, within one of the methods defined in the SCNSceneRendererDelegate protocol. Accessing this property at any other time returns nil.
  976. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522609-currentrendercommandencoder
  977. */
  978. get currentRenderCommandEncoder() {
  979. return this._renderer.currentRenderCommandEncoder
  980. }
  981.  
  982. /**
  983. * Required. The Metal device this renderer uses for rendering.
  984. * @type {?MTLDevice}
  985. * @desc Use this property to create or look up other Metal resources that use the same device as your SceneKit renderer.NoteThis property is valid only for scene renderers whose renderingAPI value is metal. You create a SceneKit view that renders using Metal with the preferredRenderingAPI initialization option or in Interface Builder, or an SCNRenderer that uses Metal with the init(device:options:) method. For OpenGL-based scene renderers, this property’s value is always nil.
  986. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523935-device
  987. */
  988. get device() {
  989. return this._device
  990. }
  991.  
  992. /**
  993. * Required. The Metal command queue this renderer uses for rendering.
  994. * @type {?MTLCommandQueue}
  995. * @desc Use this property to schedule additional command buffers for the Metal device to execute as part of the render cycle. For example, you can use a compute command encoder to modify the vertex data in a Metal buffer for use by a SCNGeometrySource object.NoteThis property is valid only for scene renderers whose renderingAPI value is metal. You create a SceneKit view that renders using Metal with the preferredRenderingAPI initialization option or in Interface Builder, or an SCNRenderer that uses Metal with the init(device:options:) method. For OpenGL-based scene renderers, this property’s value is always nil.
  996. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523974-commandqueue
  997. */
  998. get commandQueue() {
  999. return this._renderer.commandQueue
  1000. }
  1001.  
  1002. /**
  1003. * Required. The Metal pixel format for the renderer’s color output.
  1004. * @type {MTLPixelFormat}
  1005. * @desc Use this property, along with the depthPixelFormat and stencilPixelFormat properties, if you perform custom drawing with Metal (see the SCNSceneRendererDelegate and SCNNodeRendererDelegate classes) and need to create a new MTLRenderPipelineState object to change the GPU state as part of your rendering.NoteThis property is valid only for scene renderers whose renderingAPI value is metal. You create a SceneKit view that renders using Metal with the preferredRenderingAPI initialization option or in Interface Builder, or an SCNRenderer that uses Metal with the init(device:options:) method. For OpenGL-based scene renderers, this property’s value is always nil.
  1006. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523701-colorpixelformat
  1007. */
  1008. get colorPixelFormat() {
  1009. return this._renderer.colorPixelFormat
  1010. }
  1011.  
  1012. /**
  1013. * Required. The Metal pixel format for the renderer’s depth buffer.
  1014. * @type {MTLPixelFormat}
  1015. * @desc Use this property, along with the colorPixelFormat and stencilPixelFormat properties, if you perform custom drawing with Metal (see the SCNSceneRendererDelegate and SCNNodeRendererDelegate classes) and need to create a new MTLRenderPipelineState object to change the GPU state as part of your rendering.NoteThis property is valid only for scene renderers whose renderingAPI value is metal. You create a SceneKit view that renders using Metal with the preferredRenderingAPI initialization option or in Interface Builder, or an SCNRenderer that uses Metal with the init(device:options:) method. For OpenGL-based scene renderers, this property’s value is always nil.
  1016. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523780-depthpixelformat
  1017. */
  1018. get depthPixelFormat() {
  1019. return this._renderer.depthPixelFormat
  1020. }
  1021.  
  1022. /**
  1023. * Required. The Metal pixel format for the renderer’s stencil buffer.
  1024. * @type {MTLPixelFormat}
  1025. * @desc Use this property, along with the depthPixelFormat and colorPixelFormat properties, if you perform custom drawing with Metal (see the SCNSceneRendererDelegate and SCNNodeRendererDelegate classes) and need to create a new MTLRenderPipelineState object to change the GPU state as part of your rendering.NoteThis property is valid only for scene renderers whose renderingAPI value is metal. You create a SceneKit view that renders using Metal with the preferredRenderingAPI initialization option or in Interface Builder, or an SCNRenderer that uses Metal with the init(device:options:) method. For OpenGL-based scene renderers, this property’s value is always nil.
  1026. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523315-stencilpixelformat
  1027. */
  1028. get stencilPixelFormat() {
  1029. return this._renderer._stencilPixelFormat
  1030. }
  1031.  
  1032. // Customizing Scene Rendering with OpenGL
  1033.  
  1034. /**
  1035. * Required. The OpenGL rendering context that SceneKit uses for rendering the scene.
  1036. * @type {?WebGLRenderingContext}
  1037. * @desc In macOS, the value of this property is a Core OpenGL cglContextObj object.In iOS, the value of this property is an EAGLContext object.
  1038. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522840-context
  1039. */
  1040. get context() {
  1041. return this._renderer.context
  1042. }
  1043.  
  1044. // Rendering Sprite Kit Content over a Scene
  1045.  
  1046. /**
  1047. * Required. A Sprite Kit scene to be rendered on top of the SceneKit content.
  1048. * @type {?SKScene}
  1049. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1524051-overlayskscene
  1050. */
  1051. get overlaySKScene() {
  1052. return this._renderer.overlaySKScene
  1053. }
  1054.  
  1055. set overlaySKScene(newValue) {
  1056. this._renderer.overlaySKScene = newValue
  1057. }
  1058.  
  1059. // Working With Positional Audio
  1060.  
  1061. /**
  1062. * Required. The node representing the listener’s position in the scene for use with positional audio effects.
  1063. * @type {?SCNNode}
  1064. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523747-audiolistener
  1065. */
  1066. get audioListener() {
  1067. return this._renderer.audioListener
  1068. }
  1069.  
  1070. set audioListener(newValue) {
  1071. this._renderer.audioListener = newValue
  1072. }
  1073.  
  1074. /**
  1075. * Required. The 3D audio mixing node SceneKit uses for positional audio effects.
  1076. * @type {AVAudioEnvironmentNode}
  1077. * @desc SceneKit uses this audio node to spatialize sounds from SCNAudioPlayer objects attached to nodes in the scene. You can use this object in conjunction with the audioEngine property to rearrange the audio graph to add other, non-spatialized audio sources or mix in audio processing effects.
  1078. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1523582-audioenvironmentnode
  1079. */
  1080. get audioEnvironmentNode() {
  1081. return this._renderer.audioEnvironmentNode
  1082. }
  1083.  
  1084. /**
  1085. * Required. The audio engine SceneKit uses for playing scene sounds.
  1086. * @type {AVAudioEngine}
  1087. * @desc SceneKit uses this audio engine to play sounds from SCNAudioPlayer objects attached to nodes in the scene. You can use this object directly to add other sound sources not related to scene contents, or to add other sound processing nodes or mixing nodes to the audio engine. To identify the node SceneKit uses for spatializing scene sounds when connecting other nodes, use the audioEnvironmentNode property.
  1088. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522686-audioengine
  1089. */
  1090. get audioEngine() {
  1091. return this._renderer.audioEngine
  1092. }
  1093.  
  1094. // Instance Properties
  1095.  
  1096. /**
  1097. * Required.
  1098. * @type {number}
  1099. * @see https://developer.apple.com/documentation/scenekit/scnscenerenderer/1522854-currenttime
  1100. */
  1101. get currentTime() {
  1102. return this._renderer.currentTime
  1103. }
  1104.  
  1105. set currentTime(newValue) {
  1106. this._renderer.currentTime = newValue
  1107. }
  1108.  
  1109. ////////////////////////////////////////////////
  1110. // NSView/UIView
  1111. ////////////////////////////////////////////////
  1112. // TODO: implement NSView/UIView and extend it
  1113. viewDidMoveToWindow() {}
  1114.  
  1115. setFrameSize(newSize) {}
  1116.  
  1117. /**
  1118. * draw one frame
  1119. * @access private
  1120. * @param {number} time - current time
  1121. * @param {WebGLRenderingContext} context - context to draw frame
  1122. * @returns {void}
  1123. */
  1124. _drawAtTimeWithContext(time, context) {
  1125. this._renderer._time = time
  1126.  
  1127. this._createPresentationNodes()
  1128. this._createSKPresentationNodes()
  1129.  
  1130. this._updateTransform()
  1131.  
  1132. if(this._delegate && this._delegate.rendererUpdateAtTime){
  1133. this._delegate.rendererUpdateAtTime(this._renderer, time)
  1134. }
  1135.  
  1136. ///////////////////////////////
  1137. // runs actions & animations //
  1138. ///////////////////////////////
  1139. this._copyTransformToPresentationNodes()
  1140. this._copyTransformToPresentationSKNodes()
  1141. this._updateTransform()
  1142.  
  1143. this._runActions()
  1144. this._runAnimations()
  1145. this._runSKActions()
  1146.  
  1147. this._updateTransform()
  1148.  
  1149. if(this._delegate && this._delegate.rendererDidApplyAnimationsAtTime){
  1150. this._delegate.rendererDidApplyAnimationsAtTime(this._renderer, time)
  1151. }
  1152.  
  1153. this._updateTransform()
  1154.  
  1155. ///////////////////////
  1156. // simulates physics //
  1157. ///////////////////////
  1158. if(this._scene && this._scene._physicsWorld !== null){
  1159. this._scene._physicsWorld._simulate(time)
  1160. }
  1161.  
  1162. if(this._delegate && this._delegate.rendererDidSimulatePhysicsAtTime){
  1163. this._delegate.rendererDidSimulatePhysicsAtTime(this._renderer, time)
  1164. }
  1165.  
  1166. ///////////////////////////
  1167. // evaluates constraints //
  1168. ///////////////////////////
  1169.  
  1170. if(this._delegate && this._delegate.rendererWillRenderSceneAtTime){
  1171. this._delegate.rendererWillRenderSceneAtTime(this._renderer, this._scene, time)
  1172. }
  1173.  
  1174. ///////////////////////
  1175. // renders the scene //
  1176. ///////////////////////
  1177. this._updateSkinner()
  1178. this._updateMorph()
  1179. this._updateParticles()
  1180.  
  1181. this._updateSKTransform()
  1182. this._renderer.render()
  1183.  
  1184. if(this._delegate && this._delegate.rendererDidRenderSceneAtTime){
  1185. this._delegate.rendererDidRenderSceneAtTime(this._renderer, time)
  1186. }
  1187. }
  1188.  
  1189. _createPresentationNodes() {
  1190. if(this._scene === null){
  1191. return
  1192. }
  1193.  
  1194. const arr = [this._scene.rootNode]
  1195. while(arr.length > 0){
  1196. const node = arr.shift()
  1197. if(!node._presentation){
  1198. node._createPresentation()
  1199. }
  1200. arr.push(...node.childNodes)
  1201. }
  1202. }
  1203.  
  1204. _copyTransformToPresentationNodes() {
  1205. if(this._scene === null){
  1206. return
  1207. }
  1208.  
  1209. const arr = [
  1210. this._scene.rootNode,
  1211. this._scene._skyBox,
  1212. this._renderer._defaultCameraPosNode,
  1213. this._renderer._defaultLightNode
  1214. ]
  1215. while(arr.length > 0){
  1216. const node = arr.shift()
  1217. node._copyTransformToPresentation()
  1218. node._copyMaterialPropertiesToPresentation()
  1219. node._copyMorpherToPresentation()
  1220. arr.push(...node.childNodes)
  1221. }
  1222. }
  1223.  
  1224. _createSKPresentationNodes() {
  1225. if(this.overlaySKScene === null){
  1226. return
  1227. }
  1228.  
  1229. const arr = [this.overlaySKScene]
  1230. while(arr.length > 0){
  1231. const node = arr.shift()
  1232. let p = node.__presentation
  1233. if(p === null){
  1234. p = node.copy()
  1235. p._isPresentationInstance = true
  1236. node.__presentation = p
  1237. }
  1238. //node._copyTransformToPresentation()
  1239. arr.push(...node.children)
  1240. }
  1241. }
  1242.  
  1243. _copyTransformToPresentationSKNodes() {
  1244. if(this.overlaySKScene === null){
  1245. return
  1246. }
  1247.  
  1248. const arr = [this.overlaySKScene]
  1249. while(arr.length > 0){
  1250. const node = arr.shift()
  1251. node._copyTransformToPresentation()
  1252. arr.push(...node.children)
  1253. }
  1254. }
  1255.  
  1256. /**
  1257. * request animation frame repeatedly as long as isPlaying is true
  1258. * @access private
  1259. * @returns {void}
  1260. */
  1261. __requestAnimationFrame() {
  1262. // Reflect.apply(this._requestAnimationFrame, window, () => {
  1263. this._requestAnimationFrame.call(window, () => {
  1264. const time = Date.now()
  1265.  
  1266. let elapsedTimeMs = 0
  1267. if(this._previousSystemTimeMs){
  1268. elapsedTimeMs = time - this._previousSystemTimeMs
  1269. }
  1270. if(elapsedTimeMs){
  1271. if(!this._lastFpsCalculationTimeMs){
  1272. this._lastFpsCalculationTime = time
  1273. }
  1274. this._sumElapsedTimeMs += elapsedTimeMs
  1275. this._sumFrames += 1
  1276.  
  1277. if(time - this._lastFpsCalculationTimeMs > this._fpsCalculationSpanMs){
  1278. this._fps = this._sumFrames / (this._sumElapsedTimeMs * 0.001)
  1279.  
  1280. this._sumFrames = 0
  1281. this._sumElapsedTimeMs = 0
  1282. this._lastFpsCalculationTimeMs = time
  1283.  
  1284. console.error('fps: ' + this._fps)
  1285. }
  1286. }
  1287.  
  1288. this._currentSystemTime = time * 0.001
  1289. this._elapsedTime = elapsedTimeMs * 0.001
  1290. this.currentTime = this._currentSystemTime
  1291. GCController._update()
  1292. this._drawAtTimeWithContext(this.currentTime, this._context)
  1293.  
  1294. if(this._isPlaying){
  1295. this.__requestAnimationFrame()
  1296. }
  1297. this._previousSystemTimeMs = time
  1298. })
  1299. }
  1300.  
  1301. _updateTransform(node, parentTransform) {
  1302. if(this._scene === null){
  1303. return
  1304. }
  1305. this._scene.rootNode._updateWorldTransform()
  1306. this._scene.rootNode._updateBoundingBox()
  1307. }
  1308.  
  1309. _updateSkinner(node) {
  1310. if(typeof node === 'undefined'){
  1311. if(this._scene){
  1312. this._updateSkinner(this._scene.rootNode)
  1313. }
  1314. return
  1315. }
  1316. if(node.skinner !== null && !node.skinner._useGPU){
  1317. node.skinner._update(node)
  1318. }
  1319. node.childNodes.forEach((child) => {
  1320. this._updateSkinner(child)
  1321. })
  1322.  
  1323. }
  1324.  
  1325. _updateMorph(node) {
  1326. if(typeof node === 'undefined'){
  1327. if(this._scene){
  1328. this._updateMorph(this._scene.rootNode)
  1329. }
  1330. return
  1331. }
  1332. if(node.morpher !== null){
  1333. node.morpher._morph(node)
  1334. }
  1335. node.childNodes.forEach((child) => {
  1336. this._updateMorph(child)
  1337. })
  1338. }
  1339.  
  1340. _updateSKTransform() {
  1341. if(this.overlaySKScene === null){
  1342. return
  1343. }
  1344. this.overlaySKScene._updateWorldTransform()
  1345. }
  1346.  
  1347. _runActions() {
  1348. if(this._scene === null){
  1349. return
  1350. }
  1351. this._runActionForNode(this._scene.rootNode)
  1352. }
  1353.  
  1354. _runActionForNode(node) {
  1355. this._runActionForObject(node)
  1356. node.childNodes.forEach((child) => this._runActionForNode(child))
  1357. }
  1358.  
  1359. _runActionForObject(obj) {
  1360. const deleteKeys = []
  1361. obj._actions.forEach((action, key) => {
  1362. action._applyAction(obj, this.currentTime)
  1363. if(action._finished){
  1364. if(action._completionHandler){
  1365. action._completionHandler()
  1366. }
  1367. deleteKeys.push(key)
  1368. }
  1369. })
  1370. deleteKeys.forEach((key) => {
  1371. obj._actions.delete(key)
  1372. })
  1373. }
  1374.  
  1375. _runSKActions() {
  1376. if(this.overlaySKScene === null){
  1377. return
  1378. }
  1379. this._runSKActionForNode(this.overlaySKScene)
  1380. }
  1381.  
  1382. _runSKActionForNode(node) {
  1383. this._runSKActionForObject(node)
  1384. node.children.forEach((child) => this._runSKActionForNode(child))
  1385. }
  1386.  
  1387. _runSKActionForObject(obj) {
  1388. const deleteKeys = []
  1389. obj._actions.forEach((action, key) => {
  1390. action._applyAction(obj, this.currentTime)
  1391. if(action._finished){
  1392. if(action._completionHandler){
  1393. action._completionHandler()
  1394. }
  1395. deleteKeys.push(key)
  1396. }
  1397. })
  1398. deleteKeys.forEach((key) => {
  1399. obj._actions.delete(key)
  1400. })
  1401. }
  1402.  
  1403. _runAnimations() {
  1404. if(this._scene === null){
  1405. return
  1406. }
  1407. this._runAnimationForNode(this._scene.rootNode)
  1408. }
  1409.  
  1410. _runAnimationForNode(node) {
  1411. node.childNodes.forEach((child) => this._runAnimationForNode(child))
  1412. this._runAnimationForObject(node)
  1413. // TODO: implement animations for all animatable objects:
  1414. // SCNCamera, SCNConstraint, SCNGeometry, SCNLight, SCNMaterial,
  1415. // SCNMaterialProperty, SCNMorpher, SCNParticleSystem, SCNTechnique
  1416. if(node.geometry){
  1417. this._runAnimationForObject(node.geometry)
  1418. node.geometry.materials.forEach((material) => {
  1419. this._runAnimationForObject(material)
  1420. const properties = [
  1421. material._diffuse,
  1422. material._ambient,
  1423. material._specular,
  1424. material._normal,
  1425. material._reflective,
  1426. material._emission,
  1427. material._transparent,
  1428. material._multiply,
  1429. material._ambientOcclusion,
  1430. material._selfIllumination,
  1431. material._metalness,
  1432. material._roughness
  1433. ]
  1434. properties.forEach((prop) => {
  1435. this._runAnimationForObject(prop)
  1436. })
  1437. })
  1438. }
  1439. if(node._particleSystems){
  1440. for(const system of node._particleSystems){
  1441. this._runAnimationForObject(system)
  1442. }
  1443. }
  1444. }
  1445.  
  1446. _runAnimationForObject(obj) {
  1447. const deleteKeys = []
  1448. obj._animations.forEach((animation, key) => {
  1449. animation._applyAnimation(obj, this.currentTime)
  1450. if(animation._isFinished && animation.isRemovedOnCompletion){
  1451. deleteKeys.push(key)
  1452. }
  1453. })
  1454. deleteKeys.forEach((key) => {
  1455. obj._animations.delete(key)
  1456. })
  1457. }
  1458.  
  1459. _updateParticles() {
  1460. if(this._scene === null){
  1461. return
  1462. }
  1463. this._updateParticlesForScene()
  1464. this._updateParticlesForNode(this._scene.rootNode)
  1465. }
  1466.  
  1467. _updateParticlesForScene() {
  1468. if(this._scene._particleSystems === null){
  1469. return
  1470. }
  1471. const gravity = this._scene.physicsWorld ? this._scene.physicsWorld.gravity : null
  1472. const len = this._scene._particleSystems.length
  1473. for(let i=0; i<len; i++){
  1474. const system = this._scene._particleSystems[i]
  1475. const transform = this._scene._particleSystemsTransform[i]
  1476. system._updateParticles(transform, gravity, this.currentTime)
  1477. }
  1478. for(const system of this._scene._particleSystems){
  1479. if(system._finished){
  1480. this._scene.removeParticleSystem(system)
  1481. }
  1482. }
  1483. }
  1484.  
  1485. _updateParticlesForNode(node) {
  1486. this._updateParticlesForObject(node)
  1487. node.childNodes.forEach((child) => this._updateParticlesForNode(child))
  1488. }
  1489.  
  1490. _updateParticlesForObject(obj) {
  1491. if(obj.particleSystems === null){
  1492. return
  1493. }
  1494. const gravity = this._scene.physicsWorld ? this._scene.physicsWorld.gravity : null
  1495. for(const system of obj.particleSystems){
  1496. system._updateParticles(obj.presentation.worldTransform, gravity, this.currentTime)
  1497. }
  1498. for(const system of obj.particleSystems){
  1499. if(system._finished){
  1500. obj.removeParticleSystem(system)
  1501. }
  1502. }
  1503. }
  1504.  
  1505.  
  1506. // NSView
  1507.  
  1508. /**
  1509. * @access private
  1510. * @param {Event} e -
  1511. * @returns {NSEvent} -
  1512. */
  1513. _createEvent(e) {
  1514. // TODO: implement NSEvent
  1515. const ev = {}
  1516.  
  1517. ev.locationInWindow = new CGPoint(e.clientX, e.clientY)
  1518.  
  1519. ev.modifierFlags = 0 // TODO: implement
  1520. ev.timestamp = e.timeStamp
  1521. // ev.type
  1522.  
  1523. if(typeof window !== 'undefined'){
  1524. ev.window = window
  1525. }
  1526. ev.windowNumber = 0
  1527. ev.eventRef = e
  1528. ev.cgEvent = null
  1529. ev.characters = null // TODO: implement
  1530. ev.charactersIgnoringModifiers = null // TODO: implement
  1531.  
  1532. ev.isARepeat = false
  1533. if(typeof e.repeat !== 'undefined'){
  1534. ev.isARepeat = e.repeat
  1535. }
  1536.  
  1537. if(e.code && _KeyCode.has(e.code)){
  1538. ev.keyCode = _KeyCode.get(e.code)
  1539. }else{
  1540. ev.keyCode = 0
  1541. }
  1542.  
  1543. ev.buttonNumber = 0
  1544. ev.clickCount = 0
  1545. ev.associatedEventsMask = null
  1546. ev.eventNumber = 0
  1547. ev.trackingNumber = 0
  1548. ev.trackingArea = 0
  1549. ev.userData = null
  1550.  
  1551. ev.data1 = 0
  1552. ev.data2 = 0
  1553. ev.sutype = null
  1554.  
  1555. if(typeof e.deltaX !== 'undefined'){
  1556. ev.deltaX = e.deltaX
  1557. ev.deltaY = e.deltaY
  1558. ev.deltaZ = e.deltaZ
  1559. }else{
  1560. // for Firefox
  1561. ev.deltaX = 0
  1562. ev.deltaY = 0
  1563. ev.deltaZ = 0
  1564. if(typeof e.detail !== 'undefined'){
  1565. ev.deltaY = -e.detail * 10.0
  1566. }
  1567. }
  1568.  
  1569. ev._doDefaultAction = false
  1570. return ev
  1571. }
  1572.  
  1573. _preventDefault(e) {
  1574. if(!e._doDefaultAction){
  1575. e.eventRef.preventDefault()
  1576. }
  1577. }
  1578.  
  1579. /**
  1580. * @access public
  1581. * @param {NSEvent} theEvent -
  1582. * @returns {void}
  1583. */
  1584. mouseDownWith(theEvent) {
  1585. theEvent._doDefaultAction = true
  1586. }
  1587.  
  1588. /**
  1589. * @access public
  1590. * @param {NSEvent} theEvent -
  1591. * @returns {void}
  1592. */
  1593. mouseDraggedWith(theEvent) {
  1594. theEvent._doDefaultAction = true
  1595. }
  1596.  
  1597. /**
  1598. * @access public
  1599. * @param {NSEvent} theEvent -
  1600. * @returns {void}
  1601. */
  1602. mouseUpWith(theEvent) {
  1603. theEvent._doDefaultAction = true
  1604. }
  1605.  
  1606. /**
  1607. * @access public
  1608. * @param {NSEvent} theEvent -
  1609. * @returns {void}
  1610. */
  1611. mouseMovedWith(theEvent) {
  1612. theEvent._doDefaultAction = true
  1613. }
  1614.  
  1615. /**
  1616. * @access public
  1617. * @param {NSEvent} theEvent -
  1618. * @returns {void}
  1619. */
  1620. mouseEnteredWith(theEvent) {
  1621. theEvent._doDefaultAction = true
  1622. }
  1623.  
  1624. /**
  1625. * @access public
  1626. * @param {NSEvent} theEvent -
  1627. * @returns {void}
  1628. */
  1629. mouseExitedWith(theEvent) {
  1630. theEvent._doDefaultAction = true
  1631. }
  1632.  
  1633. /**
  1634. * @access public
  1635. * @param {NSEvent} theEvent -
  1636. * @returns {void}
  1637. */
  1638. rightMouseDraggedWith(theEvent) {
  1639. theEvent._doDefaultAction = true
  1640. }
  1641.  
  1642. /**
  1643. * @access public
  1644. * @param {NSEvent} theEvent -
  1645. * @returns {void}
  1646. */
  1647. rightMouseUpWith(theEvent) {
  1648. theEvent._doDefaultAction = true
  1649. }
  1650.  
  1651. /**
  1652. * @access public
  1653. * @param {NSEvent} theEvent -
  1654. * @returns {void}
  1655. */
  1656. otherMouseDownWith(theEvent) {
  1657. theEvent._doDefaultAction = true
  1658. }
  1659.  
  1660. /**
  1661. * @access public
  1662. * @param {NSEvent} theEvent -
  1663. * @returns {void}
  1664. */
  1665. otherMouseDraggedWith(theEvent) {
  1666. theEvent._doDefaultAction = true
  1667. }
  1668.  
  1669. /**
  1670. * @access public
  1671. * @param {NSEvent} theEvent -
  1672. * @returns {void}
  1673. */
  1674. otherMouseUpWith(theEvent) {
  1675. theEvent._doDefaultAction = true
  1676. }
  1677.  
  1678. /**
  1679. * @access public
  1680. * @param {NSEvent} theEvent -
  1681. * @returns {void}
  1682. */
  1683. scrollWheelWith(theEvent) {
  1684. theEvent._doDefaultAction = true
  1685. }
  1686.  
  1687. /**
  1688. * @access public
  1689. * @param {NSEvent} theEvent -
  1690. * @returns {void}
  1691. */
  1692. keyDownWith(theEvent) {
  1693. theEvent._doDefaultAction = true
  1694. }
  1695.  
  1696. /**
  1697. * @access public
  1698. * @param {NSEvent} theEvent -
  1699. * @returns {void}
  1700. */
  1701. keyUpWith(theEvent) {
  1702. theEvent._doDefaultAction = true
  1703. }
  1704.  
  1705. /**
  1706. * @access public
  1707. * @param {NSEvent} theEvent -
  1708. * @returns {void}
  1709. */
  1710. flagsChangedWith(theEvent) {
  1711. }
  1712.  
  1713. /**
  1714. * @access public
  1715. * @param {NSEvent} theEvent -
  1716. * @returns {void}
  1717. */
  1718. tablePointWith(theEvent) {
  1719. }
  1720.  
  1721. /**
  1722. * @access public
  1723. * @param {NSEvent} theEvent -
  1724. * @returns {void}
  1725. */
  1726. tableProximityWith(theEvent) {
  1727. }
  1728.  
  1729. convertFrom(point, view) {
  1730. let sx = 0
  1731. let sy = 0
  1732. if(view){
  1733. // FIXME: add accessor functions to get the element position
  1734. sx = view._frame.origin.x
  1735. sy = view._frame.origin.y
  1736. }
  1737. // FIXME: add accessor functions to get the element position
  1738. const rect = this._canvas.getBoundingClientRect()
  1739. const dx = rect.left
  1740. const dy = rect.top
  1741.  
  1742. return new CGPoint(point.x + sx - dx, point.y + sy - dy)
  1743. }
  1744.  
  1745. /**
  1746. * @type {CGRect}
  1747. */
  1748. get bounds() {
  1749. const rect = this._canvas.getBoundingClientRect()
  1750. return new CGRect(new CGPoint(rect.left, rect.top), new CGSize(rect.width, rect.height))
  1751. }
  1752. }
  1753.  
  1754. // TODO: use extension of HTMLElement when it's supported.
  1755. //if(customElements){
  1756. // customElements.define('scn-view', SCNView)
  1757. //}