babylon.vertexBuffer.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. module BABYLON {
  2. export class VertexBuffer {
  3. private _buffer: Buffer;
  4. private _kind: string;
  5. private _size: number;
  6. private _ownsBuffer: boolean;
  7. private _instanced: boolean;
  8. private _instanceDivisor: number;
  9. /**
  10. * The byte type.
  11. */
  12. public static readonly BYTE = 5120;
  13. /**
  14. * The unsigned byte type.
  15. */
  16. public static readonly UNSIGNED_BYTE = 5121;
  17. /**
  18. * The short type.
  19. */
  20. public static readonly SHORT = 5122;
  21. /**
  22. * The unsigned short type.
  23. */
  24. public static readonly UNSIGNED_SHORT = 5123;
  25. /**
  26. * The integer type.
  27. */
  28. public static readonly INT = 5124;
  29. /**
  30. * The unsigned integer type.
  31. */
  32. public static readonly UNSIGNED_INT = 5125;
  33. /**
  34. * The float type.
  35. */
  36. public static readonly FLOAT = 5126;
  37. /**
  38. * Gets or sets the instance divisor when in instanced mode
  39. */
  40. public get instanceDivisor(): number {
  41. return this._instanceDivisor;
  42. }
  43. public set instanceDivisor(value: number) {
  44. this._instanceDivisor = value;
  45. if (value == 0) {
  46. this._instanced = false;
  47. } else {
  48. this._instanced = true;
  49. }
  50. }
  51. /**
  52. * Gets the byte stride.
  53. */
  54. public readonly byteStride: number;
  55. /**
  56. * Gets the byte offset.
  57. */
  58. public readonly byteOffset: number;
  59. /**
  60. * Gets whether integer data values should be normalized into a certain range when being casted to a float.
  61. */
  62. public readonly normalized: boolean;
  63. /**
  64. * Gets the data type of each component in the array.
  65. */
  66. public readonly type: number;
  67. /**
  68. * Constructor
  69. * @param engine the engine
  70. * @param data the data to use for this vertex buffer
  71. * @param kind the vertex buffer kind
  72. * @param updatable whether the data is updatable
  73. * @param postponeInternalCreation whether to postpone creating the internal WebGL buffer (optional)
  74. * @param stride the stride (optional)
  75. * @param instanced whether the buffer is instanced (optional)
  76. * @param offset the offset of the data (optional)
  77. * @param size the number of components (optional)
  78. * @param type the type of the component (optional)
  79. * @param normalized whether the data contains normalized data (optional)
  80. * @param useBytes set to true if stride and offset are in bytes (optional)
  81. */
  82. constructor(engine: any, data: DataArray | Buffer, kind: string, updatable: boolean, postponeInternalCreation?: boolean, stride?: number, instanced?: boolean, offset?: number, size?: number, type?: number, normalized = false, useBytes = false) {
  83. if (data instanceof Buffer) {
  84. this._buffer = data;
  85. this._ownsBuffer = false;
  86. } else {
  87. this._buffer = new Buffer(engine, data, updatable, stride, postponeInternalCreation, instanced, useBytes);
  88. this._ownsBuffer = true;
  89. }
  90. this._kind = kind;
  91. if (type == undefined) {
  92. const data = this.getData();
  93. this.type = VertexBuffer.FLOAT;
  94. if (data instanceof Int8Array) this.type = VertexBuffer.BYTE;
  95. else if (data instanceof Uint8Array) this.type = VertexBuffer.UNSIGNED_BYTE;
  96. else if (data instanceof Int16Array) this.type = VertexBuffer.SHORT;
  97. else if (data instanceof Uint16Array) this.type = VertexBuffer.UNSIGNED_SHORT;
  98. else if (data instanceof Int32Array) this.type = VertexBuffer.INT;
  99. else if (data instanceof Uint32Array) this.type = VertexBuffer.UNSIGNED_INT;
  100. }
  101. else {
  102. this.type = type;
  103. }
  104. const typeByteLength = VertexBuffer.GetTypeByteLength(this.type);
  105. if (useBytes) {
  106. this._size = size || (stride ? (stride / typeByteLength) : VertexBuffer.DeduceStride(kind));
  107. this.byteStride = stride || this._buffer.byteStride || (this._size * typeByteLength);
  108. this.byteOffset = offset || 0;
  109. }
  110. else {
  111. this._size = size || stride || VertexBuffer.DeduceStride(kind);
  112. this.byteStride = stride ? (stride * typeByteLength) : (this._buffer.byteStride || (this._size * typeByteLength));
  113. this.byteOffset = (offset || 0) * typeByteLength;
  114. }
  115. this.normalized = normalized;
  116. this._instanced = instanced !== undefined ? instanced : false;
  117. this._instanceDivisor = instanced ? 1 : 0;
  118. }
  119. public _rebuild(): void {
  120. if (!this._buffer) {
  121. return;
  122. }
  123. this._buffer._rebuild();
  124. }
  125. /**
  126. * Returns the kind of the VertexBuffer (string).
  127. */
  128. public getKind(): string {
  129. return this._kind;
  130. }
  131. // Properties
  132. /**
  133. * Boolean : is the VertexBuffer updatable ?
  134. */
  135. public isUpdatable(): boolean {
  136. return this._buffer.isUpdatable();
  137. }
  138. /**
  139. * Returns an array of numbers or a typed array containing the VertexBuffer data.
  140. */
  141. public getData(): Nullable<DataArray> {
  142. return this._buffer.getData();
  143. }
  144. /**
  145. * Returns the WebGLBuffer associated to the VertexBuffer.
  146. */
  147. public getBuffer(): Nullable<WebGLBuffer> {
  148. return this._buffer.getBuffer();
  149. }
  150. /**
  151. * Returns the stride as a multiple of the type byte length.
  152. * DEPRECATED. Use byteStride instead.
  153. */
  154. public getStrideSize(): number {
  155. return this.byteStride / VertexBuffer.GetTypeByteLength(this.type);
  156. }
  157. /**
  158. * Returns the offset as a multiple of the type byte length.
  159. * DEPRECATED. Use byteOffset instead.
  160. */
  161. public getOffset(): number {
  162. return this.byteOffset / VertexBuffer.GetTypeByteLength(this.type);
  163. }
  164. /**
  165. * Returns the number of components per vertex attribute (integer).
  166. */
  167. public getSize(): number {
  168. return this._size;
  169. }
  170. /**
  171. * Boolean : is the WebGLBuffer of the VertexBuffer instanced now ?
  172. */
  173. public getIsInstanced(): boolean {
  174. return this._instanced;
  175. }
  176. /**
  177. * Returns the instancing divisor, zero for non-instanced (integer).
  178. */
  179. public getInstanceDivisor(): number {
  180. return this._instanceDivisor;
  181. }
  182. // Methods
  183. /**
  184. * Creates the underlying WebGLBuffer from the passed numeric array or Float32Array.
  185. * Returns the created WebGLBuffer.
  186. */
  187. public create(data?: DataArray): void {
  188. return this._buffer.create(data);
  189. }
  190. /**
  191. * Updates the underlying WebGLBuffer according to the passed numeric array or Float32Array.
  192. * This function will create a new buffer if the current one is not updatable
  193. * Returns the updated WebGLBuffer.
  194. */
  195. public update(data: DataArray): void {
  196. return this._buffer.update(data);
  197. }
  198. /**
  199. * Updates directly the underlying WebGLBuffer according to the passed numeric array or Float32Array.
  200. * Returns the directly updated WebGLBuffer.
  201. * @param data the new data
  202. * @param offset the new offset
  203. * @param useBytes set to true if the offset is in bytes
  204. */
  205. public updateDirectly(data: DataArray, offset: number, useBytes: boolean = false): void {
  206. this._buffer.updateDirectly(data, offset, undefined, useBytes);
  207. }
  208. /**
  209. * Disposes the VertexBuffer and the underlying WebGLBuffer.
  210. */
  211. public dispose(): void {
  212. if (this._ownsBuffer) {
  213. this._buffer.dispose();
  214. }
  215. }
  216. /**
  217. * Enumerates each value of this vertex buffer as numbers.
  218. * @param count the number of values to enumerate
  219. * @param callback the callback function called for each value
  220. */
  221. public forEach(count: number, callback: (value: number, index: number) => void): void {
  222. VertexBuffer.ForEach(this._buffer.getData()!, this.byteOffset, this.byteStride, this._size, this.type, count, this.normalized, callback);
  223. }
  224. // Enums
  225. private static _PositionKind = "position";
  226. private static _NormalKind = "normal";
  227. private static _TangentKind = "tangent";
  228. private static _UVKind = "uv";
  229. private static _UV2Kind = "uv2";
  230. private static _UV3Kind = "uv3";
  231. private static _UV4Kind = "uv4";
  232. private static _UV5Kind = "uv5";
  233. private static _UV6Kind = "uv6";
  234. private static _ColorKind = "color";
  235. private static _MatricesIndicesKind = "matricesIndices";
  236. private static _MatricesWeightsKind = "matricesWeights";
  237. private static _MatricesIndicesExtraKind = "matricesIndicesExtra";
  238. private static _MatricesWeightsExtraKind = "matricesWeightsExtra";
  239. public static get PositionKind(): string {
  240. return VertexBuffer._PositionKind;
  241. }
  242. public static get NormalKind(): string {
  243. return VertexBuffer._NormalKind;
  244. }
  245. public static get TangentKind(): string {
  246. return VertexBuffer._TangentKind;
  247. }
  248. public static get UVKind(): string {
  249. return VertexBuffer._UVKind;
  250. }
  251. public static get UV2Kind(): string {
  252. return VertexBuffer._UV2Kind;
  253. }
  254. public static get UV3Kind(): string {
  255. return VertexBuffer._UV3Kind;
  256. }
  257. public static get UV4Kind(): string {
  258. return VertexBuffer._UV4Kind;
  259. }
  260. public static get UV5Kind(): string {
  261. return VertexBuffer._UV5Kind;
  262. }
  263. public static get UV6Kind(): string {
  264. return VertexBuffer._UV6Kind;
  265. }
  266. public static get ColorKind(): string {
  267. return VertexBuffer._ColorKind;
  268. }
  269. public static get MatricesIndicesKind(): string {
  270. return VertexBuffer._MatricesIndicesKind;
  271. }
  272. public static get MatricesWeightsKind(): string {
  273. return VertexBuffer._MatricesWeightsKind;
  274. }
  275. public static get MatricesIndicesExtraKind(): string {
  276. return VertexBuffer._MatricesIndicesExtraKind;
  277. }
  278. public static get MatricesWeightsExtraKind(): string {
  279. return VertexBuffer._MatricesWeightsExtraKind;
  280. }
  281. /**
  282. * Deduces the stride given a kind.
  283. * @param kind The kind string to deduce
  284. * @returns The deduced stride
  285. */
  286. public static DeduceStride(kind: string): number {
  287. switch (kind) {
  288. case VertexBuffer.UVKind:
  289. case VertexBuffer.UV2Kind:
  290. case VertexBuffer.UV3Kind:
  291. case VertexBuffer.UV4Kind:
  292. case VertexBuffer.UV5Kind:
  293. case VertexBuffer.UV6Kind:
  294. return 2;
  295. case VertexBuffer.NormalKind:
  296. case VertexBuffer.PositionKind:
  297. return 3;
  298. case VertexBuffer.ColorKind:
  299. case VertexBuffer.MatricesIndicesKind:
  300. case VertexBuffer.MatricesIndicesExtraKind:
  301. case VertexBuffer.MatricesWeightsKind:
  302. case VertexBuffer.MatricesWeightsExtraKind:
  303. case VertexBuffer.TangentKind:
  304. return 4;
  305. default:
  306. throw new Error("Invalid kind '" + kind + "'");
  307. }
  308. }
  309. /**
  310. * Gets the byte length of the given type.
  311. * @param type the type
  312. * @returns the number of bytes
  313. */
  314. public static GetTypeByteLength(type: number): number {
  315. switch (type) {
  316. case VertexBuffer.BYTE:
  317. case VertexBuffer.UNSIGNED_BYTE:
  318. return 1;
  319. case VertexBuffer.SHORT:
  320. case VertexBuffer.UNSIGNED_SHORT:
  321. return 2;
  322. case VertexBuffer.INT:
  323. case VertexBuffer.FLOAT:
  324. return 4;
  325. default:
  326. throw new Error(`Invalid type '${type}'`);
  327. }
  328. }
  329. /**
  330. * Enumerates each value of the given parameters as numbers.
  331. * @param data the data to enumerate
  332. * @param byteOffset the byte offset of the data
  333. * @param byteStride the byte stride of the data
  334. * @param componentCount the number of components per element
  335. * @param componentType the type of the component
  336. * @param count the total number of components
  337. * @param normalized whether the data is normalized
  338. * @param callback the callback function called for each value
  339. */
  340. public static ForEach(data: DataArray, byteOffset: number, byteStride: number, componentCount: number, componentType: number, count: number, normalized: boolean, callback: (value: number, index: number) => void): void {
  341. if (data instanceof Array) {
  342. let offset = byteOffset / 4;
  343. const stride = byteStride / 4;
  344. for (let index = 0; index < count; index += componentCount) {
  345. for (let componentIndex = 0; componentIndex < componentCount; componentIndex++) {
  346. callback(data[offset + componentIndex], index + componentIndex);
  347. }
  348. offset += stride;
  349. }
  350. }
  351. else {
  352. const dataView = data instanceof ArrayBuffer ? new DataView(data) : new DataView(data.buffer, data.byteOffset, data.byteLength);
  353. const componentByteLength = VertexBuffer.GetTypeByteLength(componentType);
  354. for (let index = 0; index < count; index += componentCount) {
  355. let componentByteOffset = byteOffset;
  356. for (let componentIndex = 0; componentIndex < componentCount; componentIndex++) {
  357. const value = VertexBuffer._GetFloatValue(dataView, componentType, componentByteOffset, normalized);
  358. callback(value, index + componentIndex);
  359. componentByteOffset += componentByteLength;
  360. }
  361. byteOffset += byteStride;
  362. }
  363. }
  364. }
  365. private static _GetFloatValue(dataView: DataView, type: number, byteOffset: number, normalized: boolean): number {
  366. switch (type) {
  367. case VertexBuffer.BYTE: {
  368. let value = dataView.getInt8(byteOffset);
  369. if (normalized) {
  370. value = Math.max(value / 127, -1);
  371. }
  372. return value;
  373. }
  374. case VertexBuffer.UNSIGNED_BYTE: {
  375. let value = dataView.getUint8(byteOffset);
  376. if (normalized) {
  377. value = value / 255;
  378. }
  379. return value;
  380. }
  381. case VertexBuffer.SHORT: {
  382. let value = dataView.getInt16(byteOffset, true);
  383. if (normalized) {
  384. value = Math.max(value / 16383, -1);
  385. }
  386. return value;
  387. }
  388. case VertexBuffer.UNSIGNED_SHORT: {
  389. let value = dataView.getUint16(byteOffset, true);
  390. if (normalized) {
  391. value = value / 65535;
  392. }
  393. return value;
  394. }
  395. case VertexBuffer.FLOAT: {
  396. return dataView.getFloat32(byteOffset, true);
  397. }
  398. default: {
  399. throw new Error(`Invalid component type ${type}`);
  400. }
  401. }
  402. }
  403. }
  404. }