Home Reference Source Repository

js/SceneKit/SCNReferenceNode.js

  1. 'use strict'
  2.  
  3. import SCNNode from './SCNNode'
  4. import SCNReferenceLoadingPolicy from './SCNReferenceLoadingPolicy'
  5. import SCNScene from './SCNScene'
  6.  
  7. /**
  8. * A scene graph node that serves as a placeholder for content to be loaded from a separate scene file.
  9. * @access public
  10. * @extends {SCNNode}
  11. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode
  12. */
  13. export default class SCNReferenceNode extends SCNNode {
  14. static get _propTypes() {
  15. return {
  16. paused: ['boolean', 'isPaused'],
  17. scale: ['SCNVector3', '_scale'],
  18. rotation: ['SCNVector4', '_rotation'],
  19. orientation: ['SCNVector4', (obj, value) => {
  20. obj.orientation = value
  21. }],
  22. position: ['SCNVector3', '_position'],
  23. loadingPolicy: 'integer',
  24. referenceURL: ['NSURL', (obj, value) => {
  25. obj.referenceURL = value
  26. obj.load()
  27. }],
  28. opacity: ['float', '_opacity'],
  29. castsShadow: 'boolean',
  30. categoryBitMask: 'integer',
  31. hidden: ['boolean', 'isHidden'],
  32. name: 'string',
  33. renderingOrder: 'integer',
  34. movabilityHint: 'integer',
  35.  
  36. clientAttributes: ['NSMutableDictionary', null],
  37. overrides: ['NSObject', null] // what is this?
  38. }
  39. }
  40.  
  41. // Creating a Reference Node
  42.  
  43. /**
  44. * Initializes a node whose content is to be loaded from the referenced URL.
  45. * @access public
  46. * @constructor
  47. * @param {string} referenceURL - The URL to a scene file from which to load the node’s content.
  48. * @desc Using this initializer does not load the node’s content. To load content from the referenced URL, use the load() method.
  49. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1523967-init
  50. */
  51. constructor(referenceURL) {
  52. super()
  53.  
  54. /**
  55. * @access private
  56. * @type {boolean}
  57. */
  58. this._isLoading = false
  59.  
  60. /**
  61. * @access private
  62. * @type {boolean}
  63. */
  64. this._isLoaded = false
  65.  
  66. // Loading and Unloading a Reference Node’s Content
  67.  
  68. /**
  69. * An option for whether to load the node’s content automatically.
  70. * @type {SCNReferenceLoadingPolicy}
  71. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1522996-loadingpolicy
  72. */
  73. this.loadingPolicy = null
  74.  
  75. /**
  76. * The URL to a scene file from which to load content for the reference node.
  77. * @type {string}
  78. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1522733-referenceurl
  79. */
  80. this._referenceURL = referenceURL
  81.  
  82. this._scene = null
  83.  
  84. if(referenceURL){
  85. this.load()
  86. }
  87.  
  88. /**
  89. * @access private
  90. * @type {Promise}
  91. */
  92. this._loadedPromise = null
  93. }
  94.  
  95. // Loading and Unloading a Reference Node’s Content
  96.  
  97. /**
  98. * Loads content into the node from its referenced external scene file.
  99. * @access public
  100. * @returns {void}
  101. * @desc When SceneKit loads the referenced scene file, all children of the scene file’s root node become children of the reference node.If the node has already been loaded (either automatically, according to the loadingPolicy property, or through a previous call to this method), calling this method has no effect.
  102. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1523204-load
  103. */
  104. load() {
  105. if(this._isLoaded || this._isLoading){
  106. return
  107. }
  108. if(!this._referenceURL){
  109. return
  110. }
  111. this._isLoading = true
  112.  
  113. const promise = new Promise((resolve, reject) => {
  114. const scene = new SCNScene(this._referenceURL, null)
  115. scene.didLoad.then(() => {
  116. scene.rootNode.name = 'referenceRoot'
  117. super.addChildNode(scene.rootNode)
  118. this._scene = scene
  119.  
  120. this._isLoaded = true
  121. this._isLoading = false
  122. resolve()
  123. }).catch(() => {
  124. reject()
  125. })
  126. })
  127. this._loadedPromise = promise.then(() => this._scene.didLoad)
  128. }
  129.  
  130. /**
  131. * Removes the node’s children and marks the node as not loaded.
  132. * @access public
  133. * @returns {void}
  134. * @desc Calling this method does not necessarily unload any content associated with the node’s child nodes from memory—it merely removes them from the scene graph. The unlinked nodes and their content are then subject to normal object memory management rules. Under ARC, those objects are deallocated if and only if they are not referenced from elsewhere in your program.
  135. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1523566-unload
  136. */
  137. unload() {
  138. if(!this._isLoaded){
  139. return
  140. }
  141. this.childNodes.forEach((child) => {
  142. child.removeFromParentNode()
  143. })
  144. this._isLoaded = false
  145. this._loadedPromise = null
  146. }
  147.  
  148. /**
  149. * A Boolean value that indicates whether the reference node has already loaded its content.
  150. * @type {boolean}
  151. * @desc
  152. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1523906-isloaded
  153. */
  154. get isLoaded() {
  155. return this._isLoaded
  156. }
  157.  
  158. // Initializers
  159.  
  160. /**
  161. *
  162. * @access public
  163. * @param {NSCoder} aDecoder -
  164. * @returns {void}
  165. * @see https://developer.apple.com/documentation/scenekit/scnreferencenode/1524061-init
  166. */
  167. initCoder(aDecoder) {
  168. }
  169.  
  170. get referenceURL() {
  171. return this._referenceURL
  172. }
  173.  
  174. set referenceURL(newValue) {
  175. this.unload()
  176. this._referenceURL = newValue
  177. if(this.loadingPolicy === SCNReferenceLoadingPolicy.immediate){
  178. this.load()
  179. }
  180. }
  181.  
  182. addChildNode(child) {
  183. throw new Error('cannot add a child node to SCNReferenceNode')
  184. }
  185.  
  186. insertChildNodeAt(child, index) {
  187. throw new Error('cannot add a child node to SCNReferenceNode')
  188. }
  189.  
  190. replaceChildNodeWith(oldChild, newChild) {
  191. throw new Error('cannot add a child node to SCNReferenceNode')
  192. }
  193.  
  194. get childNodes() {
  195. // FIXME: needs synchronous loading
  196. if(!this._isLoaded){
  197. this.load()
  198. }
  199. return this._childNodes.slice(0)
  200. }
  201.  
  202. /**
  203. * @access private
  204. * @returns {Promise} -
  205. */
  206. _getLoadedPromise() {
  207. if(this._loadedPromise){
  208. return this._loadedPromise
  209. }
  210. this.load()
  211. return this._loadedPromise
  212. }
  213.  
  214. /**
  215. * @access public
  216. * @type {Promise} -
  217. */
  218. get didLoad() {
  219. return this._getLoadedPromise()
  220. }
  221. }