babylon.geometry.ts 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230
  1. module BABYLON {
  2. /**
  3. * Class used to store geometry data (vertex buffers + index buffer)
  4. */
  5. export class Geometry implements IGetSetVerticesData {
  6. // Members
  7. /**
  8. * Gets or sets the ID of the geometry
  9. */
  10. public id: string;
  11. /**
  12. * Gets or sets the unique ID of the geometry
  13. */
  14. public uniqueId: number;
  15. /**
  16. * Gets the delay loading state of the geometry (none by default which means not delayed)
  17. */
  18. public delayLoadState = Engine.DELAYLOADSTATE_NONE;
  19. /**
  20. * Gets the file containing the data to load when running in delay load state
  21. */
  22. public delayLoadingFile: Nullable<string>;
  23. /**
  24. * Callback called when the geometry is updated
  25. */
  26. public onGeometryUpdated: (geometry: Geometry, kind?: string) => void;
  27. // Private
  28. private _scene: Scene;
  29. private _engine: Engine;
  30. private _meshes: Mesh[];
  31. private _totalVertices = 0;
  32. /** @hidden */
  33. public _indices: IndicesArray;
  34. /** @hidden */
  35. public _vertexBuffers: { [key: string]: VertexBuffer; };
  36. private _isDisposed = false;
  37. private _extend: { minimum: Vector3, maximum: Vector3 };
  38. private _boundingBias: Vector2;
  39. /** @hidden */
  40. public _delayInfo: Array<string>;
  41. private _indexBuffer: Nullable<WebGLBuffer>;
  42. private _indexBufferIsUpdatable = false;
  43. /** @hidden */
  44. public _boundingInfo: Nullable<BoundingInfo>;
  45. /** @hidden */
  46. public _delayLoadingFunction: Nullable<(any: any, geometry: Geometry) => void>;
  47. /** @hidden */
  48. public _softwareSkinningFrameId: number;
  49. private _vertexArrayObjects: { [key: string]: WebGLVertexArrayObject; };
  50. private _updatable: boolean;
  51. // Cache
  52. /** @hidden */
  53. public _positions: Nullable<Vector3[]>;
  54. /**
  55. * Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
  56. */
  57. public get boundingBias(): Vector2 {
  58. return this._boundingBias;
  59. }
  60. /**
  61. * Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
  62. */
  63. public set boundingBias(value: Vector2) {
  64. if (this._boundingBias) {
  65. this._boundingBias.copyFrom(value);
  66. }
  67. else {
  68. this._boundingBias = value.clone();
  69. }
  70. this._updateBoundingInfo(true, null);
  71. }
  72. /**
  73. * Static function used to attach a new empty geometry to a mesh
  74. * @param mesh defines the mesh to attach the geometry to
  75. * @returns the new Geometry
  76. */
  77. public static CreateGeometryForMesh(mesh: Mesh): Geometry {
  78. let geometry = new Geometry(Geometry.RandomId(), mesh.getScene());
  79. geometry.applyToMesh(mesh);
  80. return geometry;
  81. }
  82. /**
  83. * Creates a new geometry
  84. * @param id defines the unique ID
  85. * @param scene defines the hosting scene
  86. * @param vertexData defines the VertexData used to get geometry data
  87. * @param updatable defines if geometry must be updatable (false by default)
  88. * @param mesh defines the mesh that will be associated with the geometry
  89. */
  90. constructor(id: string, scene: Scene, vertexData?: VertexData, updatable: boolean = false, mesh: Nullable<Mesh> = null) {
  91. this.id = id;
  92. this.uniqueId = scene.getUniqueId();
  93. this._engine = scene.getEngine();
  94. this._meshes = [];
  95. this._scene = scene;
  96. //Init vertex buffer cache
  97. this._vertexBuffers = {};
  98. this._indices = [];
  99. this._updatable = updatable;
  100. // vertexData
  101. if (vertexData) {
  102. this.setAllVerticesData(vertexData, updatable);
  103. }
  104. else {
  105. this._totalVertices = 0;
  106. this._indices = [];
  107. }
  108. if (this._engine.getCaps().vertexArrayObject) {
  109. this._vertexArrayObjects = {};
  110. }
  111. // applyToMesh
  112. if (mesh) {
  113. this.applyToMesh(mesh);
  114. mesh.computeWorldMatrix(true);
  115. }
  116. }
  117. /**
  118. * Gets the current extend of the geometry
  119. */
  120. public get extend(): { minimum: Vector3, maximum: Vector3 } {
  121. return this._extend;
  122. }
  123. /**
  124. * Gets the hosting scene
  125. * @returns the hosting Scene
  126. */
  127. public getScene(): Scene {
  128. return this._scene;
  129. }
  130. /**
  131. * Gets the hosting engine
  132. * @returns the hosting Engine
  133. */
  134. public getEngine(): Engine {
  135. return this._engine;
  136. }
  137. /**
  138. * Defines if the geometry is ready to use
  139. * @returns true if the geometry is ready to be used
  140. */
  141. public isReady(): boolean {
  142. return this.delayLoadState === Engine.DELAYLOADSTATE_LOADED || this.delayLoadState === Engine.DELAYLOADSTATE_NONE;
  143. }
  144. /**
  145. * Gets a value indicating that the geometry should not be serialized
  146. */
  147. public get doNotSerialize(): boolean {
  148. for (var index = 0; index < this._meshes.length; index++) {
  149. if (!this._meshes[index].doNotSerialize) {
  150. return false;
  151. }
  152. }
  153. return true;
  154. }
  155. /** @hidden */
  156. public _rebuild(): void {
  157. if (this._vertexArrayObjects) {
  158. this._vertexArrayObjects = {};
  159. }
  160. // Index buffer
  161. if (this._meshes.length !== 0 && this._indices) {
  162. this._indexBuffer = this._engine.createIndexBuffer(this._indices);
  163. }
  164. // Vertex buffers
  165. for (var key in this._vertexBuffers) {
  166. let vertexBuffer = <VertexBuffer>this._vertexBuffers[key];
  167. vertexBuffer._rebuild();
  168. }
  169. }
  170. /**
  171. * Affects all geometry data in one call
  172. * @param vertexData defines the geometry data
  173. * @param updatable defines if the geometry must be flagged as updatable (false as default)
  174. */
  175. public setAllVerticesData(vertexData: VertexData, updatable?: boolean): void {
  176. vertexData.applyToGeometry(this, updatable);
  177. this.notifyUpdate();
  178. }
  179. /**
  180. * Set specific vertex data
  181. * @param kind defines the data kind (Position, normal, etc...)
  182. * @param data defines the vertex data to use
  183. * @param updatable defines if the vertex must be flagged as updatable (false as default)
  184. * @param stride defines the stride to use (0 by default). This value is deduced from the kind value if not specified
  185. */
  186. public setVerticesData(kind: string, data: FloatArray, updatable: boolean = false, stride?: number): void {
  187. var buffer = new VertexBuffer(this._engine, data, kind, updatable, this._meshes.length === 0, stride);
  188. this.setVerticesBuffer(buffer);
  189. }
  190. /**
  191. * Removes a specific vertex data
  192. * @param kind defines the data kind (Position, normal, etc...)
  193. */
  194. public removeVerticesData(kind: string) {
  195. if (this._vertexBuffers[kind]) {
  196. this._vertexBuffers[kind].dispose();
  197. delete this._vertexBuffers[kind];
  198. }
  199. }
  200. /**
  201. * Affect a vertex buffer to the geometry. the vertexBuffer.getKind() function is used to determine where to store the data
  202. * @param buffer defines the vertex buffer to use
  203. * @param totalVertices defines the total number of vertices for position kind (could be null)
  204. */
  205. public setVerticesBuffer(buffer: VertexBuffer, totalVertices: Nullable<number> = null): void {
  206. var kind = buffer.getKind();
  207. if (this._vertexBuffers[kind]) {
  208. this._vertexBuffers[kind].dispose();
  209. }
  210. this._vertexBuffers[kind] = buffer;
  211. if (kind === VertexBuffer.PositionKind) {
  212. var data = <FloatArray>buffer.getData();
  213. if (totalVertices != null) {
  214. this._totalVertices = totalVertices;
  215. } else {
  216. if (data != null) {
  217. this._totalVertices = data.length / (buffer.byteStride / 4);
  218. }
  219. }
  220. this._updateExtend(data);
  221. this._resetPointsArrayCache();
  222. var meshes = this._meshes;
  223. var numOfMeshes = meshes.length;
  224. for (var index = 0; index < numOfMeshes; index++) {
  225. var mesh = meshes[index];
  226. mesh._boundingInfo = new BoundingInfo(this._extend.minimum, this._extend.maximum);
  227. mesh._createGlobalSubMesh(false);
  228. mesh.computeWorldMatrix(true);
  229. }
  230. }
  231. this.notifyUpdate(kind);
  232. if (this._vertexArrayObjects) {
  233. this._disposeVertexArrayObjects();
  234. this._vertexArrayObjects = {}; // Will trigger a rebuild of the VAO if supported
  235. }
  236. }
  237. /**
  238. * Update a specific vertex buffer
  239. * This function will directly update the underlying WebGLBuffer according to the passed numeric array or Float32Array
  240. * It will do nothing if the buffer is not updatable
  241. * @param kind defines the data kind (Position, normal, etc...)
  242. * @param data defines the data to use
  243. * @param offset defines the offset in the target buffer where to store the data
  244. * @param useBytes set to true if the offset is in bytes
  245. */
  246. public updateVerticesDataDirectly(kind: string, data: DataArray, offset: number, useBytes: boolean = false): void {
  247. var vertexBuffer = this.getVertexBuffer(kind);
  248. if (!vertexBuffer) {
  249. return;
  250. }
  251. vertexBuffer.updateDirectly(data, offset, useBytes);
  252. this.notifyUpdate(kind);
  253. }
  254. /**
  255. * Update a specific vertex buffer
  256. * This function will create a new buffer if the current one is not updatable
  257. * @param kind defines the data kind (Position, normal, etc...)
  258. * @param data defines the data to use
  259. * @param updateExtends defines if the geometry extends must be recomputed (false by default)
  260. */
  261. public updateVerticesData(kind: string, data: FloatArray, updateExtends: boolean = false): void {
  262. var vertexBuffer = this.getVertexBuffer(kind);
  263. if (!vertexBuffer) {
  264. return;
  265. }
  266. vertexBuffer.update(data);
  267. if (kind === VertexBuffer.PositionKind) {
  268. this._updateBoundingInfo(updateExtends, data);
  269. }
  270. this.notifyUpdate(kind);
  271. }
  272. private _updateBoundingInfo(updateExtends: boolean, data: Nullable<FloatArray>) {
  273. if (updateExtends) {
  274. this._updateExtend(data);
  275. }
  276. this._resetPointsArrayCache();
  277. if (updateExtends) {
  278. var meshes = this._meshes;
  279. for (const mesh of meshes) {
  280. if (mesh._boundingInfo) {
  281. mesh._boundingInfo.reConstruct(this._extend.minimum, this._extend.maximum);
  282. }
  283. else {
  284. mesh._boundingInfo = new BoundingInfo(this._extend.minimum, this._extend.maximum);
  285. }
  286. const subMeshes = mesh.subMeshes;
  287. for (const subMesh of subMeshes) {
  288. subMesh.refreshBoundingInfo();
  289. }
  290. }
  291. }
  292. }
  293. /** @hidden */
  294. public _bind(effect: Nullable<Effect>, indexToBind?: Nullable<WebGLBuffer>): void {
  295. if (!effect) {
  296. return;
  297. }
  298. if (indexToBind === undefined) {
  299. indexToBind = this._indexBuffer;
  300. }
  301. let vbs = this.getVertexBuffers();
  302. if (!vbs) {
  303. return;
  304. }
  305. if (indexToBind != this._indexBuffer || !this._vertexArrayObjects) {
  306. this._engine.bindBuffers(vbs, indexToBind, effect);
  307. return;
  308. }
  309. // Using VAO
  310. if (!this._vertexArrayObjects[effect.key]) {
  311. this._vertexArrayObjects[effect.key] = this._engine.recordVertexArrayObject(vbs, indexToBind, effect);
  312. }
  313. this._engine.bindVertexArrayObject(this._vertexArrayObjects[effect.key], indexToBind);
  314. }
  315. /**
  316. * Gets total number of vertices
  317. * @returns the total number of vertices
  318. */
  319. public getTotalVertices(): number {
  320. if (!this.isReady()) {
  321. return 0;
  322. }
  323. return this._totalVertices;
  324. }
  325. /**
  326. * Gets a specific vertex data attached to this geometry. Float data is constructed if the vertex buffer data cannot be returned directly.
  327. * @param kind defines the data kind (Position, normal, etc...)
  328. * @param copyWhenShared defines if the returned array must be cloned upon returning it if the current geometry is shared between multiple meshes
  329. * @param forceCopy defines a boolean indicating that the returned array must be cloned upon returning it
  330. * @returns a float array containing vertex data
  331. */
  332. public getVerticesData(kind: string, copyWhenShared?: boolean, forceCopy?: boolean): Nullable<FloatArray> {
  333. const vertexBuffer = this.getVertexBuffer(kind);
  334. if (!vertexBuffer) {
  335. return null;
  336. }
  337. let data = vertexBuffer.getData();
  338. if (!data) {
  339. return null;
  340. }
  341. const tightlyPackedByteStride = vertexBuffer.getSize() * VertexBuffer.GetTypeByteLength(vertexBuffer.type);
  342. const count = this._totalVertices * vertexBuffer.getSize();
  343. if (vertexBuffer.type !== VertexBuffer.FLOAT || vertexBuffer.byteStride !== tightlyPackedByteStride) {
  344. const copy : number[] = [];
  345. vertexBuffer.forEach(count, (value) => copy.push(value));
  346. return copy;
  347. }
  348. if (!((data instanceof Array) || (data instanceof Float32Array)) || vertexBuffer.byteOffset !== 0 || data.length !== count) {
  349. if (data instanceof Array) {
  350. const offset = vertexBuffer.byteOffset / 4;
  351. return Tools.Slice(data, offset, offset + count);
  352. }
  353. else if (data instanceof ArrayBuffer) {
  354. return new Float32Array(data, vertexBuffer.byteOffset, count);
  355. }
  356. else {
  357. const offset = data.byteOffset + vertexBuffer.byteOffset;
  358. if (forceCopy || (copyWhenShared && this._meshes.length !== 1)) {
  359. let result = new Float32Array(count);
  360. let source = new Float32Array(data.buffer, offset, count);
  361. result.set(source);
  362. return result;
  363. }
  364. return new Float32Array(data.buffer, offset, count);
  365. }
  366. }
  367. if (forceCopy || (copyWhenShared && this._meshes.length !== 1)) {
  368. return Tools.Slice(data);
  369. }
  370. return data;
  371. }
  372. /**
  373. * Returns a boolean defining if the vertex data for the requested `kind` is updatable
  374. * @param kind defines the data kind (Position, normal, etc...)
  375. * @returns true if the vertex buffer with the specified kind is updatable
  376. */
  377. public isVertexBufferUpdatable(kind: string): boolean {
  378. let vb = this._vertexBuffers[kind];
  379. if (!vb) {
  380. return false;
  381. }
  382. return vb.isUpdatable();
  383. }
  384. /**
  385. * Gets a specific vertex buffer
  386. * @param kind defines the data kind (Position, normal, etc...)
  387. * @returns a VertexBuffer
  388. */
  389. public getVertexBuffer(kind: string): Nullable<VertexBuffer> {
  390. if (!this.isReady()) {
  391. return null;
  392. }
  393. return this._vertexBuffers[kind];
  394. }
  395. /**
  396. * Returns all vertex buffers
  397. * @return an object holding all vertex buffers indexed by kind
  398. */
  399. public getVertexBuffers(): Nullable<{ [key: string]: VertexBuffer; }> {
  400. if (!this.isReady()) {
  401. return null;
  402. }
  403. return this._vertexBuffers;
  404. }
  405. /**
  406. * Gets a boolean indicating if specific vertex buffer is present
  407. * @param kind defines the data kind (Position, normal, etc...)
  408. * @returns true if data is present
  409. */
  410. public isVerticesDataPresent(kind: string): boolean {
  411. if (!this._vertexBuffers) {
  412. if (this._delayInfo) {
  413. return this._delayInfo.indexOf(kind) !== -1;
  414. }
  415. return false;
  416. }
  417. return this._vertexBuffers[kind] !== undefined;
  418. }
  419. /**
  420. * Gets a list of all attached data kinds (Position, normal, etc...)
  421. * @returns a list of string containing all kinds
  422. */
  423. public getVerticesDataKinds(): string[] {
  424. var result = [];
  425. var kind;
  426. if (!this._vertexBuffers && this._delayInfo) {
  427. for (kind in this._delayInfo) {
  428. result.push(kind);
  429. }
  430. } else {
  431. for (kind in this._vertexBuffers) {
  432. result.push(kind);
  433. }
  434. }
  435. return result;
  436. }
  437. /**
  438. * Update index buffer
  439. * @param indices defines the indices to store in the index buffer
  440. * @param offset defines the offset in the target buffer where to store the data
  441. */
  442. public updateIndices(indices: IndicesArray, offset?: number): void {
  443. if (!this._indexBuffer) {
  444. return;
  445. }
  446. if (!this._indexBufferIsUpdatable) {
  447. this.setIndices(indices, null, true);
  448. } else {
  449. const needToUpdateSubMeshes = indices.length !== this._indices.length;
  450. this._indices = indices;
  451. this._engine.updateDynamicIndexBuffer(this._indexBuffer, indices, offset);
  452. if (needToUpdateSubMeshes) {
  453. for (const mesh of this._meshes) {
  454. mesh._createGlobalSubMesh(true);
  455. }
  456. }
  457. }
  458. }
  459. /**
  460. * Creates a new index buffer
  461. * @param indices defines the indices to store in the index buffer
  462. * @param totalVertices defines the total number of vertices (could be null)
  463. * @param updatable defines if the index buffer must be flagged as updatable (false by default)
  464. */
  465. public setIndices(indices: IndicesArray, totalVertices: Nullable<number> = null, updatable: boolean = false): void {
  466. if (this._indexBuffer) {
  467. this._engine._releaseBuffer(this._indexBuffer);
  468. }
  469. this._disposeVertexArrayObjects();
  470. this._indices = indices;
  471. this._indexBufferIsUpdatable = updatable;
  472. if (this._meshes.length !== 0 && this._indices) {
  473. this._indexBuffer = this._engine.createIndexBuffer(this._indices, updatable);
  474. }
  475. if (totalVertices != undefined) { // including null and undefined
  476. this._totalVertices = totalVertices;
  477. }
  478. for (const mesh of this._meshes) {
  479. mesh._createGlobalSubMesh(true);
  480. }
  481. this.notifyUpdate();
  482. }
  483. /**
  484. * Return the total number of indices
  485. * @returns the total number of indices
  486. */
  487. public getTotalIndices(): number {
  488. if (!this.isReady()) {
  489. return 0;
  490. }
  491. return this._indices.length;
  492. }
  493. /**
  494. * Gets the index buffer array
  495. * @param copyWhenShared defines if the returned array must be cloned upon returning it if the current geometry is shared between multiple meshes
  496. * @param forceCopy defines a boolean indicating that the returned array must be cloned upon returning it
  497. * @returns the index buffer array
  498. */
  499. public getIndices(copyWhenShared?: boolean, forceCopy?: boolean): Nullable<IndicesArray> {
  500. if (!this.isReady()) {
  501. return null;
  502. }
  503. var orig = this._indices;
  504. if (!forceCopy && (!copyWhenShared || this._meshes.length === 1)) {
  505. return orig;
  506. } else {
  507. var len = orig.length;
  508. var copy = [];
  509. for (var i = 0; i < len; i++) {
  510. copy.push(orig[i]);
  511. }
  512. return copy;
  513. }
  514. }
  515. /**
  516. * Gets the index buffer
  517. * @return the index buffer
  518. */
  519. public getIndexBuffer(): Nullable<WebGLBuffer> {
  520. if (!this.isReady()) {
  521. return null;
  522. }
  523. return this._indexBuffer;
  524. }
  525. /** @hidden */
  526. public _releaseVertexArrayObject(effect: Nullable<Effect> = null) {
  527. if (!effect || !this._vertexArrayObjects) {
  528. return;
  529. }
  530. if (this._vertexArrayObjects[effect.key]) {
  531. this._engine.releaseVertexArrayObject(this._vertexArrayObjects[effect.key]);
  532. delete this._vertexArrayObjects[effect.key];
  533. }
  534. }
  535. /**
  536. * Release the associated resources for a specific mesh
  537. * @param mesh defines the source mesh
  538. * @param shouldDispose defines if the geometry must be disposed if there is no more mesh pointing to it
  539. */
  540. public releaseForMesh(mesh: Mesh, shouldDispose?: boolean): void {
  541. var meshes = this._meshes;
  542. var index = meshes.indexOf(mesh);
  543. if (index === -1) {
  544. return;
  545. }
  546. meshes.splice(index, 1);
  547. mesh._geometry = null;
  548. if (meshes.length === 0 && shouldDispose) {
  549. this.dispose();
  550. }
  551. }
  552. /**
  553. * Apply current geometry to a given mesh
  554. * @param mesh defines the mesh to apply geometry to
  555. */
  556. public applyToMesh(mesh: Mesh): void {
  557. if (mesh._geometry === this) {
  558. return;
  559. }
  560. var previousGeometry = mesh._geometry;
  561. if (previousGeometry) {
  562. previousGeometry.releaseForMesh(mesh);
  563. }
  564. var meshes = this._meshes;
  565. // must be done before setting vertexBuffers because of mesh._createGlobalSubMesh()
  566. mesh._geometry = this;
  567. this._scene.pushGeometry(this);
  568. meshes.push(mesh);
  569. if (this.isReady()) {
  570. this._applyToMesh(mesh);
  571. }
  572. else {
  573. mesh._boundingInfo = this._boundingInfo;
  574. }
  575. }
  576. private _updateExtend(data: Nullable<FloatArray> = null) {
  577. if (!data) {
  578. data = this.getVerticesData(VertexBuffer.PositionKind)!;
  579. }
  580. this._extend = Tools.ExtractMinAndMax(data, 0, this._totalVertices, this.boundingBias, 3);
  581. }
  582. private _applyToMesh(mesh: Mesh): void {
  583. var numOfMeshes = this._meshes.length;
  584. // vertexBuffers
  585. for (var kind in this._vertexBuffers) {
  586. if (numOfMeshes === 1) {
  587. this._vertexBuffers[kind].create();
  588. }
  589. var buffer = this._vertexBuffers[kind].getBuffer();
  590. if (buffer) {
  591. buffer.references = numOfMeshes;
  592. }
  593. if (kind === VertexBuffer.PositionKind) {
  594. if (!this._extend) {
  595. this._updateExtend();
  596. }
  597. mesh._boundingInfo = new BoundingInfo(this._extend.minimum, this._extend.maximum);
  598. mesh._createGlobalSubMesh(false);
  599. //bounding info was just created again, world matrix should be applied again.
  600. mesh._updateBoundingInfo();
  601. }
  602. }
  603. // indexBuffer
  604. if (numOfMeshes === 1 && this._indices && this._indices.length > 0) {
  605. this._indexBuffer = this._engine.createIndexBuffer(this._indices);
  606. }
  607. if (this._indexBuffer) {
  608. this._indexBuffer.references = numOfMeshes;
  609. }
  610. // morphTargets
  611. mesh._syncGeometryWithMorphTargetManager();
  612. // instances
  613. mesh.synchronizeInstances();
  614. }
  615. private notifyUpdate(kind?: string) {
  616. if (this.onGeometryUpdated) {
  617. this.onGeometryUpdated(this, kind);
  618. }
  619. for (var mesh of this._meshes) {
  620. mesh._markSubMeshesAsAttributesDirty();
  621. }
  622. }
  623. /**
  624. * Load the geometry if it was flagged as delay loaded
  625. * @param scene defines the hosting scene
  626. * @param onLoaded defines a callback called when the geometry is loaded
  627. */
  628. public load(scene: Scene, onLoaded?: () => void): void {
  629. if (this.delayLoadState === Engine.DELAYLOADSTATE_LOADING) {
  630. return;
  631. }
  632. if (this.isReady()) {
  633. if (onLoaded) {
  634. onLoaded();
  635. }
  636. return;
  637. }
  638. this.delayLoadState = Engine.DELAYLOADSTATE_LOADING;
  639. this._queueLoad(scene, onLoaded);
  640. }
  641. private _queueLoad(scene: Scene, onLoaded?: () => void): void {
  642. if (!this.delayLoadingFile) {
  643. return;
  644. }
  645. scene._addPendingData(this);
  646. scene._loadFile(this.delayLoadingFile, (data) => {
  647. if (!this._delayLoadingFunction) {
  648. return;
  649. }
  650. this._delayLoadingFunction(JSON.parse(data as string), this);
  651. this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
  652. this._delayInfo = [];
  653. scene._removePendingData(this);
  654. var meshes = this._meshes;
  655. var numOfMeshes = meshes.length;
  656. for (var index = 0; index < numOfMeshes; index++) {
  657. this._applyToMesh(meshes[index]);
  658. }
  659. if (onLoaded) {
  660. onLoaded();
  661. }
  662. }, undefined, true);
  663. }
  664. /**
  665. * Invert the geometry to move from a right handed system to a left handed one.
  666. */
  667. public toLeftHanded(): void {
  668. // Flip faces
  669. let tIndices = this.getIndices(false);
  670. if (tIndices != null && tIndices.length > 0) {
  671. for (let i = 0; i < tIndices.length; i += 3) {
  672. let tTemp = tIndices[i + 0];
  673. tIndices[i + 0] = tIndices[i + 2];
  674. tIndices[i + 2] = tTemp;
  675. }
  676. this.setIndices(tIndices);
  677. }
  678. // Negate position.z
  679. let tPositions = this.getVerticesData(VertexBuffer.PositionKind, false);
  680. if (tPositions != null && tPositions.length > 0) {
  681. for (let i = 0; i < tPositions.length; i += 3) {
  682. tPositions[i + 2] = -tPositions[i + 2];
  683. }
  684. this.setVerticesData(VertexBuffer.PositionKind, tPositions, false);
  685. }
  686. // Negate normal.z
  687. let tNormals = this.getVerticesData(VertexBuffer.NormalKind, false);
  688. if (tNormals != null && tNormals.length > 0) {
  689. for (let i = 0; i < tNormals.length; i += 3) {
  690. tNormals[i + 2] = -tNormals[i + 2];
  691. }
  692. this.setVerticesData(VertexBuffer.NormalKind, tNormals, false);
  693. }
  694. }
  695. // Cache
  696. /** @hidden */
  697. public _resetPointsArrayCache(): void {
  698. this._positions = null;
  699. }
  700. /** @hidden */
  701. public _generatePointsArray(): boolean {
  702. if (this._positions) {
  703. return true;
  704. }
  705. var data = this.getVerticesData(VertexBuffer.PositionKind);
  706. if (!data || data.length === 0) {
  707. return false;
  708. }
  709. this._positions = [];
  710. for (var index = 0; index < data.length; index += 3) {
  711. this._positions.push(Vector3.FromArray(data, index));
  712. }
  713. return true;
  714. }
  715. /**
  716. * Gets a value indicating if the geometry is disposed
  717. * @returns true if the geometry was disposed
  718. */
  719. public isDisposed(): boolean {
  720. return this._isDisposed;
  721. }
  722. private _disposeVertexArrayObjects(): void {
  723. if (this._vertexArrayObjects) {
  724. for (var kind in this._vertexArrayObjects) {
  725. this._engine.releaseVertexArrayObject(this._vertexArrayObjects[kind]);
  726. }
  727. this._vertexArrayObjects = {};
  728. }
  729. }
  730. /**
  731. * Free all associated resources
  732. */
  733. public dispose(): void {
  734. var meshes = this._meshes;
  735. var numOfMeshes = meshes.length;
  736. var index: number;
  737. for (index = 0; index < numOfMeshes; index++) {
  738. this.releaseForMesh(meshes[index]);
  739. }
  740. this._meshes = [];
  741. this._disposeVertexArrayObjects();
  742. for (var kind in this._vertexBuffers) {
  743. this._vertexBuffers[kind].dispose();
  744. }
  745. this._vertexBuffers = {};
  746. this._totalVertices = 0;
  747. if (this._indexBuffer) {
  748. this._engine._releaseBuffer(this._indexBuffer);
  749. }
  750. this._indexBuffer = null;
  751. this._indices = [];
  752. this.delayLoadState = Engine.DELAYLOADSTATE_NONE;
  753. this.delayLoadingFile = null;
  754. this._delayLoadingFunction = null;
  755. this._delayInfo = [];
  756. this._boundingInfo = null;
  757. this._scene.removeGeometry(this);
  758. this._isDisposed = true;
  759. }
  760. /**
  761. * Clone the current geometry into a new geometry
  762. * @param id defines the unique ID of the new geometry
  763. * @returns a new geometry object
  764. */
  765. public copy(id: string): Geometry {
  766. var vertexData = new VertexData();
  767. vertexData.indices = [];
  768. var indices = this.getIndices();
  769. if (indices) {
  770. for (var index = 0; index < indices.length; index++) {
  771. (<number[]>vertexData.indices).push(indices[index]);
  772. }
  773. }
  774. var updatable = false;
  775. var stopChecking = false;
  776. var kind;
  777. for (kind in this._vertexBuffers) {
  778. // using slice() to make a copy of the array and not just reference it
  779. var data = this.getVerticesData(kind);
  780. if (data) {
  781. if (data instanceof Float32Array) {
  782. vertexData.set(new Float32Array(<Float32Array>data), kind);
  783. } else {
  784. vertexData.set((<number[]>data).slice(0), kind);
  785. }
  786. if (!stopChecking) {
  787. let vb = this.getVertexBuffer(kind);
  788. if (vb) {
  789. updatable = vb.isUpdatable();
  790. stopChecking = !updatable;
  791. }
  792. }
  793. }
  794. }
  795. var geometry = new Geometry(id, this._scene, vertexData, updatable);
  796. geometry.delayLoadState = this.delayLoadState;
  797. geometry.delayLoadingFile = this.delayLoadingFile;
  798. geometry._delayLoadingFunction = this._delayLoadingFunction;
  799. for (kind in this._delayInfo) {
  800. geometry._delayInfo = geometry._delayInfo || [];
  801. geometry._delayInfo.push(kind);
  802. }
  803. // Bounding info
  804. geometry._boundingInfo = new BoundingInfo(this._extend.minimum, this._extend.maximum);
  805. return geometry;
  806. }
  807. /**
  808. * Serialize the current geometry info (and not the vertices data) into a JSON object
  809. * @return a JSON representation of the current geometry data (without the vertices data)
  810. */
  811. public serialize(): any {
  812. var serializationObject: any = {};
  813. serializationObject.id = this.id;
  814. serializationObject.updatable = this._updatable;
  815. if (Tags && Tags.HasTags(this)) {
  816. serializationObject.tags = Tags.GetTags(this);
  817. }
  818. return serializationObject;
  819. }
  820. private toNumberArray(origin: Nullable<Float32Array | IndicesArray>): number[] {
  821. if (Array.isArray(origin)) {
  822. return origin;
  823. } else {
  824. return Array.prototype.slice.call(origin);
  825. }
  826. }
  827. /**
  828. * Serialize all vertices data into a JSON oject
  829. * @returns a JSON representation of the current geometry data
  830. */
  831. public serializeVerticeData(): any {
  832. var serializationObject = this.serialize();
  833. if (this.isVerticesDataPresent(VertexBuffer.PositionKind)) {
  834. serializationObject.positions = this.toNumberArray(this.getVerticesData(VertexBuffer.PositionKind));
  835. if (this.isVertexBufferUpdatable(VertexBuffer.PositionKind)) {
  836. serializationObject.positions._updatable = true;
  837. }
  838. }
  839. if (this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
  840. serializationObject.normals = this.toNumberArray(this.getVerticesData(VertexBuffer.NormalKind));
  841. if (this.isVertexBufferUpdatable(VertexBuffer.NormalKind)) {
  842. serializationObject.normals._updatable = true;
  843. }
  844. }
  845. if (this.isVerticesDataPresent(VertexBuffer.TangentKind)) {
  846. serializationObject.tangets = this.toNumberArray(this.getVerticesData(VertexBuffer.TangentKind));
  847. if (this.isVertexBufferUpdatable(VertexBuffer.TangentKind)) {
  848. serializationObject.tangets._updatable = true;
  849. }
  850. }
  851. if (this.isVerticesDataPresent(VertexBuffer.UVKind)) {
  852. serializationObject.uvs = this.toNumberArray(this.getVerticesData(VertexBuffer.UVKind));
  853. if (this.isVertexBufferUpdatable(VertexBuffer.UVKind)) {
  854. serializationObject.uvs._updatable = true;
  855. }
  856. }
  857. if (this.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  858. serializationObject.uv2s = this.toNumberArray(this.getVerticesData(VertexBuffer.UV2Kind));
  859. if (this.isVertexBufferUpdatable(VertexBuffer.UV2Kind)) {
  860. serializationObject.uv2s._updatable = true;
  861. }
  862. }
  863. if (this.isVerticesDataPresent(VertexBuffer.UV3Kind)) {
  864. serializationObject.uv3s = this.toNumberArray(this.getVerticesData(VertexBuffer.UV3Kind));
  865. if (this.isVertexBufferUpdatable(VertexBuffer.UV3Kind)) {
  866. serializationObject.uv3s._updatable = true;
  867. }
  868. }
  869. if (this.isVerticesDataPresent(VertexBuffer.UV4Kind)) {
  870. serializationObject.uv4s = this.toNumberArray(this.getVerticesData(VertexBuffer.UV4Kind));
  871. if (this.isVertexBufferUpdatable(VertexBuffer.UV4Kind)) {
  872. serializationObject.uv4s._updatable = true;
  873. }
  874. }
  875. if (this.isVerticesDataPresent(VertexBuffer.UV5Kind)) {
  876. serializationObject.uv5s = this.toNumberArray(this.getVerticesData(VertexBuffer.UV5Kind));
  877. if (this.isVertexBufferUpdatable(VertexBuffer.UV5Kind)) {
  878. serializationObject.uv5s._updatable = true;
  879. }
  880. }
  881. if (this.isVerticesDataPresent(VertexBuffer.UV6Kind)) {
  882. serializationObject.uv6s = this.toNumberArray(this.getVerticesData(VertexBuffer.UV6Kind));
  883. if (this.isVertexBufferUpdatable(VertexBuffer.UV6Kind)) {
  884. serializationObject.uv6s._updatable = true;
  885. }
  886. }
  887. if (this.isVerticesDataPresent(VertexBuffer.ColorKind)) {
  888. serializationObject.colors = this.toNumberArray(this.getVerticesData(VertexBuffer.ColorKind));
  889. if (this.isVertexBufferUpdatable(VertexBuffer.ColorKind)) {
  890. serializationObject.colors._updatable = true;
  891. }
  892. }
  893. if (this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind)) {
  894. serializationObject.matricesIndices = this.toNumberArray(this.getVerticesData(VertexBuffer.MatricesIndicesKind));
  895. serializationObject.matricesIndices._isExpanded = true;
  896. if (this.isVertexBufferUpdatable(VertexBuffer.MatricesIndicesKind)) {
  897. serializationObject.matricesIndices._updatable = true;
  898. }
  899. }
  900. if (this.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)) {
  901. serializationObject.matricesWeights = this.toNumberArray(this.getVerticesData(VertexBuffer.MatricesWeightsKind));
  902. if (this.isVertexBufferUpdatable(VertexBuffer.MatricesWeightsKind)) {
  903. serializationObject.matricesWeights._updatable = true;
  904. }
  905. }
  906. serializationObject.indices = this.toNumberArray(this.getIndices());
  907. return serializationObject;
  908. }
  909. // Statics
  910. /**
  911. * Extracts a clone of a mesh geometry
  912. * @param mesh defines the source mesh
  913. * @param id defines the unique ID of the new geometry object
  914. * @returns the new geometry object
  915. */
  916. public static ExtractFromMesh(mesh: Mesh, id: string): Nullable<Geometry> {
  917. var geometry = mesh._geometry;
  918. if (!geometry) {
  919. return null;
  920. }
  921. return geometry.copy(id);
  922. }
  923. /**
  924. * You should now use Tools.RandomId(), this method is still here for legacy reasons.
  925. * Implementation from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#answer-2117523
  926. * Be aware Math.random() could cause collisions, but:
  927. * "All but 6 of the 128 bits of the ID are randomly generated, which means that for any two ids, there's a 1 in 2^^122 (or 5.3x10^^36) chance they'll collide"
  928. * @returns a string containing a new GUID
  929. */
  930. public static RandomId(): string {
  931. return Tools.RandomId();
  932. }
  933. /** @hidden */
  934. public static _ImportGeometry(parsedGeometry: any, mesh: Mesh): void {
  935. var scene = mesh.getScene();
  936. // Geometry
  937. var geometryId = parsedGeometry.geometryId;
  938. if (geometryId) {
  939. var geometry = scene.getGeometryByID(geometryId);
  940. if (geometry) {
  941. geometry.applyToMesh(mesh);
  942. }
  943. } else if (parsedGeometry instanceof ArrayBuffer) {
  944. var binaryInfo = mesh._binaryInfo;
  945. if (binaryInfo.positionsAttrDesc && binaryInfo.positionsAttrDesc.count > 0) {
  946. var positionsData = new Float32Array(parsedGeometry, binaryInfo.positionsAttrDesc.offset, binaryInfo.positionsAttrDesc.count);
  947. mesh.setVerticesData(VertexBuffer.PositionKind, positionsData, false);
  948. }
  949. if (binaryInfo.normalsAttrDesc && binaryInfo.normalsAttrDesc.count > 0) {
  950. var normalsData = new Float32Array(parsedGeometry, binaryInfo.normalsAttrDesc.offset, binaryInfo.normalsAttrDesc.count);
  951. mesh.setVerticesData(VertexBuffer.NormalKind, normalsData, false);
  952. }
  953. if (binaryInfo.tangetsAttrDesc && binaryInfo.tangetsAttrDesc.count > 0) {
  954. var tangentsData = new Float32Array(parsedGeometry, binaryInfo.tangetsAttrDesc.offset, binaryInfo.tangetsAttrDesc.count);
  955. mesh.setVerticesData(VertexBuffer.TangentKind, tangentsData, false);
  956. }
  957. if (binaryInfo.uvsAttrDesc && binaryInfo.uvsAttrDesc.count > 0) {
  958. var uvsData = new Float32Array(parsedGeometry, binaryInfo.uvsAttrDesc.offset, binaryInfo.uvsAttrDesc.count);
  959. mesh.setVerticesData(VertexBuffer.UVKind, uvsData, false);
  960. }
  961. if (binaryInfo.uvs2AttrDesc && binaryInfo.uvs2AttrDesc.count > 0) {
  962. var uvs2Data = new Float32Array(parsedGeometry, binaryInfo.uvs2AttrDesc.offset, binaryInfo.uvs2AttrDesc.count);
  963. mesh.setVerticesData(VertexBuffer.UV2Kind, uvs2Data, false);
  964. }
  965. if (binaryInfo.uvs3AttrDesc && binaryInfo.uvs3AttrDesc.count > 0) {
  966. var uvs3Data = new Float32Array(parsedGeometry, binaryInfo.uvs3AttrDesc.offset, binaryInfo.uvs3AttrDesc.count);
  967. mesh.setVerticesData(VertexBuffer.UV3Kind, uvs3Data, false);
  968. }
  969. if (binaryInfo.uvs4AttrDesc && binaryInfo.uvs4AttrDesc.count > 0) {
  970. var uvs4Data = new Float32Array(parsedGeometry, binaryInfo.uvs4AttrDesc.offset, binaryInfo.uvs4AttrDesc.count);
  971. mesh.setVerticesData(VertexBuffer.UV4Kind, uvs4Data, false);
  972. }
  973. if (binaryInfo.uvs5AttrDesc && binaryInfo.uvs5AttrDesc.count > 0) {
  974. var uvs5Data = new Float32Array(parsedGeometry, binaryInfo.uvs5AttrDesc.offset, binaryInfo.uvs5AttrDesc.count);
  975. mesh.setVerticesData(VertexBuffer.UV5Kind, uvs5Data, false);
  976. }
  977. if (binaryInfo.uvs6AttrDesc && binaryInfo.uvs6AttrDesc.count > 0) {
  978. var uvs6Data = new Float32Array(parsedGeometry, binaryInfo.uvs6AttrDesc.offset, binaryInfo.uvs6AttrDesc.count);
  979. mesh.setVerticesData(VertexBuffer.UV6Kind, uvs6Data, false);
  980. }
  981. if (binaryInfo.colorsAttrDesc && binaryInfo.colorsAttrDesc.count > 0) {
  982. var colorsData = new Float32Array(parsedGeometry, binaryInfo.colorsAttrDesc.offset, binaryInfo.colorsAttrDesc.count);
  983. mesh.setVerticesData(VertexBuffer.ColorKind, colorsData, false, binaryInfo.colorsAttrDesc.stride);
  984. }
  985. if (binaryInfo.matricesIndicesAttrDesc && binaryInfo.matricesIndicesAttrDesc.count > 0) {
  986. var matricesIndicesData = new Int32Array(parsedGeometry, binaryInfo.matricesIndicesAttrDesc.offset, binaryInfo.matricesIndicesAttrDesc.count);
  987. var floatIndices = [];
  988. for (var i = 0; i < matricesIndicesData.length; i++) {
  989. var index = matricesIndicesData[i];
  990. floatIndices.push(index & 0x000000FF);
  991. floatIndices.push((index & 0x0000FF00) >> 8);
  992. floatIndices.push((index & 0x00FF0000) >> 16);
  993. floatIndices.push(index >> 24);
  994. }
  995. mesh.setVerticesData(VertexBuffer.MatricesIndicesKind, floatIndices, false);
  996. }
  997. if (binaryInfo.matricesWeightsAttrDesc && binaryInfo.matricesWeightsAttrDesc.count > 0) {
  998. var matricesWeightsData = new Float32Array(parsedGeometry, binaryInfo.matricesWeightsAttrDesc.offset, binaryInfo.matricesWeightsAttrDesc.count);
  999. mesh.setVerticesData(VertexBuffer.MatricesWeightsKind, matricesWeightsData, false);
  1000. }
  1001. if (binaryInfo.indicesAttrDesc && binaryInfo.indicesAttrDesc.count > 0) {
  1002. var indicesData = new Int32Array(parsedGeometry, binaryInfo.indicesAttrDesc.offset, binaryInfo.indicesAttrDesc.count);
  1003. mesh.setIndices(indicesData, null);
  1004. }
  1005. if (binaryInfo.subMeshesAttrDesc && binaryInfo.subMeshesAttrDesc.count > 0) {
  1006. var subMeshesData = new Int32Array(parsedGeometry, binaryInfo.subMeshesAttrDesc.offset, binaryInfo.subMeshesAttrDesc.count * 5);
  1007. mesh.subMeshes = [];
  1008. for (var i = 0; i < binaryInfo.subMeshesAttrDesc.count; i++) {
  1009. var materialIndex = subMeshesData[(i * 5) + 0];
  1010. var verticesStart = subMeshesData[(i * 5) + 1];
  1011. var verticesCount = subMeshesData[(i * 5) + 2];
  1012. var indexStart = subMeshesData[(i * 5) + 3];
  1013. var indexCount = subMeshesData[(i * 5) + 4];
  1014. SubMesh.AddToMesh(materialIndex, verticesStart, verticesCount, indexStart, indexCount, <AbstractMesh>mesh);
  1015. }
  1016. }
  1017. } else if (parsedGeometry.positions && parsedGeometry.normals && parsedGeometry.indices) {
  1018. mesh.setVerticesData(VertexBuffer.PositionKind, parsedGeometry.positions, parsedGeometry.positions._updatable);
  1019. mesh.setVerticesData(VertexBuffer.NormalKind, parsedGeometry.normals, parsedGeometry.normals._updatable);
  1020. if (parsedGeometry.tangents) {
  1021. mesh.setVerticesData(VertexBuffer.TangentKind, parsedGeometry.tangents, parsedGeometry.tangents._updatable);
  1022. }
  1023. if (parsedGeometry.uvs) {
  1024. mesh.setVerticesData(VertexBuffer.UVKind, parsedGeometry.uvs, parsedGeometry.uvs._updatable);
  1025. }
  1026. if (parsedGeometry.uvs2) {
  1027. mesh.setVerticesData(VertexBuffer.UV2Kind, parsedGeometry.uvs2, parsedGeometry.uvs2._updatable);
  1028. }
  1029. if (parsedGeometry.uvs3) {
  1030. mesh.setVerticesData(VertexBuffer.UV3Kind, parsedGeometry.uvs3, parsedGeometry.uvs3._updatable);
  1031. }
  1032. if (parsedGeometry.uvs4) {
  1033. mesh.setVerticesData(VertexBuffer.UV4Kind, parsedGeometry.uvs4, parsedGeometry.uvs4._updatable);
  1034. }
  1035. if (parsedGeometry.uvs5) {
  1036. mesh.setVerticesData(VertexBuffer.UV5Kind, parsedGeometry.uvs5, parsedGeometry.uvs5._updatable);
  1037. }
  1038. if (parsedGeometry.uvs6) {
  1039. mesh.setVerticesData(VertexBuffer.UV6Kind, parsedGeometry.uvs6, parsedGeometry.uvs6._updatable);
  1040. }
  1041. if (parsedGeometry.colors) {
  1042. mesh.setVerticesData(VertexBuffer.ColorKind, Color4.CheckColors4(parsedGeometry.colors, parsedGeometry.positions.length / 3), parsedGeometry.colors._updatable);
  1043. }
  1044. if (parsedGeometry.matricesIndices) {
  1045. if (!parsedGeometry.matricesIndices._isExpanded) {
  1046. var floatIndices = [];
  1047. for (var i = 0; i < parsedGeometry.matricesIndices.length; i++) {
  1048. var matricesIndex = parsedGeometry.matricesIndices[i];
  1049. floatIndices.push(matricesIndex & 0x000000FF);
  1050. floatIndices.push((matricesIndex & 0x0000FF00) >> 8);
  1051. floatIndices.push((matricesIndex & 0x00FF0000) >> 16);
  1052. floatIndices.push(matricesIndex >> 24);
  1053. }
  1054. mesh.setVerticesData(VertexBuffer.MatricesIndicesKind, floatIndices, parsedGeometry.matricesIndices._updatable);
  1055. } else {
  1056. delete parsedGeometry.matricesIndices._isExpanded;
  1057. mesh.setVerticesData(VertexBuffer.MatricesIndicesKind, parsedGeometry.matricesIndices, parsedGeometry.matricesIndices._updatable);
  1058. }
  1059. }
  1060. if (parsedGeometry.matricesIndicesExtra) {
  1061. if (!parsedGeometry.matricesIndicesExtra._isExpanded) {
  1062. var floatIndices = [];
  1063. for (var i = 0; i < parsedGeometry.matricesIndicesExtra.length; i++) {
  1064. var matricesIndex = parsedGeometry.matricesIndicesExtra[i];
  1065. floatIndices.push(matricesIndex & 0x000000FF);
  1066. floatIndices.push((matricesIndex & 0x0000FF00) >> 8);
  1067. floatIndices.push((matricesIndex & 0x00FF0000) >> 16);
  1068. floatIndices.push(matricesIndex >> 24);
  1069. }
  1070. mesh.setVerticesData(VertexBuffer.MatricesIndicesExtraKind, floatIndices, parsedGeometry.matricesIndicesExtra._updatable);
  1071. } else {
  1072. delete parsedGeometry.matricesIndices._isExpanded;
  1073. mesh.setVerticesData(VertexBuffer.MatricesIndicesExtraKind, parsedGeometry.matricesIndicesExtra, parsedGeometry.matricesIndicesExtra._updatable);
  1074. }
  1075. }
  1076. if (parsedGeometry.matricesWeights) {
  1077. Geometry._CleanMatricesWeights(parsedGeometry, mesh);
  1078. mesh.setVerticesData(VertexBuffer.MatricesWeightsKind, parsedGeometry.matricesWeights, parsedGeometry.matricesWeights._updatable);
  1079. }
  1080. if (parsedGeometry.matricesWeightsExtra) {
  1081. mesh.setVerticesData(VertexBuffer.MatricesWeightsExtraKind, parsedGeometry.matricesWeightsExtra, parsedGeometry.matricesWeights._updatable);
  1082. }
  1083. mesh.setIndices(parsedGeometry.indices, null);
  1084. }
  1085. // SubMeshes
  1086. if (parsedGeometry.subMeshes) {
  1087. mesh.subMeshes = [];
  1088. for (var subIndex = 0; subIndex < parsedGeometry.subMeshes.length; subIndex++) {
  1089. var parsedSubMesh = parsedGeometry.subMeshes[subIndex];
  1090. SubMesh.AddToMesh(parsedSubMesh.materialIndex, parsedSubMesh.verticesStart, parsedSubMesh.verticesCount, parsedSubMesh.indexStart, parsedSubMesh.indexCount, <AbstractMesh>mesh);
  1091. }
  1092. }
  1093. // Flat shading
  1094. if (mesh._shouldGenerateFlatShading) {
  1095. mesh.convertToFlatShadedMesh();
  1096. delete mesh._shouldGenerateFlatShading;
  1097. }
  1098. // Update
  1099. mesh.computeWorldMatrix(true);
  1100. scene.onMeshImportedObservable.notifyObservers(<AbstractMesh>mesh);
  1101. }
  1102. private static _CleanMatricesWeights(parsedGeometry: any, mesh: Mesh): void {
  1103. const epsilon: number = 1e-3;
  1104. if (!SceneLoader.CleanBoneMatrixWeights) {
  1105. return;
  1106. }
  1107. let noInfluenceBoneIndex = 0.0;
  1108. if (parsedGeometry.skeletonId > -1) {
  1109. let skeleton = mesh.getScene().getLastSkeletonByID(parsedGeometry.skeletonId);
  1110. if (!skeleton) {
  1111. return;
  1112. }
  1113. noInfluenceBoneIndex = skeleton.bones.length;
  1114. } else {
  1115. return;
  1116. }
  1117. let matricesIndices = (<FloatArray>mesh.getVerticesData(VertexBuffer.MatricesIndicesKind));
  1118. let matricesIndicesExtra = (<FloatArray>mesh.getVerticesData(VertexBuffer.MatricesIndicesExtraKind));
  1119. let matricesWeights = parsedGeometry.matricesWeights;
  1120. let matricesWeightsExtra = parsedGeometry.matricesWeightsExtra;
  1121. let influencers = parsedGeometry.numBoneInfluencer;
  1122. let size = matricesWeights.length;
  1123. for (var i = 0; i < size; i += 4) {
  1124. let weight = 0.0;
  1125. let firstZeroWeight = -1;
  1126. for (var j = 0; j < 4; j++) {
  1127. let w = matricesWeights[i + j];
  1128. weight += w;
  1129. if (w < epsilon && firstZeroWeight < 0) {
  1130. firstZeroWeight = j;
  1131. }
  1132. }
  1133. if (matricesWeightsExtra) {
  1134. for (var j = 0; j < 4; j++) {
  1135. let w = matricesWeightsExtra[i + j];
  1136. weight += w;
  1137. if (w < epsilon && firstZeroWeight < 0) {
  1138. firstZeroWeight = j + 4;
  1139. }
  1140. }
  1141. }
  1142. if (firstZeroWeight < 0 || firstZeroWeight > (influencers - 1)) {
  1143. firstZeroWeight = influencers - 1;
  1144. }
  1145. if (weight > epsilon) {
  1146. let mweight = 1.0 / weight;
  1147. for (var j = 0; j < 4; j++) {
  1148. matricesWeights[i + j] *= mweight;
  1149. }
  1150. if (matricesWeightsExtra) {
  1151. for (var j = 0; j < 4; j++) {
  1152. matricesWeightsExtra[i + j] *= mweight;
  1153. }
  1154. }
  1155. } else {
  1156. if (firstZeroWeight >= 4) {
  1157. matricesWeightsExtra[i + firstZeroWeight - 4] = 1.0 - weight;
  1158. matricesIndicesExtra[i + firstZeroWeight - 4] = noInfluenceBoneIndex;
  1159. } else {
  1160. matricesWeights[i + firstZeroWeight] = 1.0 - weight;
  1161. matricesIndices[i + firstZeroWeight] = noInfluenceBoneIndex;
  1162. }
  1163. }
  1164. }
  1165. mesh.setVerticesData(VertexBuffer.MatricesIndicesKind, matricesIndices);
  1166. if (parsedGeometry.matricesWeightsExtra) {
  1167. mesh.setVerticesData(VertexBuffer.MatricesIndicesExtraKind, matricesIndicesExtra);
  1168. }
  1169. }
  1170. /**
  1171. * Create a new geometry from persisted data (Using .babylon file format)
  1172. * @param parsedVertexData defines the persisted data
  1173. * @param scene defines the hosting scene
  1174. * @param rootUrl defines the root url to use to load assets (like delayed data)
  1175. * @returns the new geometry object
  1176. */
  1177. public static Parse(parsedVertexData: any, scene: Scene, rootUrl: string): Nullable<Geometry> {
  1178. if (scene.getGeometryByID(parsedVertexData.id)) {
  1179. return null; // null since geometry could be something else than a box...
  1180. }
  1181. var geometry = new Geometry(parsedVertexData.id, scene, undefined, parsedVertexData.updatable);
  1182. if (Tags) {
  1183. Tags.AddTagsTo(geometry, parsedVertexData.tags);
  1184. }
  1185. if (parsedVertexData.delayLoadingFile) {
  1186. geometry.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
  1187. geometry.delayLoadingFile = rootUrl + parsedVertexData.delayLoadingFile;
  1188. geometry._boundingInfo = new BoundingInfo(Vector3.FromArray(parsedVertexData.boundingBoxMinimum), Vector3.FromArray(parsedVertexData.boundingBoxMaximum));
  1189. geometry._delayInfo = [];
  1190. if (parsedVertexData.hasUVs) {
  1191. geometry._delayInfo.push(VertexBuffer.UVKind);
  1192. }
  1193. if (parsedVertexData.hasUVs2) {
  1194. geometry._delayInfo.push(VertexBuffer.UV2Kind);
  1195. }
  1196. if (parsedVertexData.hasUVs3) {
  1197. geometry._delayInfo.push(VertexBuffer.UV3Kind);
  1198. }
  1199. if (parsedVertexData.hasUVs4) {
  1200. geometry._delayInfo.push(VertexBuffer.UV4Kind);
  1201. }
  1202. if (parsedVertexData.hasUVs5) {
  1203. geometry._delayInfo.push(VertexBuffer.UV5Kind);
  1204. }
  1205. if (parsedVertexData.hasUVs6) {
  1206. geometry._delayInfo.push(VertexBuffer.UV6Kind);
  1207. }
  1208. if (parsedVertexData.hasColors) {
  1209. geometry._delayInfo.push(VertexBuffer.ColorKind);
  1210. }
  1211. if (parsedVertexData.hasMatricesIndices) {
  1212. geometry._delayInfo.push(VertexBuffer.MatricesIndicesKind);
  1213. }
  1214. if (parsedVertexData.hasMatricesWeights) {
  1215. geometry._delayInfo.push(VertexBuffer.MatricesWeightsKind);
  1216. }
  1217. geometry._delayLoadingFunction = VertexData.ImportVertexData;
  1218. } else {
  1219. VertexData.ImportVertexData(parsedVertexData, geometry);
  1220. }
  1221. scene.pushGeometry(geometry, true);
  1222. return geometry;
  1223. }
  1224. }
  1225. // Primitives
  1226. /// Abstract class
  1227. /**
  1228. * Abstract class used to provide common services for all typed geometries
  1229. * @hidden
  1230. */
  1231. export class _PrimitiveGeometry extends Geometry {
  1232. private _beingRegenerated: boolean;
  1233. /**
  1234. * Creates a new typed geometry
  1235. * @param id defines the unique ID of the geometry
  1236. * @param scene defines the hosting scene
  1237. * @param _canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1238. * @param mesh defines the hosting mesh (can be null)
  1239. */
  1240. constructor(id: string, scene: Scene, private _canBeRegenerated: boolean = false, mesh: Nullable<Mesh> = null) {
  1241. super(id, scene, undefined, false, mesh); // updatable = false to be sure not to update vertices
  1242. this._beingRegenerated = true;
  1243. this.regenerate();
  1244. this._beingRegenerated = false;
  1245. }
  1246. /**
  1247. * Gets a value indicating if the geometry supports being regenerated with new parameters (false by default)
  1248. * @returns true if the geometry can be regenerated
  1249. */
  1250. public canBeRegenerated(): boolean {
  1251. return this._canBeRegenerated;
  1252. }
  1253. /**
  1254. * If the geometry supports regeneration, the function will recreates the geometry with updated parameter values
  1255. */
  1256. public regenerate(): void {
  1257. if (!this._canBeRegenerated) {
  1258. return;
  1259. }
  1260. this._beingRegenerated = true;
  1261. this.setAllVerticesData(this._regenerateVertexData(), false);
  1262. this._beingRegenerated = false;
  1263. }
  1264. /**
  1265. * Clone the geometry
  1266. * @param id defines the unique ID of the new geometry
  1267. * @returns the new geometry
  1268. */
  1269. public asNewGeometry(id: string): Geometry {
  1270. return super.copy(id);
  1271. }
  1272. // overrides
  1273. public setAllVerticesData(vertexData: VertexData, updatable?: boolean): void {
  1274. if (!this._beingRegenerated) {
  1275. return;
  1276. }
  1277. super.setAllVerticesData(vertexData, false);
  1278. }
  1279. public setVerticesData(kind: string, data: FloatArray, updatable?: boolean): void {
  1280. if (!this._beingRegenerated) {
  1281. return;
  1282. }
  1283. super.setVerticesData(kind, data, false);
  1284. }
  1285. // to override
  1286. /** @hidden */
  1287. public _regenerateVertexData(): VertexData {
  1288. throw new Error("Abstract method");
  1289. }
  1290. public copy(id: string): Geometry {
  1291. throw new Error("Must be overriden in sub-classes.");
  1292. }
  1293. public serialize(): any {
  1294. var serializationObject = super.serialize();
  1295. serializationObject.canBeRegenerated = this.canBeRegenerated();
  1296. return serializationObject;
  1297. }
  1298. }
  1299. /**
  1300. * Creates a ribbon geometry
  1301. * @description See http://doc.babylonjs.com/how_to/ribbon_tutorial, http://doc.babylonjs.com/resources/maths_make_ribbons
  1302. */
  1303. export class RibbonGeometry extends _PrimitiveGeometry {
  1304. /**
  1305. * Creates a ribbon geometry
  1306. * @param id defines the unique ID of the geometry
  1307. * @param scene defines the hosting scene
  1308. * @param pathArray defines the array of paths to use
  1309. * @param closeArray defines if the last path and the first path must be joined
  1310. * @param closePath defines if the last and first points of each path in your pathArray must be joined
  1311. * @param offset defines the offset between points
  1312. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1313. * @param mesh defines the hosting mesh (can be null)
  1314. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1315. */
  1316. constructor(
  1317. id: string, scene: Scene,
  1318. /**
  1319. * Defines the array of paths to use
  1320. */
  1321. public pathArray: Vector3[][],
  1322. /**
  1323. * Defines if the last and first points of each path in your pathArray must be joined
  1324. */
  1325. public closeArray: boolean,
  1326. /**
  1327. * Defines if the last and first points of each path in your pathArray must be joined
  1328. */
  1329. public closePath: boolean,
  1330. /**
  1331. * Defines the offset between points
  1332. */
  1333. public offset: number,
  1334. canBeRegenerated?: boolean,
  1335. mesh?: Mesh,
  1336. /**
  1337. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1338. */
  1339. public side: number = Mesh.DEFAULTSIDE) {
  1340. super(id, scene, canBeRegenerated, mesh);
  1341. }
  1342. /** @hidden */
  1343. public _regenerateVertexData(): VertexData {
  1344. return VertexData.CreateRibbon({ pathArray: this.pathArray, closeArray: this.closeArray, closePath: this.closePath, offset: this.offset, sideOrientation: this.side });
  1345. }
  1346. public copy(id: string): Geometry {
  1347. return new RibbonGeometry(id, this.getScene(), this.pathArray, this.closeArray, this.closePath, this.offset, this.canBeRegenerated(), undefined, this.side);
  1348. }
  1349. }
  1350. /**
  1351. * Creates a box geometry
  1352. * @description see http://doc.babylonjs.com/how_to/set_shapes#box
  1353. */
  1354. export class BoxGeometry extends _PrimitiveGeometry {
  1355. /**
  1356. * Creates a box geometry
  1357. * @param id defines the unique ID of the geometry
  1358. * @param scene defines the hosting scene
  1359. * @param size defines the zise of the box (width, height and depth are the same)
  1360. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1361. * @param mesh defines the hosting mesh (can be null)
  1362. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1363. */
  1364. constructor(
  1365. id: string, scene: Scene,
  1366. /**
  1367. * Defines the zise of the box (width, height and depth are the same)
  1368. */
  1369. public size: number,
  1370. canBeRegenerated?: boolean,
  1371. mesh: Nullable<Mesh> = null,
  1372. /**
  1373. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1374. */
  1375. public side: number = Mesh.DEFAULTSIDE) {
  1376. super(id, scene, canBeRegenerated, mesh);
  1377. }
  1378. /** @hidden */
  1379. public _regenerateVertexData(): VertexData {
  1380. return VertexData.CreateBox({ size: this.size, sideOrientation: this.side });
  1381. }
  1382. public copy(id: string): Geometry {
  1383. return new BoxGeometry(id, this.getScene(), this.size, this.canBeRegenerated(), undefined, this.side);
  1384. }
  1385. public serialize(): any {
  1386. var serializationObject = super.serialize();
  1387. serializationObject.size = this.size;
  1388. return serializationObject;
  1389. }
  1390. public static Parse(parsedBox: any, scene: Scene): Nullable<BoxGeometry> {
  1391. if (scene.getGeometryByID(parsedBox.id)) {
  1392. return null; // null since geometry could be something else than a box...
  1393. }
  1394. var box = new BoxGeometry(parsedBox.id, scene, parsedBox.size, parsedBox.canBeRegenerated, null);
  1395. if (Tags) {
  1396. Tags.AddTagsTo(box, parsedBox.tags);
  1397. }
  1398. scene.pushGeometry(box, true);
  1399. return box;
  1400. }
  1401. }
  1402. /**
  1403. * Creates a sphere geometry
  1404. * @description see http://doc.babylonjs.com/how_to/set_shapes#sphere
  1405. */
  1406. export class SphereGeometry extends _PrimitiveGeometry {
  1407. /**
  1408. * Create a new sphere geometry
  1409. * @param id defines the unique ID of the geometry
  1410. * @param scene defines the hosting scene
  1411. * @param segments defines the number of segments to use to create the sphere
  1412. * @param diameter defines the diameter of the sphere
  1413. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1414. * @param mesh defines the hosting mesh (can be null)
  1415. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1416. */
  1417. constructor(
  1418. id: string, scene: Scene,
  1419. /**
  1420. * Defines the number of segments to use to create the sphere
  1421. */
  1422. public segments: number,
  1423. /**
  1424. * Defines the diameter of the sphere
  1425. */
  1426. public diameter: number,
  1427. canBeRegenerated?: boolean,
  1428. mesh: Nullable<Mesh> = null,
  1429. /**
  1430. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1431. */
  1432. public side: number = Mesh.DEFAULTSIDE) {
  1433. super(id, scene, canBeRegenerated, mesh);
  1434. }
  1435. /** @hidden */
  1436. public _regenerateVertexData(): VertexData {
  1437. return VertexData.CreateSphere({ segments: this.segments, diameter: this.diameter, sideOrientation: this.side });
  1438. }
  1439. public copy(id: string): Geometry {
  1440. return new SphereGeometry(id, this.getScene(), this.segments, this.diameter, this.canBeRegenerated(), null, this.side);
  1441. }
  1442. public serialize(): any {
  1443. var serializationObject = super.serialize();
  1444. serializationObject.segments = this.segments;
  1445. serializationObject.diameter = this.diameter;
  1446. return serializationObject;
  1447. }
  1448. public static Parse(parsedSphere: any, scene: Scene): Nullable<SphereGeometry> {
  1449. if (scene.getGeometryByID(parsedSphere.id)) {
  1450. return null; // null since geometry could be something else than a sphere...
  1451. }
  1452. var sphere = new SphereGeometry(parsedSphere.id, scene, parsedSphere.segments, parsedSphere.diameter, parsedSphere.canBeRegenerated, null);
  1453. if (Tags) {
  1454. Tags.AddTagsTo(sphere, parsedSphere.tags);
  1455. }
  1456. scene.pushGeometry(sphere, true);
  1457. return sphere;
  1458. }
  1459. }
  1460. /**
  1461. * Creates a disc geometry
  1462. * @description see http://doc.babylonjs.com/how_to/set_shapes#disc-or-regular-polygon
  1463. */
  1464. export class DiscGeometry extends _PrimitiveGeometry {
  1465. /**
  1466. * Creates a new disc geometry
  1467. * @param id defines the unique ID of the geometry
  1468. * @param scene defines the hosting scene
  1469. * @param radius defines the radius of the disc
  1470. * @param tessellation defines the tesselation factor to apply to the disc
  1471. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1472. * @param mesh defines the hosting mesh (can be null)
  1473. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1474. */
  1475. constructor(
  1476. id: string, scene: Scene,
  1477. /**
  1478. * Defines the radius of the disc
  1479. */
  1480. public radius: number,
  1481. /**
  1482. * Defines the tesselation factor to apply to the disc
  1483. */
  1484. public tessellation: number,
  1485. canBeRegenerated?: boolean,
  1486. mesh: Nullable<Mesh> = null,
  1487. /**
  1488. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1489. */
  1490. public side: number = Mesh.DEFAULTSIDE) {
  1491. super(id, scene, canBeRegenerated, mesh);
  1492. }
  1493. /** @hidden */
  1494. public _regenerateVertexData(): VertexData {
  1495. return VertexData.CreateDisc({ radius: this.radius, tessellation: this.tessellation, sideOrientation: this.side });
  1496. }
  1497. public copy(id: string): Geometry {
  1498. return new DiscGeometry(id, this.getScene(), this.radius, this.tessellation, this.canBeRegenerated(), null, this.side);
  1499. }
  1500. }
  1501. /**
  1502. * Creates a new cylinder geometry
  1503. * @description see http://doc.babylonjs.com/how_to/set_shapes#cylinder-or-cone
  1504. */
  1505. export class CylinderGeometry extends _PrimitiveGeometry {
  1506. /**
  1507. * Creates a new cylinder geometry
  1508. * @param id defines the unique ID of the geometry
  1509. * @param scene defines the hosting scene
  1510. * @param height defines the height of the cylinder
  1511. * @param diameterTop defines the diameter of the cylinder's top cap
  1512. * @param diameterBottom defines the diameter of the cylinder's bottom cap
  1513. * @param tessellation defines the tessellation factor to apply to the cylinder (number of radial sides)
  1514. * @param subdivisions defines the number of subdivisions to apply to the cylinder (number of rings) (1 by default)
  1515. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1516. * @param mesh defines the hosting mesh (can be null)
  1517. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1518. */
  1519. constructor(
  1520. id: string, scene: Scene,
  1521. /**
  1522. * Defines the height of the cylinder
  1523. */
  1524. public height: number,
  1525. /**
  1526. * Defines the diameter of the cylinder's top cap
  1527. */
  1528. public diameterTop: number,
  1529. /**
  1530. * Defines the diameter of the cylinder's bottom cap
  1531. */
  1532. public diameterBottom: number,
  1533. /**
  1534. * Defines the tessellation factor to apply to the cylinder
  1535. */
  1536. public tessellation: number,
  1537. /**
  1538. * Defines the number of subdivisions to apply to the cylinder (1 by default)
  1539. */
  1540. public subdivisions: number = 1,
  1541. canBeRegenerated?: boolean, mesh:
  1542. Nullable<Mesh> = null,
  1543. /**
  1544. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1545. */
  1546. public side: number = Mesh.DEFAULTSIDE) {
  1547. super(id, scene, canBeRegenerated, mesh);
  1548. }
  1549. /** @hidden */
  1550. public _regenerateVertexData(): VertexData {
  1551. return VertexData.CreateCylinder({ height: this.height, diameterTop: this.diameterTop, diameterBottom: this.diameterBottom, tessellation: this.tessellation, subdivisions: this.subdivisions, sideOrientation: this.side });
  1552. }
  1553. public copy(id: string): Geometry {
  1554. return new CylinderGeometry(id, this.getScene(), this.height, this.diameterTop, this.diameterBottom, this.tessellation, this.subdivisions, this.canBeRegenerated(), null, this.side);
  1555. }
  1556. public serialize(): any {
  1557. var serializationObject = super.serialize();
  1558. serializationObject.height = this.height;
  1559. serializationObject.diameterTop = this.diameterTop;
  1560. serializationObject.diameterBottom = this.diameterBottom;
  1561. serializationObject.tessellation = this.tessellation;
  1562. return serializationObject;
  1563. }
  1564. public static Parse(parsedCylinder: any, scene: Scene): Nullable<CylinderGeometry> {
  1565. if (scene.getGeometryByID(parsedCylinder.id)) {
  1566. return null; // null since geometry could be something else than a cylinder...
  1567. }
  1568. var cylinder = new CylinderGeometry(parsedCylinder.id, scene, parsedCylinder.height, parsedCylinder.diameterTop, parsedCylinder.diameterBottom, parsedCylinder.tessellation, parsedCylinder.subdivisions, parsedCylinder.canBeRegenerated, null);
  1569. if (Tags) {
  1570. Tags.AddTagsTo(cylinder, parsedCylinder.tags);
  1571. }
  1572. scene.pushGeometry(cylinder, true);
  1573. return cylinder;
  1574. }
  1575. }
  1576. /**
  1577. * Creates a new torus geometry
  1578. * @description see http://doc.babylonjs.com/how_to/set_shapes#torus
  1579. */
  1580. export class TorusGeometry extends _PrimitiveGeometry {
  1581. /**
  1582. * Creates a new torus geometry
  1583. * @param id defines the unique ID of the geometry
  1584. * @param scene defines the hosting scene
  1585. * @param diameter defines the diameter of the torus
  1586. * @param thickness defines the thickness of the torus (ie. internal diameter)
  1587. * @param tessellation defines the tesselation factor to apply to the torus (number of segments along the circle)
  1588. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1589. * @param mesh defines the hosting mesh (can be null)
  1590. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1591. */
  1592. constructor(
  1593. id: string, scene: Scene,
  1594. /**
  1595. * Defines the diameter of the torus
  1596. */
  1597. public diameter: number,
  1598. /**
  1599. * Defines the thickness of the torus (ie. internal diameter)
  1600. */
  1601. public thickness: number,
  1602. /**
  1603. * Defines the tesselation factor to apply to the torus
  1604. */
  1605. public tessellation: number,
  1606. canBeRegenerated?: boolean,
  1607. mesh: Nullable<Mesh> = null,
  1608. /**
  1609. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1610. */
  1611. public side: number = Mesh.DEFAULTSIDE) {
  1612. super(id, scene, canBeRegenerated, mesh);
  1613. }
  1614. /** @hidden */
  1615. public _regenerateVertexData(): VertexData {
  1616. return VertexData.CreateTorus({ diameter: this.diameter, thickness: this.thickness, tessellation: this.tessellation, sideOrientation: this.side });
  1617. }
  1618. public copy(id: string): Geometry {
  1619. return new TorusGeometry(id, this.getScene(), this.diameter, this.thickness, this.tessellation, this.canBeRegenerated(), null, this.side);
  1620. }
  1621. public serialize(): any {
  1622. var serializationObject = super.serialize();
  1623. serializationObject.diameter = this.diameter;
  1624. serializationObject.thickness = this.thickness;
  1625. serializationObject.tessellation = this.tessellation;
  1626. return serializationObject;
  1627. }
  1628. public static Parse(parsedTorus: any, scene: Scene): Nullable<TorusGeometry> {
  1629. if (scene.getGeometryByID(parsedTorus.id)) {
  1630. return null; // null since geometry could be something else than a torus...
  1631. }
  1632. var torus = new TorusGeometry(parsedTorus.id, scene, parsedTorus.diameter, parsedTorus.thickness, parsedTorus.tessellation, parsedTorus.canBeRegenerated, null);
  1633. if (Tags) {
  1634. Tags.AddTagsTo(torus, parsedTorus.tags);
  1635. }
  1636. scene.pushGeometry(torus, true);
  1637. return torus;
  1638. }
  1639. }
  1640. /**
  1641. * Creates a new ground geometry
  1642. * @description see http://doc.babylonjs.com/how_to/set_shapes#ground
  1643. */
  1644. export class GroundGeometry extends _PrimitiveGeometry {
  1645. /**
  1646. * Creates a new ground geometry
  1647. * @param id defines the unique ID of the geometry
  1648. * @param scene defines the hosting scene
  1649. * @param width defines the width of the ground
  1650. * @param height defines the height of the ground
  1651. * @param subdivisions defines the subdivisions to apply to the ground
  1652. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1653. * @param mesh defines the hosting mesh (can be null)
  1654. */
  1655. constructor(
  1656. id: string, scene: Scene,
  1657. /**
  1658. * Defines the width of the ground
  1659. */
  1660. public width: number,
  1661. /**
  1662. * Defines the height of the ground
  1663. */
  1664. public height: number,
  1665. /**
  1666. * Defines the subdivisions to apply to the ground
  1667. */
  1668. public subdivisions: number,
  1669. canBeRegenerated?: boolean,
  1670. mesh: Nullable<Mesh> = null) {
  1671. super(id, scene, canBeRegenerated, mesh);
  1672. }
  1673. /** @hidden */
  1674. public _regenerateVertexData(): VertexData {
  1675. return VertexData.CreateGround({ width: this.width, height: this.height, subdivisions: this.subdivisions });
  1676. }
  1677. public copy(id: string): Geometry {
  1678. return new GroundGeometry(id, this.getScene(), this.width, this.height, this.subdivisions, this.canBeRegenerated(), null);
  1679. }
  1680. public serialize(): any {
  1681. var serializationObject = super.serialize();
  1682. serializationObject.width = this.width;
  1683. serializationObject.height = this.height;
  1684. serializationObject.subdivisions = this.subdivisions;
  1685. return serializationObject;
  1686. }
  1687. public static Parse(parsedGround: any, scene: Scene): Nullable<GroundGeometry> {
  1688. if (scene.getGeometryByID(parsedGround.id)) {
  1689. return null; // null since geometry could be something else than a ground...
  1690. }
  1691. var ground = new GroundGeometry(parsedGround.id, scene, parsedGround.width, parsedGround.height, parsedGround.subdivisions, parsedGround.canBeRegenerated, null);
  1692. if (Tags) {
  1693. Tags.AddTagsTo(ground, parsedGround.tags);
  1694. }
  1695. scene.pushGeometry(ground, true);
  1696. return ground;
  1697. }
  1698. }
  1699. /**
  1700. * Creates a tiled ground geometry
  1701. * @description see http://doc.babylonjs.com/how_to/set_shapes#tiled-ground
  1702. */
  1703. export class TiledGroundGeometry extends _PrimitiveGeometry {
  1704. /**
  1705. * Creates a tiled ground geometry
  1706. * @param id defines the unique ID of the geometry
  1707. * @param scene defines the hosting scene
  1708. * @param xmin defines the minimum value on X axis
  1709. * @param zmin defines the minimum value on Z axis
  1710. * @param xmax defines the maximum value on X axis
  1711. * @param zmax defines the maximum value on Z axis
  1712. * @param subdivisions defines the subdivisions to apply to the ground (number of subdivisions (tiles) on the height and the width of the map)
  1713. * @param precision defines the precision to use when computing the tiles
  1714. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1715. * @param mesh defines the hosting mesh (can be null)
  1716. */
  1717. constructor(
  1718. id: string, scene: Scene,
  1719. /**
  1720. * Defines the minimum value on X axis
  1721. */
  1722. public xmin: number,
  1723. /**
  1724. * Defines the minimum value on Z axis
  1725. */
  1726. public zmin: number,
  1727. /**
  1728. * Defines the maximum value on X axis
  1729. */
  1730. public xmax: number,
  1731. /**
  1732. * Defines the maximum value on Z axis
  1733. */
  1734. public zmax: number,
  1735. /**
  1736. * Defines the subdivisions to apply to the ground
  1737. */
  1738. public subdivisions: { w: number; h: number; },
  1739. /**
  1740. * Defines the precision to use when computing the tiles
  1741. */
  1742. public precision: { w: number; h: number; },
  1743. canBeRegenerated?: boolean,
  1744. mesh: Nullable<Mesh> = null) {
  1745. super(id, scene, canBeRegenerated, mesh);
  1746. }
  1747. /** @hidden */
  1748. public _regenerateVertexData(): VertexData {
  1749. return VertexData.CreateTiledGround({ xmin: this.xmin, zmin: this.zmin, xmax: this.xmax, zmax: this.zmax, subdivisions: this.subdivisions, precision: this.precision });
  1750. }
  1751. public copy(id: string): Geometry {
  1752. return new TiledGroundGeometry(id, this.getScene(), this.xmin, this.zmin, this.xmax, this.zmax, this.subdivisions, this.precision, this.canBeRegenerated(), null);
  1753. }
  1754. }
  1755. /**
  1756. * Creates a plane geometry
  1757. * @description see http://doc.babylonjs.com/how_to/set_shapes#plane
  1758. */
  1759. export class PlaneGeometry extends _PrimitiveGeometry {
  1760. /**
  1761. * Creates a plane geometry
  1762. * @param id defines the unique ID of the geometry
  1763. * @param scene defines the hosting scene
  1764. * @param size defines the size of the plane (width === height)
  1765. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1766. * @param mesh defines the hosting mesh (can be null)
  1767. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1768. */
  1769. constructor(
  1770. id: string, scene: Scene,
  1771. /**
  1772. * Defines the size of the plane (width === height)
  1773. */
  1774. public size: number,
  1775. canBeRegenerated?: boolean,
  1776. mesh: Nullable<Mesh> = null,
  1777. /**
  1778. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1779. */
  1780. public side: number = Mesh.DEFAULTSIDE) {
  1781. super(id, scene, canBeRegenerated, mesh);
  1782. }
  1783. /** @hidden */
  1784. public _regenerateVertexData(): VertexData {
  1785. return VertexData.CreatePlane({ size: this.size, sideOrientation: this.side });
  1786. }
  1787. public copy(id: string): Geometry {
  1788. return new PlaneGeometry(id, this.getScene(), this.size, this.canBeRegenerated(), null, this.side);
  1789. }
  1790. public serialize(): any {
  1791. var serializationObject = super.serialize();
  1792. serializationObject.size = this.size;
  1793. return serializationObject;
  1794. }
  1795. public static Parse(parsedPlane: any, scene: Scene): Nullable<PlaneGeometry> {
  1796. if (scene.getGeometryByID(parsedPlane.id)) {
  1797. return null; // null since geometry could be something else than a ground...
  1798. }
  1799. var plane = new PlaneGeometry(parsedPlane.id, scene, parsedPlane.size, parsedPlane.canBeRegenerated, null);
  1800. if (Tags) {
  1801. Tags.AddTagsTo(plane, parsedPlane.tags);
  1802. }
  1803. scene.pushGeometry(plane, true);
  1804. return plane;
  1805. }
  1806. }
  1807. /**
  1808. * Creates a torus knot geometry
  1809. * @description see http://doc.babylonjs.com/how_to/set_shapes#torus-knot
  1810. */
  1811. export class TorusKnotGeometry extends _PrimitiveGeometry {
  1812. /**
  1813. * Creates a torus knot geometry
  1814. * @param id defines the unique ID of the geometry
  1815. * @param scene defines the hosting scene
  1816. * @param radius defines the radius of the torus knot
  1817. * @param tube defines the thickness of the torus knot tube
  1818. * @param radialSegments defines the number of radial segments
  1819. * @param tubularSegments defines the number of tubular segments
  1820. * @param p defines the first number of windings
  1821. * @param q defines the second number of windings
  1822. * @param canBeRegenerated defines if the geometry supports being regenerated with new parameters (false by default)
  1823. * @param mesh defines the hosting mesh (can be null)
  1824. * @param side defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1825. */
  1826. constructor(
  1827. id: string, scene: Scene,
  1828. /**
  1829. * Defines the radius of the torus knot
  1830. */
  1831. public radius: number,
  1832. /**
  1833. * Defines the thickness of the torus knot tube
  1834. */
  1835. public tube: number,
  1836. /**
  1837. * Defines the number of radial segments
  1838. */
  1839. public radialSegments: number,
  1840. /**
  1841. * Defines the number of tubular segments
  1842. */
  1843. public tubularSegments: number,
  1844. /**
  1845. * Defines the first number of windings
  1846. */
  1847. public p: number,
  1848. /**
  1849. * Defines the second number of windings
  1850. */
  1851. public q: number,
  1852. canBeRegenerated?: boolean,
  1853. mesh: Nullable<Mesh> = null,
  1854. /**
  1855. * Defines if the created geometry is double sided or not (default is BABYLON.Mesh.DEFAULTSIDE)
  1856. */
  1857. public side: number = Mesh.DEFAULTSIDE) {
  1858. super(id, scene, canBeRegenerated, mesh);
  1859. }
  1860. /** @hidden */
  1861. public _regenerateVertexData(): VertexData {
  1862. return VertexData.CreateTorusKnot({ radius: this.radius, tube: this.tube, radialSegments: this.radialSegments, tubularSegments: this.tubularSegments, p: this.p, q: this.q, sideOrientation: this.side });
  1863. }
  1864. public copy(id: string): Geometry {
  1865. return new TorusKnotGeometry(id, this.getScene(), this.radius, this.tube, this.radialSegments, this.tubularSegments, this.p, this.q, this.canBeRegenerated(), null, this.side);
  1866. }
  1867. public serialize(): any {
  1868. var serializationObject = super.serialize();
  1869. serializationObject.radius = this.radius;
  1870. serializationObject.tube = this.tube;
  1871. serializationObject.radialSegments = this.radialSegments;
  1872. serializationObject.tubularSegments = this.tubularSegments;
  1873. serializationObject.p = this.p;
  1874. serializationObject.q = this.q;
  1875. return serializationObject;
  1876. }
  1877. public static Parse(parsedTorusKnot: any, scene: Scene): Nullable<TorusKnotGeometry> {
  1878. if (scene.getGeometryByID(parsedTorusKnot.id)) {
  1879. return null; // null since geometry could be something else than a ground...
  1880. }
  1881. var torusKnot = new TorusKnotGeometry(parsedTorusKnot.id, scene, parsedTorusKnot.radius, parsedTorusKnot.tube, parsedTorusKnot.radialSegments, parsedTorusKnot.tubularSegments, parsedTorusKnot.p, parsedTorusKnot.q, parsedTorusKnot.canBeRegenerated, null);
  1882. if (Tags) {
  1883. Tags.AddTagsTo(torusKnot, parsedTorusKnot.tags);
  1884. }
  1885. scene.pushGeometry(torusKnot, true);
  1886. return torusKnot;
  1887. }
  1888. }
  1889. //}
  1890. }