/home/lindsay/xeolabs/xeogl-next/xeogl/src/models/model.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/src/models/model.js

  1. /**
  2. A **Model** is a {{#crossLink "Group"}}{{/crossLink}} of {{#crossLink "Component"}}Components{{/crossLink}}.
  3.  
  4. Model is an abstract base class that's subclassed by (at least):
  5.  
  6. * {{#crossLink "GLTFModel"}}{{/crossLink}}, which loads its components from glTF files.
  7. * {{#crossLink "OBJModel"}}{{/crossLink}}, which loads its components from .OBJ and .MTL files.
  8. * {{#crossLink "STLModel"}}{{/crossLink}}, which loads its components from .STL files.
  9. * {{#crossLink "SceneJSModel"}}{{/crossLink}}, which loads its components from SceneJS scene definitions.
  10. * {{#crossLink "BuildableModel"}}{{/crossLink}}, which provides a fluent API for building its components.
  11.  
  12.  
  13. @class Model
  14. @module xeogl
  15. @submodule models
  16. @constructor
  17. @param [owner] {Component} Owner component. When destroyed, the owner will destroy this component as well. Creates this component within the default {{#crossLink "Scene"}}{{/crossLink}} when omitted.
  18. @param [cfg] {*} Configs
  19. @param [cfg.id] {String} Optional ID, unique among all components in the parent scene, generated automatically when omitted.
  20. @param [cfg.meta] {String:Object} Optional map of user-defined metadata.
  21. @param [cfg.entityType] {String} Optional entity classification when using within a semantic data model. See the {{#crossLink "Object"}}{{/crossLink}} documentation for usage.
  22. @param [cfg.parent] {Object} The parent.
  23. @param [cfg.position=[0,0,0]] {Float32Array} Local 3D position.
  24. @param [cfg.scale=[1,1,1]] {Float32Array} Local scale.
  25. @param [cfg.rotation=[0,0,0]] {Float32Array} Local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis.
  26. @param [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] {Float32Array} Local modelling transform matrix. Overrides the position, scale and rotation parameters.
  27. @param [cfg.visible=true] {Boolean} Indicates if visible.
  28. @param [cfg.culled=false] {Boolean} Indicates if culled from view.
  29. @param [cfg.pickable=true] {Boolean} Indicates if pickable.
  30. @param [cfg.clippable=true] {Boolean} Indicates if clippable.
  31. @param [cfg.collidable=true] {Boolean} Indicates if included in boundary calculations.
  32. @param [cfg.castShadow=true] {Boolean} Indicates if casting shadows.
  33. @param [cfg.receiveShadow=true] {Boolean} Indicates if receiving shadows.
  34. @param [cfg.outlined=false] {Boolean} Indicates if outline is rendered.
  35. @param [cfg.ghosted=false] {Boolean} Indicates if rendered as ghosted.
  36. @param [cfg.highlighted=false] {Boolean} Indicates if rendered as highlighted.
  37. @param [cfg.selected=false] {Boolean} Indicates if rendered as selected.
  38. @param [cfg.edges=false] {Boolean} Indicates if edges are emphasized.
  39. @param [cfg.aabbVisible=false] {Boolean} Indicates if axis-aligned World-space bounding box is visible.
  40. @param [cfg.obbVisible=false] {Boolean} Indicates if oriented World-space bounding box is visible.
  41. @param [cfg.colorize=[1.0,1.0,1.0]] {Float32Array} RGB colorize color, multiplies by the rendered fragment colors.
  42. @param [cfg.opacity=1.0] {Number} Opacity factor, multiplies by the rendered fragment alpha.
  43.  
  44. @extends Group
  45. */
  46. import {core} from "../core.js";
  47. import {utils} from '../utils.js';
  48. import {Group} from "../objects/group.js";
  49. import {componentClasses} from "./../componentClasses.js";
  50.  
  51. const type = "xeogl.Model";
  52.  
  53. class Model extends Group {
  54.  
  55. /**
  56. JavaScript class name for this Component.
  57.  
  58. For example: "xeogl.AmbientLight", "xeogl.MetallicMaterial" etc.
  59.  
  60. @property type
  61. @type String
  62. @final
  63. */
  64. get type() {
  65. return type;
  66. }
  67.  
  68. init(cfg) {
  69.  
  70. /**
  71. All contained {{#crossLink "Components"}}{{/crossLink}}, mapped to their IDs.
  72.  
  73. @property components
  74. @type {{String:Component}}
  75. */
  76. this.components = {};
  77.  
  78. /**
  79. Number of contained {{#crossLink "Components"}}{{/crossLink}}.
  80.  
  81. @property numComponents
  82. @type Number
  83. */
  84. this.numComponents = 0;
  85.  
  86. /**
  87. A map of maps; for each contained {{#crossLink "Component"}}{{/crossLink}} type,
  88. a map to IDs to {{#crossLink "Component"}}{{/crossLink}} instances, eg.
  89.  
  90. ````
  91. "xeogl.Geometry": {
  92. "alpha": <xeogl.Geometry>,
  93. "beta": <xeogl.Geometry>
  94. },
  95. "xeogl.Rotate": {
  96. "charlie": <xeogl.Rotate>,
  97. "delta": <xeogl.Rotate>,
  98. "echo": <xeogl.Rotate>,
  99. },
  100. //...
  101. ````
  102.  
  103. @property types
  104. @type {String:{String:xeogl.Component}}
  105. */
  106. this.types = {};
  107.  
  108. /**
  109. All contained {{#crossLink "Object"}}Objects{{/crossLink}}, mapped to their IDs.
  110.  
  111. @property objects
  112. @final
  113. @type {{String:Object}}
  114. */
  115. this.objects = {};
  116.  
  117. /**
  118. {{#crossLink "Object"}}Objects{{/crossLink}} in this Model that have GUIDs, mapped to their GUIDs.
  119.  
  120. Each Object is registered in this map when its {{#crossLink "Object/guid:property"}}{{/crossLink}} is
  121. assigned a value.
  122.  
  123. @property guidObjects
  124. @final
  125. @type {{String:Object}}
  126. */
  127. this.guidObjects = {};
  128.  
  129. /**
  130. All contained {{#crossLink "Mesh"}}Meshes{{/crossLink}}, mapped to their IDs.
  131.  
  132. @property meshes
  133. @final
  134. @type {String:xeogl.Mesh}
  135. */
  136. this.meshes = {};
  137.  
  138. /**
  139. {{#crossLink "Object"}}Objects{{/crossLink}} in this Model that have entity types, mapped to their IDs.
  140.  
  141. Each Object is registered in this map when its {{#crossLink "Object/entityType:property"}}{{/crossLink}} is
  142. set to value.
  143.  
  144. @property entities
  145. @final
  146. @type {{String:Object}}
  147. */
  148. this.entities = {};
  149.  
  150. /**
  151. For each entity type, a map of IDs to {{#crossLink "Object"}}Objects{{/crossLink}} of that entity type.
  152.  
  153. Each Object is registered in this map when its {{#crossLink "Object/entityType:property"}}{{/crossLink}} is
  154. assigned a value.
  155.  
  156. @property entityTypes
  157. @final
  158. @type {String:{String:xeogl.Component}}
  159. */
  160. this.entityTypes = {};
  161.  
  162. /**
  163. Lazy-regenerated ID lists.
  164. */
  165. this._objectGUIDs = null;
  166. this._entityIds = null;
  167.  
  168. // xeogl.Model overrides xeogl.Group / xeogl.Object state properties, (eg. visible, ghosted etc)
  169. // and those redefined properties are being set here through the super constructor.
  170.  
  171. super.init(cfg); // Call xeogl.Group._init()
  172.  
  173. this.scene._modelCreated(this);
  174. }
  175.  
  176. _addComponent(component) {
  177. let componentId;
  178. let types;
  179. if (utils.isNumeric(component) || utils.isString(component)) { // Component ID
  180. component = this.scene.components[component];
  181. if (!component) {
  182. this.warn("Component not found: " + utils.inQuotes(component));
  183. return;
  184. }
  185. } else if (utils.isObject(component)) { // Component config
  186. const type = component.type || "xeogl.Component";
  187. if (!core.isComponentType(type)) {
  188. this.error("Not a xeogl component type: " + type);
  189. return;
  190. }
  191. component = new window[type](this.scene, component);
  192. }
  193. if (component.scene !== this.scene) { // Component in wrong Scene
  194. this.error("Attempted to add component from different xeogl.Scene: " + utils.inQuotes(component.id));
  195. return;
  196. }
  197. if (this.components[component.id]) { // Component already in this Model
  198. return;
  199. }
  200. if (component.model && component.model.id !== this.id) { // Component in other Model
  201. component.model._removeComponent(component); // Transferring to this Model
  202. }
  203. this.components[component.id] = component;
  204. types = this.types[component.type];
  205. if (!types) {
  206. types = this.types[component.type] = {};
  207. }
  208. types[component.id] = component;
  209. if (component.isType("xeogl.Object")) {
  210. const object = component;
  211. this.objects[object.id] = object;
  212. if (object.entityType) {
  213. this.entities[object.id] = object;
  214. let objectsOfType = this.entityTypes[object.entityType];
  215. if (!objectsOfType) {
  216. objectsOfType = {};
  217. this.entityTypes[object.entityType] = objectsOfType;
  218. }
  219. objectsOfType[object.id] = object;
  220. this._entityIds = null; // Lazy regenerate
  221. this._entityTypeIds = null; // Lazy regenerate
  222. }
  223. if (object.guid) {
  224. this.guidObjects[object.id] = object;
  225. this._objectGUIDs = null; // To lazy-rebuild
  226. }
  227. if (component.isType("xeogl.Mesh")) {
  228. this.meshes[component.id] = component;
  229. }
  230. }
  231. this.numComponents++;
  232. component._addedToModel(this);
  233. return component;
  234. }
  235.  
  236. _removeComponent(component) {
  237. const id = component.id;
  238. delete this.components[id];
  239. delete this.meshes[id];
  240. delete this.objects[id];
  241. if (component.entityType) {
  242. delete this.entities[id];
  243. const objectsOfType = this.entityTypes[component.entityType];
  244. if (objectsOfType) {
  245. delete objectsOfType[id];
  246. }
  247. this._entityIds = null; // Lazy regenerate
  248. this._entityTypeIds = null; // Lazy regenerate
  249. }
  250. if (component.guid) {
  251. delete this.guidObjects[component.guid];
  252. this._objectGUIDs = null; // To lazy-rebuild
  253. }
  254. }
  255.  
  256. /**
  257. Destroys all {{#crossLink "Component"}}Components{{/crossLink}} in this Model.
  258. @method clear
  259. */
  260. clear() {
  261. // For efficiency, destroy Meshes first to avoid
  262. // xeogl's automatic default component substitutions
  263. for (var id in this.meshes) {
  264. if (this.meshes.hasOwnProperty(id)) {
  265. this.meshes[id].destroy();
  266. }
  267. }
  268. for (var id in this.components) {
  269. if (this.components.hasOwnProperty(id)) {
  270. this.components[id].destroy(); // Groups in this Model will remove themselves when they're destroyed
  271. }
  272. }
  273. this.components = {};
  274. this.numComponents = 0;
  275. this.types = {};
  276. this.objects = {};
  277. this.meshes = {};
  278. this.entities = {};
  279. }
  280.  
  281. /**
  282. Convenience array of entity type IDs in {{#crossLink "Model/entityTypes:property"}}{{/crossLink}}.
  283. @property entityTypeIds
  284. @final
  285. @type {Array of String}
  286. */
  287. get objectGUIDs() {
  288. if (!this._objectGUIDs) {
  289. this._objectGUIDs = Object.keys(this.guidObjects);
  290. }
  291. return this._objectGUIDs;
  292. }
  293.  
  294. /**
  295. Convenience array of entity type IDs in {{#crossLink "Model/entityTypes:property"}}{{/crossLink}}.
  296. @property entityTypeIds
  297. @final
  298. @type {Array of String}
  299. */
  300. get entityTypeIds() {
  301. if (!this._entityTypeIds) {
  302. this._entityTypeIds = Object.keys(this.entityTypes);
  303. }
  304. return this._entityTypeIds;
  305. }
  306.  
  307. /**
  308. Convenience array of IDs in {{#crossLink "Model/entities:property"}}{{/crossLink}}.
  309. @property entityIds
  310. @final
  311. @type {Array of String}
  312. */
  313. get entityIds() {
  314. if (!this._entityIds) {
  315. this._entityIds = Object.keys(this.entities);
  316. }
  317. return this._entityIds;
  318. }
  319.  
  320. /**
  321. * @deprecated
  322. */
  323. destroyAll() {
  324. this.clear();
  325. }
  326.  
  327. destroy() {
  328. super.destroy();
  329. this.clear();
  330. this.scene._modelDestroyed(this);
  331. }
  332. }
  333.  
  334. componentClasses[type] = Model;
  335.  
  336. export{Model};