babylon.polygonMesh.ts 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. module BABYLON {
  2. declare var earcut: any;
  3. class IndexedVector2 extends Vector2 {
  4. constructor(original: Vector2, public index: number) {
  5. super(original.x, original.y);
  6. }
  7. }
  8. class PolygonPoints {
  9. elements = new Array<IndexedVector2>();
  10. add(originalPoints: Array<Vector2>): Array<IndexedVector2> {
  11. var result = new Array<IndexedVector2>();
  12. originalPoints.forEach(point => {
  13. if (result.length === 0 || !point.equalsWithEpsilon(result[0])) {
  14. var newPoint = new IndexedVector2(point, this.elements.length);
  15. result.push(newPoint);
  16. this.elements.push(newPoint);
  17. }
  18. });
  19. return result;
  20. }
  21. computeBounds(): { min: Vector2; max: Vector2; width: number; height: number } {
  22. var lmin = new Vector2(this.elements[0].x, this.elements[0].y);
  23. var lmax = new Vector2(this.elements[0].x, this.elements[0].y);
  24. this.elements.forEach(point => {
  25. // x
  26. if (point.x < lmin.x) {
  27. lmin.x = point.x;
  28. }
  29. else if (point.x > lmax.x) {
  30. lmax.x = point.x;
  31. }
  32. // y
  33. if (point.y < lmin.y) {
  34. lmin.y = point.y;
  35. }
  36. else if (point.y > lmax.y) {
  37. lmax.y = point.y;
  38. }
  39. });
  40. return {
  41. min: lmin,
  42. max: lmax,
  43. width: lmax.x - lmin.x,
  44. height: lmax.y - lmin.y
  45. };
  46. }
  47. }
  48. export class Polygon {
  49. static Rectangle(xmin: number, ymin: number, xmax: number, ymax: number): Vector2[] {
  50. return [
  51. new Vector2(xmin, ymin),
  52. new Vector2(xmax, ymin),
  53. new Vector2(xmax, ymax),
  54. new Vector2(xmin, ymax)
  55. ];
  56. }
  57. static Circle(radius: number, cx: number = 0, cy: number = 0, numberOfSides: number = 32): Vector2[] {
  58. var result = new Array<Vector2>();
  59. var angle = 0;
  60. var increment = (Math.PI * 2) / numberOfSides;
  61. for (var i = 0; i < numberOfSides; i++) {
  62. result.push(new Vector2(
  63. cx + Math.cos(angle) * radius,
  64. cy + Math.sin(angle) * radius
  65. ));
  66. angle -= increment;
  67. }
  68. return result;
  69. }
  70. static Parse(input: string): Vector2[] {
  71. var floats = input.split(/[^-+eE\.\d]+/).map(parseFloat).filter(val => (!isNaN(val)));
  72. var i: number, result = [];
  73. for (i = 0; i < (floats.length & 0x7FFFFFFE); i += 2) {
  74. result.push(new Vector2(floats[i], floats[i + 1]));
  75. }
  76. return result;
  77. }
  78. static StartingAt(x: number, y: number): Path2 {
  79. return Path2.StartingAt(x, y);
  80. }
  81. }
  82. export class PolygonMeshBuilder {
  83. private _points = new PolygonPoints();
  84. private _outlinepoints = new PolygonPoints();
  85. private _holes = new Array<PolygonPoints>();
  86. private _name: string;
  87. private _scene: Scene;
  88. private _epoints: number[] = new Array<number>();
  89. private _eholes: number[] = new Array<number>();
  90. private _addToepoint(points: Vector2[]) {
  91. for (let p of points) {
  92. this._epoints.push(p.x, p.y);
  93. }
  94. }
  95. constructor(name: string, contours: Path2, scene: Scene)
  96. constructor(name: string, contours: Vector2[], scene: Scene)
  97. constructor(name: string, contours: any, scene: Scene) {
  98. this._name = name;
  99. this._scene = scene;
  100. var points: Vector2[];
  101. if (contours instanceof Path2) {
  102. points = (<Path2>contours).getPoints();
  103. } else {
  104. points = (<Vector2[]>contours);
  105. }
  106. this._addToepoint(points);
  107. this._points.add(points);
  108. this._outlinepoints.add(points);
  109. if (typeof earcut === 'undefined') {
  110. Tools.Warn("Earcut was not found, the polygon will not be built.")
  111. }
  112. }
  113. addHole(hole: Vector2[]): PolygonMeshBuilder {
  114. this._points.add(hole);
  115. var holepoints = new PolygonPoints();
  116. holepoints.add(hole);
  117. this._holes.push(holepoints);
  118. this._eholes.push(this._epoints.length / 2);
  119. this._addToepoint(hole);
  120. return this;
  121. }
  122. build(updatable: boolean = false, depth: number = 0): Mesh {
  123. var result = new Mesh(this._name, this._scene);
  124. var normals = new Array<number>();
  125. var positions = new Array<number>();
  126. var uvs = new Array<number>();
  127. var bounds = this._points.computeBounds();
  128. this._points.elements.forEach((p) => {
  129. normals.push(0, 1.0, 0);
  130. positions.push(p.x, 0, p.y);
  131. uvs.push((p.x - bounds.min.x) / bounds.width, (p.y - bounds.min.y) / bounds.height);
  132. });
  133. var indices = new Array<number>();
  134. let res = earcut(this._epoints, this._eholes, 2);
  135. for (let i = 0; i < res.length; i++) {
  136. indices.push(res[i]);
  137. }
  138. if (depth > 0) {
  139. var positionscount = (positions.length / 3); //get the current pointcount
  140. this._points.elements.forEach((p) => { //add the elements at the depth
  141. normals.push(0, -1.0, 0);
  142. positions.push(p.x, -depth, p.y);
  143. uvs.push(1 - (p.x - bounds.min.x) / bounds.width, 1 - (p.y - bounds.min.y) / bounds.height);
  144. });
  145. let totalCount = indices.length;
  146. for (let i = 0; i < totalCount; i += 3) {
  147. let i0 = indices[i + 0];
  148. let i1 = indices[i + 1];
  149. let i2 = indices[i + 2];
  150. indices.push(i2 + positionscount);
  151. indices.push(i1 + positionscount);
  152. indices.push(i0 + positionscount);
  153. }
  154. //Add the sides
  155. this.addSide(positions, normals, uvs, indices, bounds, this._outlinepoints, depth, false);
  156. this._holes.forEach((hole) => {
  157. this.addSide(positions, normals, uvs, indices, bounds, hole, depth, true);
  158. });
  159. }
  160. result.setVerticesData(VertexBuffer.PositionKind, positions, updatable);
  161. result.setVerticesData(VertexBuffer.NormalKind, normals, updatable);
  162. result.setVerticesData(VertexBuffer.UVKind, uvs, updatable);
  163. result.setIndices(indices);
  164. return result;
  165. }
  166. private addSide(positions: any[], normals: any[], uvs: any[], indices: any[], bounds: any, points: PolygonPoints, depth: number, flip: boolean) {
  167. var StartIndex: number = positions.length / 3;
  168. var ulength: number = 0;
  169. for (var i: number = 0; i < points.elements.length; i++) {
  170. var p: IndexedVector2 = points.elements[i];
  171. var p1: IndexedVector2
  172. if ((i + 1) > points.elements.length - 1) {
  173. p1 = points.elements[0];
  174. }
  175. else {
  176. p1 = points.elements[i + 1];
  177. }
  178. positions.push(p.x, 0, p.y);
  179. positions.push(p.x, -depth, p.y);
  180. positions.push(p1.x, 0, p1.y);
  181. positions.push(p1.x, -depth, p1.y);
  182. var v1 = new Vector3(p.x, 0, p.y);
  183. var v2 = new Vector3(p1.x, 0, p1.y);
  184. var v3 = v2.subtract(v1);
  185. var v4 = new Vector3(0, 1, 0);
  186. var vn = Vector3.Cross(v3, v4);
  187. vn = vn.normalize();
  188. uvs.push(ulength / bounds.width, 0);
  189. uvs.push(ulength / bounds.width, 1);
  190. ulength += v3.length();
  191. uvs.push((ulength / bounds.width), 0);
  192. uvs.push((ulength / bounds.width), 1);
  193. if (!flip) {
  194. normals.push(-vn.x, - vn.y, -vn.z);
  195. normals.push(-vn.x, -vn.y, -vn.z);
  196. normals.push(-vn.x, -vn.y, -vn.z);
  197. normals.push(-vn.x, -vn.y, -vn.z);
  198. indices.push(StartIndex);
  199. indices.push(StartIndex + 1);
  200. indices.push(StartIndex + 2);
  201. indices.push(StartIndex + 1);
  202. indices.push(StartIndex + 3);
  203. indices.push(StartIndex + 2);
  204. }
  205. else {
  206. normals.push(vn.x, vn.y, vn.z);
  207. normals.push(vn.x, vn.y, vn.z);
  208. normals.push(vn.x, vn.y, vn.z);
  209. normals.push(vn.x, vn.y, vn.z);
  210. indices.push(StartIndex);
  211. indices.push(StartIndex + 2);
  212. indices.push(StartIndex + 1);
  213. indices.push(StartIndex + 1);
  214. indices.push(StartIndex + 2);
  215. indices.push(StartIndex + 3);
  216. }
  217. StartIndex += 4;
  218. };
  219. }
  220. }
  221. }