Node.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. import { NodeUpdateType } from './constants.js';
  2. import { getNodesKeys, getCacheKey } from './NodeUtils.js';
  3. import { MathUtils } from 'three';
  4. let _nodeId = 0;
  5. class Node {
  6. constructor( nodeType = null ) {
  7. this.isNode = true;
  8. this.nodeType = nodeType;
  9. this.updateType = NodeUpdateType.NONE;
  10. this.uuid = MathUtils.generateUUID();
  11. Object.defineProperty( this, 'id', { value: _nodeId ++ } );
  12. }
  13. get type() {
  14. return this.constructor.name;
  15. }
  16. isGlobal( /*builder*/ ) {
  17. return false;
  18. }
  19. getChildren() {
  20. const children = [];
  21. for ( const property in this ) {
  22. const object = this[ property ];
  23. if ( Array.isArray( object ) === true ) {
  24. for ( const child of object ) {
  25. if ( child && child.isNode === true ) {
  26. children.push( child );
  27. }
  28. }
  29. } else if ( object && object.isNode === true ) {
  30. children.push( object );
  31. } else if ( typeof object === 'object' ) {
  32. for ( const property in object ) {
  33. const child = object[ property ];
  34. if ( child && child.isNode === true ) {
  35. children.push( child );
  36. }
  37. }
  38. }
  39. }
  40. return children;
  41. }
  42. getCacheKey() {
  43. return getCacheKey( this );
  44. }
  45. getHash( /*builder*/ ) {
  46. return this.uuid;
  47. }
  48. getUpdateType( /*builder*/ ) {
  49. return this.updateType;
  50. }
  51. getNodeType( /*builder*/ ) {
  52. return this.nodeType;
  53. }
  54. getReference( builder ) {
  55. const hash = this.getHash( builder );
  56. const nodeFromHash = builder.getNodeFromHash( hash );
  57. return nodeFromHash || this;
  58. }
  59. construct( builder ) {
  60. const nodeProperties = builder.getNodeProperties( this );
  61. for ( const childNode of this.getChildren() ) {
  62. nodeProperties[ '_node' + childNode.id ] = childNode;
  63. }
  64. // return a outputNode if exists
  65. return null;
  66. }
  67. analyze( builder ) {
  68. const nodeData = builder.getDataFromNode( this );
  69. nodeData.dependenciesCount = nodeData.dependenciesCount === undefined ? 1 : nodeData.dependenciesCount + 1;
  70. if ( nodeData.dependenciesCount === 1 ) {
  71. // node flow children
  72. const nodeProperties = builder.getNodeProperties( this );
  73. for ( const childNode of Object.values( nodeProperties ) ) {
  74. if ( childNode && childNode.isNode === true ) {
  75. childNode.build( builder );
  76. }
  77. }
  78. }
  79. }
  80. generate( builder, output ) {
  81. const { outputNode } = builder.getNodeProperties( this );
  82. if ( outputNode && outputNode.isNode === true ) {
  83. return outputNode.build( builder, output );
  84. }
  85. }
  86. update( /*frame*/ ) {
  87. console.warn( 'Abstract function.' );
  88. }
  89. build( builder, output = null ) {
  90. const refNode = this.getReference( builder );
  91. if ( this !== refNode ) {
  92. return refNode.build( builder, output );
  93. }
  94. builder.addNode( this );
  95. builder.addStack( this );
  96. /* expected return:
  97. - "construct" -> Node
  98. - "analyze" -> null
  99. - "generate" -> String
  100. */
  101. let result = null;
  102. const buildStage = builder.getBuildStage();
  103. if ( buildStage === 'construct' ) {
  104. const properties = builder.getNodeProperties( this );
  105. if ( properties.initialized !== true || builder.context.tempRead === false ) {
  106. properties.initialized = true;
  107. properties.outputNode = this.construct( builder );
  108. for ( const childNode of Object.values( properties ) ) {
  109. if ( childNode && childNode.isNode === true ) {
  110. childNode.build( builder );
  111. }
  112. }
  113. }
  114. } else if ( buildStage === 'analyze' ) {
  115. this.analyze( builder );
  116. } else if ( buildStage === 'generate' ) {
  117. const isGenerateOnce = this.generate.length === 1;
  118. if ( isGenerateOnce ) {
  119. const type = this.getNodeType( builder );
  120. const nodeData = builder.getDataFromNode( this );
  121. result = nodeData.snippet;
  122. if ( result === undefined /*|| builder.context.tempRead === false*/ ) {
  123. result = this.generate( builder ) || '';
  124. nodeData.snippet = result;
  125. }
  126. result = builder.format( result, type, output );
  127. } else {
  128. result = this.generate( builder, output ) || '';
  129. }
  130. }
  131. builder.removeStack( this );
  132. return result;
  133. }
  134. serialize( json ) {
  135. const nodeKeys = getNodesKeys( this );
  136. if ( nodeKeys.length > 0 ) {
  137. const inputNodes = {};
  138. for ( const property of nodeKeys ) {
  139. inputNodes[ property ] = this[ property ].toJSON( json.meta ).uuid;
  140. }
  141. json.inputNodes = inputNodes;
  142. }
  143. }
  144. deserialize( json ) {
  145. if ( json.inputNodes !== undefined ) {
  146. const nodes = json.meta.nodes;
  147. for ( const property in json.inputNodes ) {
  148. const uuid = json.inputNodes[ property ];
  149. this[ property ] = nodes[ uuid ];
  150. }
  151. }
  152. }
  153. toJSON( meta ) {
  154. const { uuid, type } = this;
  155. const isRoot = ( meta === undefined || typeof meta === 'string' );
  156. if ( isRoot ) {
  157. meta = {
  158. textures: {},
  159. images: {},
  160. nodes: {}
  161. };
  162. }
  163. // serialize
  164. let data = meta.nodes[ uuid ];
  165. if ( data === undefined ) {
  166. data = {
  167. uuid,
  168. type,
  169. meta,
  170. metadata: {
  171. version: 4.5,
  172. type: 'Node',
  173. generator: 'Node.toJSON'
  174. }
  175. };
  176. meta.nodes[ data.uuid ] = data;
  177. this.serialize( data );
  178. delete data.meta;
  179. }
  180. // TODO: Copied from Object3D.toJSON
  181. function extractFromCache( cache ) {
  182. const values = [];
  183. for ( const key in cache ) {
  184. const data = cache[ key ];
  185. delete data.metadata;
  186. values.push( data );
  187. }
  188. return values;
  189. }
  190. if ( isRoot ) {
  191. const textures = extractFromCache( meta.textures );
  192. const images = extractFromCache( meta.images );
  193. const nodes = extractFromCache( meta.nodes );
  194. if ( textures.length > 0 ) data.textures = textures;
  195. if ( images.length > 0 ) data.images = images;
  196. if ( nodes.length > 0 ) data.nodes = nodes;
  197. }
  198. return data;
  199. }
  200. }
  201. export default Node;