/droid/DroidRUGL/src/com/ryanm/droid/rugl/geom/ShapeUtil.java

http://rugl.googlecode.com/ · Java · 1136 lines · 662 code · 152 blank · 322 comment · 45 complexity · 83a671b26e51821bd131723e3f878428 MD5 · raw file

  1. package com.ryanm.droid.rugl.geom;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import com.ryanm.droid.rugl.util.Trig;
  5. import com.ryanm.droid.rugl.util.geom.LineUtils;
  6. import com.ryanm.droid.rugl.util.geom.Vector2f;
  7. import com.ryanm.droid.rugl.util.geom.Vector3f;
  8. import com.ryanm.droid.rugl.util.geom.VectorUtils;
  9. /**
  10. * Utility for constructing various {@link Shape}s
  11. *
  12. * @author ryanm
  13. */
  14. public class ShapeUtil
  15. {
  16. /**
  17. * Vertices will be in nbr, ntr, nbl, ntl, fbr, ftr, fbl, ftl
  18. * order, where near is -z, far is +z, bottom is -y, top is +y,
  19. * left is -x, right is +x
  20. *
  21. * @param minx
  22. * @param miny
  23. * @param minz
  24. * @param maxx
  25. * @param maxy
  26. * @param maxz
  27. * @return An axis-aligned cuboid
  28. */
  29. public static Shape cuboid( float minx, float miny, float minz, float maxx,
  30. float maxy, float maxz )
  31. {
  32. float[] verts = new float[ 8 * 3 ];
  33. short[] tris = new short[ 6 * 2 * 3 ];
  34. int vi = 0;
  35. verts[ vi++ ] = minx;
  36. verts[ vi++ ] = miny;
  37. verts[ vi++ ] = minz;
  38. verts[ vi++ ] = minx;
  39. verts[ vi++ ] = maxy;
  40. verts[ vi++ ] = minz;
  41. verts[ vi++ ] = maxx;
  42. verts[ vi++ ] = miny;
  43. verts[ vi++ ] = minz;
  44. verts[ vi++ ] = maxx;
  45. verts[ vi++ ] = maxy;
  46. verts[ vi++ ] = minz;
  47. verts[ vi++ ] = minx;
  48. verts[ vi++ ] = miny;
  49. verts[ vi++ ] = maxz;
  50. verts[ vi++ ] = minx;
  51. verts[ vi++ ] = maxy;
  52. verts[ vi++ ] = maxz;
  53. verts[ vi++ ] = maxx;
  54. verts[ vi++ ] = miny;
  55. verts[ vi++ ] = maxz;
  56. verts[ vi++ ] = maxx;
  57. verts[ vi++ ] = maxy;
  58. verts[ vi++ ] = maxz;
  59. int ti = 0;
  60. // near
  61. tris[ ti++ ] = 0;
  62. tris[ ti++ ] = 2;
  63. tris[ ti++ ] = 1;
  64. tris[ ti++ ] = 2;
  65. tris[ ti++ ] = 3;
  66. tris[ ti++ ] = 1;
  67. // bottom
  68. tris[ ti++ ] = 0;
  69. tris[ ti++ ] = 4;
  70. tris[ ti++ ] = 2;
  71. tris[ ti++ ] = 4;
  72. tris[ ti++ ] = 6;
  73. tris[ ti++ ] = 2;
  74. // right
  75. tris[ ti++ ] = 2;
  76. tris[ ti++ ] = 6;
  77. tris[ ti++ ] = 3;
  78. tris[ ti++ ] = 7;
  79. tris[ ti++ ] = 3;
  80. tris[ ti++ ] = 6;
  81. // top
  82. tris[ ti++ ] = 1;
  83. tris[ ti++ ] = 3;
  84. tris[ ti++ ] = 5;
  85. tris[ ti++ ] = 3;
  86. tris[ ti++ ] = 7;
  87. tris[ ti++ ] = 5;
  88. // left
  89. tris[ ti++ ] = 4;
  90. tris[ ti++ ] = 0;
  91. tris[ ti++ ] = 5;
  92. tris[ ti++ ] = 0;
  93. tris[ ti++ ] = 1;
  94. tris[ ti++ ] = 5;
  95. // far
  96. tris[ ti++ ] = 6;
  97. tris[ ti++ ] = 4;
  98. tris[ ti++ ] = 7;
  99. tris[ ti++ ] = 4;
  100. tris[ ti++ ] = 5;
  101. tris[ ti++ ] = 7;
  102. return new Shape( verts, tris );
  103. }
  104. /**
  105. * @param angle
  106. * the angle range through which to spiral
  107. * @param angleInc
  108. * granularity of spiral
  109. * @param width
  110. * The width of the line
  111. * @return A golden spiral at the origin
  112. */
  113. public static Shape goldenSpiral( float angle, float angleInc, float width )
  114. {
  115. return logSpiral( 1, 0.306349f, angle, angleInc, width );
  116. }
  117. /**
  118. * @param a
  119. * @param b
  120. * @param tRange
  121. * @param tStep
  122. * @param width
  123. * @return A logarithmic spiral
  124. */
  125. public static Shape logSpiral( float a, float b, float tRange, float tStep, float width )
  126. {
  127. assert tRange != 0;
  128. int points = ( int ) ( tRange / tStep ) + 2;
  129. tStep = tRange / points;
  130. float[] verts = new float[ points * 2 ];
  131. int vi = 0;
  132. for( int i = 0; i < points; i++ )
  133. {
  134. float t = i * tStep;
  135. float r = ( float ) ( a * Math.pow( Math.E, b * t ) );
  136. verts[ vi++ ] = r * Trig.cos( t );
  137. verts[ vi++ ] = r * Trig.sin( t );
  138. }
  139. return line( width, verts );
  140. }
  141. /**
  142. * @param legs
  143. * number of legs on each side
  144. * @param legLength
  145. * length of legs
  146. * @param legwidth
  147. * width of legs
  148. * @param sep
  149. * distance between core and legs
  150. * @return A chip icon shape
  151. */
  152. public static Shape chipIcon( int legs, float legLength, float legwidth, float sep )
  153. {
  154. float core = 1 - 2 * sep - 2 * legLength;
  155. Shape coreShape = filledQuad( 0, 0, core, core, 0 );
  156. coreShape.translate( legLength + sep, legLength + sep, 0 );
  157. Shape hLeg = filledQuad( 0, -legwidth / 2, legLength, legwidth / 2, 0 );
  158. Shape vLeg = filledQuad( -legwidth / 2, 0, legwidth / 2, legLength, 0 );
  159. ShapeWelder<Shape> b = new ShapeWelder<Shape>();
  160. b.addShape( coreShape );
  161. float legSep = core / legs;
  162. float p = legLength + sep + legSep / 2;
  163. for( int i = 0; i < legs; i++ )
  164. {
  165. b.addShape( hLeg.clone().translate( 0, p, 0 ) );
  166. b.addShape( hLeg.clone().translate( core + 2 * sep + legLength, p, 0 ) );
  167. b.addShape( vLeg.clone().translate( p, 0, 0 ) );
  168. b.addShape( vLeg.clone().translate( p, core + 2 * sep + legLength, 0 ) );
  169. p += legSep;
  170. }
  171. return b.fuse();
  172. }
  173. /**
  174. * Constructs an arrow shape, such as you might find on a return
  175. * key
  176. *
  177. * @param posx
  178. * The lower-left corner of the bounding box
  179. * @param posy
  180. * @param width
  181. * The dimensions
  182. * @param height
  183. * @param arrowlength
  184. * The length of the arrowhead
  185. * @param thickness
  186. * The width of the shaft
  187. * @return An arrow shape
  188. */
  189. public static Shape retArrow( float posx, float posy, float width, float height,
  190. float arrowlength, float thickness )
  191. {
  192. float pointy = height / 2;
  193. float low = pointy - thickness / 2;
  194. float high = low + thickness;
  195. float[] verts =
  196. new float[] { 0, pointy, arrowlength, height, arrowlength, high,
  197. width - thickness, high, width - thickness, height, width, height,
  198. width, low, arrowlength, low, arrowlength, 0 };
  199. for( int i = 0; i < verts.length; i += 2 )
  200. {
  201. verts[ i ] += posx;
  202. verts[ i + 1 ] += posy;
  203. }
  204. short[] tris =
  205. new short[] { 0, 2, 1, 0, 7, 2, 0, 8, 7, 7, 6, 2, 2, 6, 3, 6, 4, 3, 6, 5, 4 };
  206. return new Shape( to3D( verts, 0 ), tris );
  207. }
  208. /**
  209. * Constructs a filled circle
  210. *
  211. * @param cx
  212. * The x coordinate of the center point
  213. * @param cy
  214. * The y coordinate of the center point
  215. * @param radius
  216. * The radius of the circle
  217. * @param maxSegment
  218. * The maximum length of the line segments making up the
  219. * circumference
  220. * @param z
  221. * The z coordinate of the circle
  222. * @return A filled circle {@link Shape}
  223. */
  224. public static Shape filledCircle( float cx, float cy, float radius, float maxSegment,
  225. float z )
  226. {
  227. assert radius >= 0;
  228. float c = ( float ) ( 2 * radius * Math.PI );
  229. int segs = ( int ) Math.ceil( c / maxSegment );
  230. segs = Math.max( segs, 3 );
  231. float angleIncrement = ( float ) ( 2 * Math.PI / segs );
  232. Vector3f[] verts = new Vector3f[ segs ];
  233. short[] tris = new short[ 3 * ( segs - 2 ) ];
  234. for( int i = 0; i < verts.length; i++ )
  235. {
  236. float a = i * angleIncrement;
  237. verts[ i ] =
  238. new Vector3f( ( float ) ( radius * Math.cos( a ) ),
  239. ( float ) ( radius * Math.sin( a ) ), z );
  240. verts[ i ].x += cx;
  241. verts[ i ].y += cy;
  242. }
  243. int ti = 0;
  244. for( int i = 0; i < segs - 2; i++ )
  245. {
  246. tris[ ti++ ] = 0;
  247. tris[ ti++ ] = ( short ) ( i + 1 );
  248. tris[ ti++ ] = ( short ) ( i + 2 );
  249. }
  250. return new Shape( ShapeUtil.extract( verts ), tris );
  251. }
  252. /**
  253. * Constructs a filled circle that has a central vertex
  254. *
  255. * @param cx
  256. * The x coordinate of the center point
  257. * @param cy
  258. * The y coordinate of the center point
  259. * @param radius
  260. * The radius of the circle
  261. * @param maxSegment
  262. * The maximum length of the line segments making up the
  263. * circumference
  264. * @param z
  265. * The z coordinate of the circle
  266. * @return A filled circle {@link Shape}. The center vertex is at
  267. * index 0
  268. */
  269. public static Shape filledCenteredCircle( float cx, float cy, float radius,
  270. float maxSegment, float z )
  271. {
  272. assert radius >= 0;
  273. float c = ( float ) ( 2 * radius * Math.PI );
  274. int segs = ( int ) Math.ceil( c / maxSegment );
  275. segs = Math.max( segs, 3 );
  276. float angleIncrement = ( float ) ( 2 * Math.PI / segs );
  277. Vector3f[] verts = new Vector3f[ segs + 1 ];
  278. short[] tris = new short[ 3 * segs ];
  279. verts[ 0 ] = new Vector3f( cx, cy, z );
  280. for( int i = 1; i < verts.length; i++ )
  281. {
  282. float a = i * angleIncrement;
  283. verts[ i ] =
  284. new Vector3f( ( float ) ( radius * Math.cos( a ) ),
  285. ( float ) ( radius * Math.sin( a ) ), z );
  286. verts[ i ].x += cx;
  287. verts[ i ].y += cy;
  288. }
  289. int ti = 0;
  290. short vi = 1;
  291. for( int i = 0; i < segs; i++ )
  292. {
  293. tris[ ti++ ] = 0;
  294. tris[ ti++ ] = vi;
  295. vi++;
  296. tris[ ti++ ] = vi;
  297. }
  298. tris[ tris.length - 1 ] = 1;
  299. return new Shape( ShapeUtil.extract( verts ), tris );
  300. }
  301. /**
  302. * Build a circle outline that entirely encompasses the specified
  303. * radius
  304. *
  305. * @param cx
  306. * The x coordinate of the center point
  307. * @param cy
  308. * The y coordinate of the center point
  309. * @param radius
  310. * The inner radius of the circle outline
  311. * @param width
  312. * The width of the line used to draw the circle
  313. * @param maxSegment
  314. * The maximum length of line segment used to draw the
  315. * circle
  316. * @param z
  317. * The z coordinate for the circle
  318. * @return A {@link Shape} that contains the circle's geometry
  319. */
  320. public static Shape outerCircle( float cx, float cy, float radius, float width,
  321. float maxSegment, float z )
  322. {
  323. return ShapeUtil.innerCircle( cx, cy, radius + width, width, maxSegment, z );
  324. }
  325. /**
  326. * Builds a circle outline that lies completely within the
  327. * specified radius
  328. *
  329. * @param cx
  330. * The x coordinate of the center point
  331. * @param cy
  332. * The y coordinate of the center point
  333. * @param radius
  334. * The outer radius of the circle outline
  335. * @param width
  336. * The width of the line used to draw the circle
  337. * @param maxSegment
  338. * The maximum length of line segment used to draw the
  339. * circle
  340. * @param z
  341. * The z coordinate for the circle
  342. * @return A {@link Shape} that contains the circle's geometry
  343. */
  344. public static Shape innerCircle( float cx, float cy, float radius, float width,
  345. float maxSegment, float z )
  346. {
  347. if( width > radius )
  348. {
  349. width = radius;
  350. }
  351. float inner = radius - width;
  352. float outer = radius;
  353. if( inner == 0 )
  354. {
  355. return filledCircle( cx, cy, radius, maxSegment, z );
  356. }
  357. int segments = ( int ) Math.ceil( Math.PI * 2 * outer / maxSegment );
  358. segments = Math.max( 3, segments );
  359. float angleIncrement = ( float ) ( Math.PI * 2 / segments );
  360. Vector3f[] verts = new Vector3f[ segments * 2 ];
  361. short[] indices = new short[ segments * 6 ];
  362. for( int i = 0; i < segments; i++ )
  363. {
  364. float cos = ( float ) Math.cos( angleIncrement * i );
  365. float sin = ( float ) Math.sin( angleIncrement * i );
  366. verts[ 2 * i ] = new Vector3f( cx + inner * cos, cy + inner * sin, z );
  367. verts[ 2 * i + 1 ] = new Vector3f( cx + outer * cos, cy + outer * sin, z );
  368. short ci = ( short ) ( 2 * i );
  369. short co = ( short ) ( 2 * i + 1 );
  370. short ni = ( short ) ( ( ci + 2 ) % verts.length );
  371. short no = ( short ) ( ( co + 2 ) % verts.length );
  372. indices[ 6 * i ] = ci;
  373. indices[ 6 * i + 1 ] = co;
  374. indices[ 6 * i + 2 ] = ni;
  375. indices[ 6 * i + 3 ] = co;
  376. indices[ 6 * i + 4 ] = no;
  377. indices[ 6 * i + 5 ] = ni;
  378. }
  379. return new Shape( ShapeUtil.extract( verts ), indices );
  380. }
  381. /**
  382. * Creates a cross occupying the unit square
  383. *
  384. * @param width
  385. * The width of the arms
  386. * @return A cross shape
  387. */
  388. public static Shape cross( float width )
  389. {
  390. float n = 0.5f - width / 2;
  391. float f = n + width;
  392. float[] verts =
  393. new float[] { n, 0, n, n, 0, n, 0, f, n, f, n, 1, f, 1, f, f, 1, f, 1, n, f,
  394. n, f, 0 };
  395. short[] tris =
  396. new short[] { 1, 3, 2, 1, 4, 3, 4, 6, 5, 4, 7, 6, 7, 9, 8, 7, 10, 9, 10, 0,
  397. 11, 10, 1, 0, 1, 7, 4, 1, 10, 7 };
  398. return new Shape( to3D( verts, 0 ), tris );
  399. }
  400. /**
  401. * Takes a 2D vertex array and adds the z-coordinates
  402. *
  403. * @param verts
  404. * @param z
  405. * @return A 3D vertex array
  406. */
  407. public static float[] to3D( float[] verts, float z )
  408. {
  409. float[] tdv = new float[ verts.length / 2 * 3 ];
  410. int vi = 0;
  411. for( int i = 0; i < verts.length; i += 2 )
  412. {
  413. tdv[ vi++ ] = verts[ i ];
  414. tdv[ vi++ ] = verts[ i + 1 ];
  415. tdv[ vi++ ] = z;
  416. }
  417. return tdv;
  418. }
  419. /**
  420. * @param verts
  421. * @return the 2D projection of the 3D coordinates
  422. */
  423. public static float[] to2D( float[] verts )
  424. {
  425. float[] tdv = new float[ verts.length / 3 * 2 ];
  426. int vi = 0;
  427. for( int i = 0; i < verts.length; i += 3 )
  428. {
  429. tdv[ vi++ ] = verts[ i ];
  430. tdv[ vi++ ] = verts[ i + 1 ];
  431. }
  432. return tdv;
  433. }
  434. /**
  435. * Creates an upward-pointing arrow shape
  436. *
  437. * @param bx
  438. * The bottom corner
  439. * @param by
  440. * @param tx
  441. * The top corner
  442. * @param ty
  443. * @param cx
  444. * The inner corner nearest the bottom corner, in terms
  445. * of the bounding box
  446. * @param cy
  447. * @return An arrow shape
  448. */
  449. public static Shape arrow( float bx, float by, float tx, float ty, float cx, float cy )
  450. {
  451. float dx = tx - bx;
  452. float dy = ty - by;
  453. float ix = dx * cx;
  454. float iy = dy * cy;
  455. float near = bx + ix;
  456. float far = tx - ix;
  457. float peakx = ( bx + tx ) / 2;
  458. float[] verts =
  459. new float[] { near, by, near, iy, bx, iy, peakx, ty, tx, iy, far, iy, far, bx };
  460. short[] tris = new short[] { 1, 3, 2, 1, 5, 3, 5, 4, 3, 0, 5, 1, 0, 6, 5 };
  461. return new Shape( to3D( verts, 0 ), tris );
  462. }
  463. /**
  464. * Builds a simple filled quad. The vertices are in bl tl br tr
  465. * order
  466. *
  467. * @param px
  468. * corner x
  469. * @param py
  470. * corner y
  471. * @param qx
  472. * opposite corner x
  473. * @param qy
  474. * opposite corner y
  475. * @param z
  476. * The z coordinate of the quad
  477. * @return A filled quad
  478. */
  479. public static Shape filledQuad( float px, float py, float qx, float qy, float z )
  480. {
  481. if( px > qx )
  482. {
  483. float t = qx;
  484. qx = px;
  485. px = t;
  486. }
  487. if( py > qy )
  488. {
  489. float t = qy;
  490. qy = py;
  491. py = t;
  492. }
  493. Vector3f[] verts = new Vector3f[ 4 ];
  494. verts[ 0 ] = new Vector3f( px, py, z );
  495. verts[ 1 ] = new Vector3f( px, qy, z );
  496. verts[ 2 ] = new Vector3f( qx, py, z );
  497. verts[ 3 ] = new Vector3f( qx, qy, z );
  498. return new Shape( ShapeUtil.extract( verts ), makeQuads( 4, 0, null, 0 ) );
  499. }
  500. /**
  501. * Builds a quad outline that lies completely within the specified
  502. * bounds
  503. *
  504. * @param px
  505. * corner x
  506. * @param py
  507. * corner y
  508. * @param qx
  509. * opposite corner x
  510. * @param qy
  511. * opposite corner y
  512. * @param width
  513. * the width of the outline
  514. * @param z
  515. * The z coordinate of the quad outline
  516. * @return A quad outline
  517. */
  518. public static Shape innerQuad( float px, float py, float qx, float qy, float width,
  519. float z )
  520. {
  521. if( px > qx )
  522. {
  523. float t = qx;
  524. qx = px;
  525. px = t;
  526. }
  527. if( py > qy )
  528. {
  529. float t = qy;
  530. qy = py;
  531. py = t;
  532. }
  533. Vector3f[] verts = new Vector3f[ 8 ];
  534. short[] tris = new short[ 8 * 3 ];
  535. float xwidth = width;
  536. float ywidth = width;
  537. if( Math.abs( qx - px ) < 2 * width )
  538. {
  539. xwidth = Math.abs( qx - px ) / 2.0f;
  540. }
  541. if( Math.abs( qy - py ) < 2 * width )
  542. {
  543. ywidth = Math.abs( qy - py ) / 2.0f;
  544. }
  545. int index = 0;
  546. verts[ index++ ] = new Vector3f( px, py, z );
  547. verts[ index++ ] = new Vector3f( px + xwidth, py + ywidth, z );
  548. verts[ index++ ] = new Vector3f( px, qy, z );
  549. verts[ index++ ] = new Vector3f( px + xwidth, qy - ywidth, z );
  550. verts[ index++ ] = new Vector3f( qx, qy, z );
  551. verts[ index++ ] = new Vector3f( qx - xwidth, qy - ywidth, z );
  552. verts[ index++ ] = new Vector3f( qx, py, z );
  553. verts[ index++ ] = new Vector3f( qx - xwidth, py + ywidth, z );
  554. index = 0;
  555. for( short i = 0; i < 4; i++ )
  556. {
  557. short a = ( short ) ( i * 2 );
  558. short b = ( short ) ( a + 1 );
  559. short c = ( short ) ( ( b + 1 ) % verts.length );
  560. short d = ( short ) ( ( c + 1 ) % verts.length );
  561. addTriangle( a, b, c, tris, index );
  562. index += 3;
  563. addTriangle( b, d, c, tris, index );
  564. index += 3;
  565. }
  566. return new Shape( ShapeUtil.extract( verts ), tris );
  567. }
  568. /**
  569. * Builds a quad outline that encompasses the supplied bounds
  570. *
  571. * @param px
  572. * corner x
  573. * @param py
  574. * corner y
  575. * @param qx
  576. * opposite corner x
  577. * @param qy
  578. * opposite corner y
  579. * @param width
  580. * The outline width
  581. * @param z
  582. * The outline's z-component
  583. * @return A quad outline
  584. */
  585. public static Shape outerQuad( float px, float py, float qx, float qy, float width,
  586. float z )
  587. {
  588. float minx, miny, maxx, maxy;
  589. if( px < qx )
  590. {
  591. minx = px;
  592. maxx = qx;
  593. }
  594. else
  595. {
  596. minx = qx;
  597. maxx = px;
  598. }
  599. if( py < qy )
  600. {
  601. miny = py;
  602. maxy = qy;
  603. }
  604. else
  605. {
  606. miny = qy;
  607. maxy = py;
  608. }
  609. return innerQuad( minx - width, miny - width, maxx + width, maxy + width, width, z );
  610. }
  611. static void addTriangle( short a, short b, short c, short[] array, int index )
  612. {
  613. array[ index ] = a;
  614. array[ index + 1 ] = b;
  615. array[ index + 2 ] = c;
  616. }
  617. /**
  618. * Creates a 2D triangle shape
  619. *
  620. * @param ax
  621. * @param ay
  622. * @param bx
  623. * @param by
  624. * @param cx
  625. * @param cy
  626. * @return The triangle abc
  627. */
  628. public static Shape triangle( float ax, float ay, float bx, float by, float cx,
  629. float cy )
  630. {
  631. float[] v = new float[] { ax, ay, 0, bx, by, 0, cx, cy, 0 };
  632. short[] t = new short[] { 0, 1, 2 };
  633. return new Shape( v, t );
  634. }
  635. /**
  636. * Returns the outline around some polygon
  637. *
  638. * @param width
  639. * The width of the outline
  640. * @param pos
  641. * The position of the input polygon faces relative to
  642. * the output outline edges 0 = on the right-hand edge,
  643. * 0.5 in the middle, 1 = on the left-hand edge
  644. * @param vin
  645. * The input polygon vertices, in x,y,x,y,x,y format.
  646. * @return The outline shape
  647. */
  648. public static Shape outline( float width, float pos, float... vin )
  649. {
  650. assert vin.length >= 6;
  651. Vector2f prevDir = new Vector2f(), nextDir = new Vector2f(), point = new Vector2f();
  652. Vector2f ta = new Vector2f(), tb = new Vector2f(), tc = new Vector2f(), td =
  653. new Vector2f();
  654. float[] vout = new float[ vin.length * 2 ];
  655. int vi = 0;
  656. for( int i = 1; i <= vin.length / 2; i++ )
  657. {
  658. int c = 2 * i % vin.length;
  659. int p = 2 * ( i - 1 ) % vin.length;
  660. int n = 2 * ( i + 1 ) % vin.length;
  661. prevDir.set( vin[ c ] - vin[ p ], vin[ c + 1 ] - vin[ p + 1 ] );
  662. prevDir.normalise();
  663. nextDir.set( vin[ n ] - vin[ c ], vin[ n + 1 ] - vin[ c + 1 ] );
  664. nextDir.normalise();
  665. prevDir.scale( width );
  666. nextDir.scale( width );
  667. VectorUtils.rotate90( prevDir );
  668. VectorUtils.rotate90( nextDir );
  669. // inner
  670. ta.set( vin[ p ] - pos * prevDir.x, vin[ p + 1 ] - pos * prevDir.y );
  671. tb.set( vin[ c ] - pos * prevDir.x, vin[ c + 1 ] - pos * prevDir.y );
  672. tc.set( vin[ c ] - pos * nextDir.x, vin[ c + 1 ] - pos * nextDir.y );
  673. td.set( vin[ n ] - pos * nextDir.x, vin[ n + 1 ] - pos * nextDir.y );
  674. LineUtils.lineIntersection( ta, tb, tc, td, point );
  675. vout[ vi++ ] = point.x;
  676. vout[ vi++ ] = point.y;
  677. // outer
  678. ta.set( vin[ p ] + ( 1 - pos ) * prevDir.x, vin[ p + 1 ] + ( 1 - pos )
  679. * prevDir.y );
  680. tb.set( vin[ c ] + ( 1 - pos ) * prevDir.x, vin[ c + 1 ] + ( 1 - pos )
  681. * prevDir.y );
  682. tc.set( vin[ c ] + ( 1 - pos ) * nextDir.x, vin[ c + 1 ] + ( 1 - pos )
  683. * nextDir.y );
  684. td.set( vin[ n ] + ( 1 - pos ) * nextDir.x, vin[ n + 1 ] + ( 1 - pos )
  685. * nextDir.y );
  686. LineUtils.lineIntersection( ta, tb, tc, td, point );
  687. vout[ vi++ ] = point.x;
  688. vout[ vi++ ] = point.y;
  689. }
  690. assert vi == vout.length : vi + " " + vout.length;
  691. short[] tris = new short[ 3 * vin.length ];
  692. int ti = 0;
  693. for( int i = 0; i < vin.length / 2; i++ )
  694. {
  695. tris[ ti++ ] = ( short ) ( 2 * i );
  696. tris[ ti++ ] = ( short ) ( 2 * i + 2 );
  697. tris[ ti++ ] = ( short ) ( 2 * i + 1 );
  698. tris[ ti++ ] = ( short ) ( 2 * i + 2 );
  699. tris[ ti++ ] = ( short ) ( 2 * i + 3 );
  700. tris[ ti++ ] = ( short ) ( 2 * i + 1 );
  701. }
  702. for( int i = 0; i < tris.length; i++ )
  703. {
  704. tris[ i ] %= vout.length / 2;
  705. }
  706. return new Shape( to3D( vout, 0 ), tris );
  707. }
  708. /**
  709. * A simple line segment path
  710. *
  711. * @param width
  712. * @param vin
  713. * @return A line path of the specified width
  714. */
  715. public static Shape line( float width, float... vin )
  716. {
  717. assert vin.length >= 4;
  718. Vector2f prevDir = new Vector2f(), nextDir = new Vector2f(), point = new Vector2f();
  719. Vector2f ta = new Vector2f(), tb = new Vector2f(), tc = new Vector2f(), td =
  720. new Vector2f();
  721. float pos = 0.5f;
  722. float[] vout = new float[ vin.length * 2 ];
  723. int vi = 0;
  724. prevDir.set( vin[ 2 ] - vin[ 0 ], vin[ 3 ] - vin[ 1 ] );
  725. prevDir.normalise();
  726. prevDir.scale( width );
  727. VectorUtils.rotate90( prevDir );
  728. vout[ vi++ ] = vin[ 0 ] - pos * prevDir.x;
  729. vout[ vi++ ] = vin[ 1 ] - pos * prevDir.y;
  730. vout[ vi++ ] = vin[ 0 ] + ( 1 - pos ) * prevDir.x;
  731. vout[ vi++ ] = vin[ 1 ] + ( 1 - pos ) * prevDir.y;
  732. nextDir.set( prevDir );
  733. for( int i = 1; i < vin.length / 2 - 1; i++ )
  734. {
  735. int p = 2 * ( i - 1 );
  736. int c = 2 * i;
  737. int n = 2 * ( i + 1 );
  738. prevDir.set( vin[ c ] - vin[ p ], vin[ c + 1 ] - vin[ p + 1 ] );
  739. prevDir.normalise();
  740. nextDir.set( vin[ n ] - vin[ c ], vin[ n + 1 ] - vin[ c + 1 ] );
  741. nextDir.normalise();
  742. prevDir.scale( width );
  743. nextDir.scale( width );
  744. VectorUtils.rotate90( prevDir );
  745. VectorUtils.rotate90( nextDir );
  746. // inner
  747. ta.set( vin[ p ] - pos * prevDir.x, vin[ p + 1 ] - pos * prevDir.y );
  748. tb.set( vin[ c ] - pos * prevDir.x, vin[ c + 1 ] - pos * prevDir.y );
  749. tc.set( vin[ c ] - pos * nextDir.x, vin[ c + 1 ] - pos * nextDir.y );
  750. td.set( vin[ n ] - pos * nextDir.x, vin[ n + 1 ] - pos * nextDir.y );
  751. if( LineUtils.lineIntersection( ta, tb, tc, td, point ) == null )
  752. {
  753. // parallel segments
  754. vout[ vi++ ] = tb.x;
  755. vout[ vi++ ] = tb.y;
  756. }
  757. else
  758. {
  759. vout[ vi++ ] = point.x;
  760. vout[ vi++ ] = point.y;
  761. }
  762. // outer
  763. ta.set( vin[ p ] + ( 1 - pos ) * prevDir.x, vin[ p + 1 ] + ( 1 - pos )
  764. * prevDir.y );
  765. tb.set( vin[ c ] + ( 1 - pos ) * prevDir.x, vin[ c + 1 ] + ( 1 - pos )
  766. * prevDir.y );
  767. tc.set( vin[ c ] + ( 1 - pos ) * nextDir.x, vin[ c + 1 ] + ( 1 - pos )
  768. * nextDir.y );
  769. td.set( vin[ n ] + ( 1 - pos ) * nextDir.x, vin[ n + 1 ] + ( 1 - pos )
  770. * nextDir.y );
  771. if( LineUtils.lineIntersection( ta, tb, tc, td, point ) == null )
  772. {
  773. // parallel segments
  774. vout[ vi++ ] = tb.x;
  775. vout[ vi++ ] = tb.y;
  776. }
  777. else
  778. {
  779. vout[ vi++ ] = point.x;
  780. vout[ vi++ ] = point.y;
  781. }
  782. }
  783. vout[ vi++ ] = vin[ vin.length - 2 ] - pos * nextDir.x;
  784. vout[ vi++ ] = vin[ vin.length - 1 ] - pos * nextDir.y;
  785. vout[ vi++ ] = vin[ vin.length - 2 ] + ( 1 - pos ) * nextDir.x;
  786. vout[ vi++ ] = vin[ vin.length - 1 ] + ( 1 - pos ) * nextDir.y;
  787. assert vi == vout.length : vi + " " + vout.length;
  788. short[] tris = new short[ 3 * ( vin.length - 2 ) ];
  789. int ti = 0;
  790. for( int i = 0; i < vin.length / 2 - 1; i++ )
  791. {
  792. tris[ ti++ ] = ( short ) ( 2 * i );
  793. tris[ ti++ ] = ( short ) ( 2 * i + 2 );
  794. tris[ ti++ ] = ( short ) ( 2 * i + 1 );
  795. tris[ ti++ ] = ( short ) ( 2 * i + 2 );
  796. tris[ ti++ ] = ( short ) ( 2 * i + 3 );
  797. tris[ ti++ ] = ( short ) ( 2 * i + 1 );
  798. }
  799. return new Shape( to3D( vout, 0 ), tris );
  800. }
  801. /**
  802. * Calculates the vertex indices to form a sequence of quads from
  803. * consecutive vertices. Assumes vertices are in bl tl br tr format
  804. *
  805. * @param vertexCount
  806. * The number of vertices. Should be a multiple of 4
  807. * @param startVertex
  808. * The index of the lowest vertex
  809. * @param dest
  810. * An array in which to store the resulting vertices, or
  811. * null
  812. * @param start
  813. * The position in dest to store. Ignored if dest is null
  814. * @return dest, or a new int array
  815. */
  816. public static short[] makeQuads( int vertexCount, int startVertex, short[] dest,
  817. int start )
  818. {
  819. if( dest == null )
  820. {
  821. dest = new short[ 6 * ( vertexCount / 4 ) ];
  822. start = 0;
  823. }
  824. int index = start;
  825. for( int i = startVertex; i < vertexCount + startVertex; i += 4 )
  826. {
  827. dest[ index++ ] = ( short ) i;
  828. dest[ index++ ] = ( short ) ( i + 3 );
  829. dest[ index++ ] = ( short ) ( i + 1 );
  830. dest[ index++ ] = ( short ) i;
  831. dest[ index++ ] = ( short ) ( i + 2 );
  832. dest[ index++ ] = ( short ) ( i + 3 );
  833. }
  834. return dest;
  835. }
  836. /**
  837. * Gets the basic full-coverage texture coordinates for a series of
  838. * quads, in bl, tl, br, tr order
  839. *
  840. * @param quads
  841. * the number of quads
  842. * @return texture coordinates
  843. */
  844. public static float[] getQuadTexCoords( int quads )
  845. {
  846. float[] tc = new float[ 8 * quads ];
  847. for( int i = 0; i < quads; i++ )
  848. {
  849. int b = 8 * i;
  850. int o = 0;
  851. tc[ b + o++ ] = 0;
  852. tc[ b + o++ ] = 0;
  853. tc[ b + o++ ] = 0;
  854. tc[ b + o++ ] = 1;
  855. tc[ b + o++ ] = 1;
  856. tc[ b + o++ ] = 0;
  857. tc[ b + o++ ] = 1;
  858. tc[ b + o++ ] = 1;
  859. }
  860. return tc;
  861. }
  862. /**
  863. * Vertically flips a series of quad tex-coords
  864. *
  865. * @param tc
  866. * @return The input array
  867. */
  868. public static float[] vertFlipQuadTexCoords( float[] tc )
  869. {
  870. float swap = 0;
  871. for( int i = 1; i < tc.length - 2; i += 4 )
  872. {
  873. swap = tc[ i ];
  874. tc[ i ] = tc[ i + 2 ];
  875. tc[ i + 2 ] = swap;
  876. }
  877. return tc;
  878. }
  879. /**
  880. * @param verts
  881. * @return a vertex array
  882. */
  883. public static float[] extract( Vector3f[] verts )
  884. {
  885. float[] v = new float[ 3 * verts.length ];
  886. for( int i = 0; i < verts.length; i++ )
  887. {
  888. v[ 3 * i ] = verts[ i ].x;
  889. v[ 3 * i + 1 ] = verts[ i ].y;
  890. v[ 3 * i + 2 ] = verts[ i ].z;
  891. }
  892. return v;
  893. }
  894. /**
  895. * @param verts
  896. * @param z
  897. * @return a vertex array
  898. */
  899. public static float[] extract( Vector2f[] verts, float z )
  900. {
  901. float[] v = new float[ 3 * verts.length ];
  902. for( int i = 0; i < verts.length; i++ )
  903. {
  904. v[ 3 * i ] = verts[ i ].x;
  905. v[ 3 * i + 1 ] = verts[ i ].y;
  906. v[ 3 * i + 2 ] = z;
  907. }
  908. return v;
  909. }
  910. /**
  911. * @param verts
  912. * @return a texture coordinate array
  913. */
  914. public static float[] extract( Vector2f[] verts )
  915. {
  916. float[] v = new float[ 2 * verts.length ];
  917. for( int i = 0; i < verts.length; i++ )
  918. {
  919. v[ 2 * i ] = verts[ i ].x;
  920. v[ 2 * i + 1 ] = verts[ i ].y;
  921. }
  922. return v;
  923. }
  924. /**
  925. * @param verts
  926. * @return a vertex array
  927. */
  928. public static float[] extract( List<Vector3f> verts )
  929. {
  930. float[] va = new float[ 3 * verts.size() ];
  931. int vi = 0;
  932. for( Vector3f v : verts )
  933. {
  934. va[ vi++ ] = v.x;
  935. va[ vi++ ] = v.y;
  936. va[ vi++ ] = v.z;
  937. }
  938. return va;
  939. }
  940. /**
  941. * @param verts
  942. * @param z
  943. * @return a vertex array
  944. */
  945. public static float[] extractVerts( List<Vector2f> verts, float z )
  946. {
  947. float[] va = new float[ 3 * verts.size() ];
  948. int vi = 0;
  949. for( Vector2f v : verts )
  950. {
  951. va[ vi++ ] = v.x;
  952. va[ vi++ ] = v.y;
  953. va[ vi++ ] = z;
  954. }
  955. return va;
  956. }
  957. /**
  958. * Extracts a triangle index list
  959. *
  960. * @param indexes
  961. * @return The triangle index array
  962. */
  963. public static short[] extractIndices( List<Short> indexes )
  964. {
  965. short[] ia = new short[ indexes.size() ];
  966. int j = 0;
  967. for( Short i : indexes )
  968. {
  969. ia[ j++ ] = i.shortValue();
  970. }
  971. return ia;
  972. }
  973. /**
  974. * @param value
  975. * @param size
  976. * @return An array filled with value
  977. */
  978. public static int[] expand( int value, int size )
  979. {
  980. int[] a = new int[ size ];
  981. Arrays.fill( a, value );
  982. return a;
  983. }
  984. }