PageRenderTime 54ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/core/src/processing/core/PShape3D.java

https://github.com/ghostandthemachine/android-core-fragmented
Java | 1796 lines | 1285 code | 391 blank | 120 comment | 342 complexity | e5272960b6bccf1d8a90847fc7cc14f2 MD5 | raw file
  1. /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
  2. /*
  3. Part of the Processing project - http://processing.org
  4. Copyright (c) 2010 Ben Fry and Casey Reas
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License version 2.1 as published by the Free Software Foundation.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General
  13. Public License along with this library; if not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  15. Boston, MA 02111-1307 USA
  16. */
  17. package processing.core;
  18. import java.nio.FloatBuffer;
  19. import java.nio.ByteBuffer;
  20. import java.nio.ByteOrder;
  21. import java.nio.ShortBuffer;
  22. import java.util.ArrayList;
  23. import java.util.Arrays;
  24. import java.util.HashMap;
  25. import java.util.Hashtable;
  26. import java.io.BufferedReader;
  27. import javax.microedition.khronos.opengles.*;
  28. /**
  29. * This class holds a 3D model composed of vertices, normals, colors (per vertex) and
  30. * texture coordinates (also per vertex). All this data is stored in Vertex Buffer Objects
  31. * (VBO) in GPU memory for very fast access.
  32. * OBJ loading implemented using code from Saito's OBJLoader library (http://code.google.com/p/saitoobjloader/)
  33. * and OBJReader from Ahmet Kizilay (http://www.openprocessing.org/visuals/?visualID=191).
  34. * By Andres Colubri
  35. *
  36. */
  37. public class PShape3D extends PShape implements PConstants {
  38. protected PApplet papplet;
  39. protected PGraphicsAndroid3D a3d;
  40. // Element types handled by PShape3D (vertices, normals, color, texture coordinates).
  41. protected static final int VERTICES = 0;
  42. protected static final int NORMALS = 1;
  43. protected static final int COLORS = 2;
  44. protected static final int TEXCOORDS = 3;
  45. // ROOT shape properties:
  46. // Number of texture buffers currently in use:
  47. protected int numTexBuffers;
  48. // STATIC or DYNAMIC
  49. // TODO: vertex, color, normal and texcoord data can potentially have
  50. // different usage modes.
  51. protected int glUsage;
  52. // The OpenGL IDs for the different VBOs
  53. public int glVertexBufferID;
  54. public int glColorBufferID;
  55. public int glNormalBufferID;
  56. public int[] glTexCoordBufferID;
  57. // The float buffers (directly allocated) used to put data into the VBOs
  58. protected FloatBuffer vertexBuffer;
  59. protected FloatBuffer colorBuffer;
  60. protected FloatBuffer normalBuffer;
  61. protected FloatBuffer texCoordBuffer;
  62. // Public arrays for setting/getting vertices, colors, normals, and
  63. // texture coordinates when using loadVertices/updateVertices,
  64. // loadNormals/updateNormals, etc. This is modeled following the
  65. // loadPixels/updatePixels API for setting/getting pixel data in
  66. // PImage.
  67. public float[] vertices;
  68. public float[] colors;
  69. public float[] normals;
  70. public float[] texcoords;
  71. // Indexed mode, testing:
  72. protected int glIndexBufferID = 0;
  73. protected ShortBuffer indexBuffer = null;
  74. protected int indexCount = 0;
  75. protected short[] indices;
  76. protected boolean useIndices;
  77. // To put the texture coordinate values adjusted according to texture
  78. // flipping mode, max UV range, etc.
  79. protected float[] convTexcoords;
  80. // The array of arrays holding the texture coordinates for all texture units.
  81. protected float[][] allTexcoords;
  82. // Child PShape3D associated to each vertex in the model.
  83. protected PShape3D[] vertexChild;
  84. // Some utility arrays.
  85. protected boolean[] texCoordSet;
  86. protected boolean autoBounds = true;
  87. // For OBJ loading. Only used by the root shape.
  88. boolean readFromOBJ = false;
  89. ArrayList<PVector> objVertices;
  90. ArrayList<PVector> objNormal;
  91. ArrayList<PVector> objTexCoords;
  92. ArrayList<OBJFace> objFaces;
  93. ArrayList<OBJMaterial> objMaterials;
  94. // GEOMETRY shape properties:
  95. // Draw mode, point sprites and textures.
  96. // Stroke weight is inherited from PShape.
  97. protected int glMode;
  98. protected boolean pointSprites;
  99. protected PImage[] textures;
  100. protected float maxSpriteSize = PGraphicsAndroid3D.maxPointSize;
  101. // Coefficients for point sprite distance attenuation function.
  102. // These default values correspond to the constant sprite size.
  103. protected float spriteDistAtt[] = { 1.0f, 0.0f, 0.0f };
  104. // Used in the drawGeometry() method.
  105. protected PTexture[] renderTextures;
  106. // GROUP and GEOMETRY properties:
  107. // The root group shape.
  108. protected PShape3D root;
  109. // Element type, vertex indices and texture units being currently updated.
  110. protected int updateElement;
  111. protected int updateTexunit;
  112. protected int firstUpdateIdx;
  113. protected int lastUpdateIdx;
  114. // first and last vertex in the shape. For the root group shape, these are 0 and
  115. // vertexCount - 1.
  116. protected int firstVertex;
  117. protected int lastVertex;
  118. protected int firstIndex;
  119. protected int lastIndex;
  120. // Bounding box (defined for all shapes, group and geometry):
  121. public float xmin, xmax;
  122. public float ymin, ymax;
  123. public float zmin, zmax;
  124. ////////////////////////////////////////////////////////////
  125. // Constructors.
  126. public PShape3D() {
  127. this.papplet = null;
  128. a3d = null;
  129. glVertexBufferID = 0;
  130. glColorBufferID = 0;
  131. glNormalBufferID = 0;
  132. glTexCoordBufferID = null;
  133. }
  134. public PShape3D(PApplet parent) {
  135. this();
  136. this.papplet = parent;
  137. a3d = (PGraphicsAndroid3D)parent.g;
  138. this.family = PShape.GROUP;
  139. this.name = "root";
  140. this.root = this;
  141. }
  142. public PShape3D(PApplet parent, int numVert) {
  143. this(parent, numVert, new Parameters());
  144. }
  145. public PShape3D(PApplet parent, String filename, Parameters params) {
  146. this.papplet = parent;
  147. a3d = (PGraphicsAndroid3D)parent.g;
  148. this.family = PShape.GROUP;
  149. this.name = "root";
  150. this.root = this;
  151. glVertexBufferID = 0;
  152. glColorBufferID = 0;
  153. glNormalBufferID = 0;
  154. glTexCoordBufferID = null;
  155. updateElement = -1;
  156. initShapeOBJ(filename, params);
  157. }
  158. public PShape3D(PApplet parent, int size, Parameters params) {
  159. this.papplet = parent;
  160. a3d = (PGraphicsAndroid3D)parent.g;
  161. this.family = PShape.GROUP;
  162. this.name = "root";
  163. this.root = this;
  164. glVertexBufferID = 0;
  165. glColorBufferID = 0;
  166. glNormalBufferID = 0;
  167. glTexCoordBufferID = null;
  168. updateElement = -1;
  169. initShape(size, params);
  170. }
  171. public void delete() {
  172. if (root != this) return; // Can be done only from the root shape.
  173. release();
  174. a3d.unregisterPGLObject(this);
  175. deleteVertexBuffer();
  176. deleteColorBuffer();
  177. deleteTexCoordBuffer();
  178. deleteNormalBuffer();
  179. deleteIndexBuffer();
  180. }
  181. public void backup() {
  182. }
  183. public void restore() {
  184. if (root != this) return; // Can be done only from the root shape.
  185. // Loading/updating each piece of data so the arrays on the CPU-side
  186. // are copied to the VBOs on the GPU.
  187. loadVertices();
  188. updateVertices();
  189. loadColors();
  190. updateColors();
  191. loadNormals();
  192. updateNormals();
  193. for (int i = 0; i < numTexBuffers; i++) {
  194. loadTexcoords(i);
  195. updateTexcoords();
  196. }
  197. }
  198. ////////////////////////////////////////////////////////////
  199. // SHAPE RECORDING HACK
  200. public void beginRecord() {
  201. a3d.beginRecord(this);
  202. }
  203. public void endRecord() {
  204. a3d.endRecord();
  205. }
  206. public void beginShape(int kind) {
  207. a3d.beginShape(kind);
  208. }
  209. public void endShape() {
  210. a3d.endShape();
  211. }
  212. public void endShape(int mode) {
  213. a3d.endShape(mode);
  214. }
  215. public void shapeName(String name) {
  216. a3d.shapeName(name);
  217. }
  218. public void mergeShapes(boolean val) {
  219. a3d.mergeShapes(val);
  220. }
  221. public void vertex(float x, float y, float u, float v) {
  222. a3d.vertex(x, y, u, v);
  223. }
  224. public void vertex(float x, float y, float z, float u, float v) {
  225. a3d.vertex(x, y, z, u, v);
  226. }
  227. public void vertex(float... values) {
  228. a3d.vertex(values);
  229. }
  230. public void normal(float nx, float ny, float nz) {
  231. a3d.normal(nx, ny, nz);
  232. }
  233. public void texture(PImage image) {
  234. a3d.texture(image);
  235. }
  236. public void texture(PImage... images) {
  237. a3d.texture(images);
  238. }
  239. public void sphereDetail(int res) {
  240. a3d.sphereDetail(res);
  241. }
  242. public void sphereDetail(int ures, int vres) {
  243. a3d.sphereDetail(ures, vres);
  244. }
  245. public void sphere(float r) {
  246. a3d.sphere(r);
  247. }
  248. public void box(float size) {
  249. a3d.box(size);
  250. }
  251. public void box(float w, float h, float d) {
  252. a3d.box(w, h, d);
  253. }
  254. public void noFill() {
  255. a3d.saveDrawingState();
  256. a3d.noFill();
  257. a3d.restoreDrawingState();
  258. }
  259. public void fill(int rgb) {
  260. a3d.saveDrawingState();
  261. a3d.fill(rgb);
  262. a3d.restoreDrawingState();
  263. }
  264. public void fill(int rgb, float alpha) {
  265. a3d.saveDrawingState();
  266. a3d.fill(rgb, alpha);
  267. a3d.restoreDrawingState();
  268. }
  269. public void fill(float gray) {
  270. a3d.saveDrawingState();
  271. a3d.fill(gray);
  272. a3d.restoreDrawingState();
  273. }
  274. public void fill(float gray, float alpha) {
  275. a3d.saveDrawingState();
  276. a3d.fill(gray, alpha);
  277. a3d.restoreDrawingState();
  278. }
  279. public void fill(float x, float y, float z) {
  280. a3d.saveDrawingState();
  281. a3d.fill(x, y, z);
  282. a3d.restoreDrawingState();
  283. }
  284. public void fill(float x, float y, float z, float a) {
  285. a3d.saveDrawingState();
  286. a3d.fill(x, y, z, a);
  287. a3d.restoreDrawingState();
  288. }
  289. public void noStroke() {
  290. a3d.saveDrawingState();
  291. a3d.noStroke();
  292. a3d.restoreDrawingState();
  293. }
  294. public void stroke(int rgb) {
  295. a3d.saveDrawingState();
  296. a3d.stroke(rgb);
  297. a3d.restoreDrawingState();
  298. }
  299. public void stroke(int rgb, float alpha) {
  300. a3d.saveDrawingState();
  301. a3d.stroke(rgb, alpha);
  302. a3d.restoreDrawingState();
  303. }
  304. public void stroke(float gray) {
  305. a3d.saveDrawingState();
  306. a3d.stroke(gray);
  307. a3d.restoreDrawingState();
  308. }
  309. public void stroke(float gray, float alpha) {
  310. a3d.saveDrawingState();
  311. a3d.stroke(gray, alpha);
  312. a3d.restoreDrawingState();
  313. }
  314. public void stroke(float x, float y, float z) {
  315. a3d.saveDrawingState();
  316. a3d.stroke(x, y, z);
  317. a3d.restoreDrawingState();
  318. }
  319. public void stroke(float x, float y, float z, float a) {
  320. a3d.saveDrawingState();
  321. a3d.stroke(x, y, z, a);
  322. a3d.restoreDrawingState();
  323. }
  324. ////////////////////////////////////////////////////////////
  325. // load/update/set/get methods
  326. public void loadVertices() {
  327. loadVertices(firstVertex, lastVertex);
  328. }
  329. public void loadVertices(int first, int last) {
  330. if (last < first || first < firstVertex || lastVertex < last) {
  331. PGraphics.showWarning("PShape3D: wrong vertex index");
  332. updateElement = -1;
  333. return;
  334. }
  335. if (updateElement != -1) {
  336. PGraphics.showWarning("PShape3D: can load only one type of data at the time");
  337. return;
  338. }
  339. updateElement = VERTICES;
  340. firstUpdateIdx = first;
  341. lastUpdateIdx = last;
  342. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glVertexBufferID);
  343. }
  344. public void updateVertices() {
  345. if (updateElement == VERTICES) {
  346. int offset = firstUpdateIdx * 3;
  347. int size = (lastUpdateIdx - firstUpdateIdx + 1) * 3;
  348. if (root.autoBounds) {
  349. updateBounds(firstUpdateIdx, lastUpdateIdx);
  350. }
  351. vertexBuffer.position(0);
  352. vertexBuffer.put(vertices, offset, size);
  353. vertexBuffer.flip();
  354. getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
  355. size * PGraphicsAndroid3D.SIZEOF_FLOAT, vertexBuffer);
  356. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
  357. updateElement = -1;
  358. } else {
  359. PGraphics.showWarning("PShape3D: need to call loadVertices() first");
  360. }
  361. }
  362. public void loadColors() {
  363. loadColors(firstVertex, lastVertex);
  364. }
  365. public void loadColors(int first, int last) {
  366. if (last < first || first < firstVertex || lastVertex < last) {
  367. PGraphics.showWarning("PShape3D: wrong vertex index");
  368. updateElement = -1;
  369. return;
  370. }
  371. if (updateElement != -1) {
  372. PGraphics.showWarning("PShape3D: can load only one type of data at the time");
  373. return;
  374. }
  375. updateElement = COLORS;
  376. firstUpdateIdx = first;
  377. lastUpdateIdx = last;
  378. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glColorBufferID);
  379. }
  380. public void updateColors() {
  381. if (updateElement == COLORS) {
  382. int offset = firstUpdateIdx * 4;
  383. int size = (lastUpdateIdx - firstUpdateIdx + 1) * 4;
  384. colorBuffer.position(0);
  385. colorBuffer.put(colors, offset, size);
  386. colorBuffer.flip();
  387. getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
  388. size * PGraphicsAndroid3D.SIZEOF_FLOAT, colorBuffer);
  389. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
  390. updateElement = -1;
  391. } else {
  392. PGraphics.showWarning("PShape3D: need to call loadColors() first");
  393. }
  394. }
  395. public void loadNormals() {
  396. loadNormals(firstVertex, lastVertex);
  397. }
  398. public void loadNormals(int first, int last) {
  399. if (last < first || first < firstVertex || lastVertex < last) {
  400. PGraphics.showWarning("PShape3D: wrong vertex index");
  401. updateElement = -1;
  402. return;
  403. }
  404. if (updateElement != -1) {
  405. PGraphics.showWarning("PShape3D: can load only one type of data at the time");
  406. return;
  407. }
  408. updateElement = NORMALS;
  409. firstUpdateIdx = first;
  410. lastUpdateIdx = last;
  411. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glNormalBufferID);
  412. }
  413. public void updateNormals() {
  414. if (updateElement == NORMALS) {
  415. int offset = firstUpdateIdx * 3;
  416. int size = (lastUpdateIdx - firstUpdateIdx + 1) * 3;
  417. normalBuffer.position(0);
  418. normalBuffer.put(normals, offset, size);
  419. normalBuffer.flip();
  420. getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
  421. size * PGraphicsAndroid3D.SIZEOF_FLOAT, normalBuffer);
  422. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
  423. updateElement = -1;
  424. } else {
  425. PGraphics.showWarning("PShape3D: need to call loadNormals() first");
  426. }
  427. }
  428. public void loadTexcoords() {
  429. loadTexcoords(0);
  430. }
  431. public void loadTexcoords(int unit) {
  432. loadTexcoords(unit, firstVertex, lastVertex);
  433. }
  434. protected void loadTexcoords(int unit, int first, int last) {
  435. if (last < first || first < firstVertex || lastVertex < last) {
  436. PGraphics.showWarning("PShape3D: wrong vertex index");
  437. updateElement = -1;
  438. return;
  439. }
  440. if (updateElement != -1) {
  441. PGraphics.showWarning("PShape3D: can load only one type of data at the time");
  442. return;
  443. }
  444. if (PGraphicsAndroid3D.maxTextureUnits <= unit) {
  445. PGraphics.showWarning("PShape3D: wrong texture unit");
  446. return;
  447. }
  448. updateElement = TEXCOORDS;
  449. firstUpdateIdx = first;
  450. lastUpdateIdx = last;
  451. updateTexunit = unit;
  452. if (numTexBuffers <= unit) {
  453. addTexBuffers(unit - numTexBuffers + 1);
  454. }
  455. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glTexCoordBufferID[unit]);
  456. texcoords = allTexcoords[unit];
  457. }
  458. public void updateTexcoords() {
  459. if (updateElement == TEXCOORDS) {
  460. int offset = firstUpdateIdx * 2;
  461. int size = (lastUpdateIdx - firstUpdateIdx + 1) * 2;
  462. convertTexcoords();
  463. texCoordBuffer.position(0);
  464. texCoordBuffer.put(convTexcoords, offset, size);
  465. texCoordBuffer.flip();
  466. getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
  467. size * PGraphicsAndroid3D.SIZEOF_FLOAT, texCoordBuffer);
  468. getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
  469. texCoordSet[updateTexunit] = true;
  470. updateElement = -1;
  471. } else {
  472. PGraphics.showWarning("PShape3D: need to call loadTexcoords() first");
  473. }
  474. }
  475. public float[] get(int idx) {
  476. float[] v = null;
  477. if (updateElement == VERTICES) {
  478. v = new float[3];
  479. PApplet.arrayCopy(vertices, 3 * idx, v, 0, 3);
  480. } else if (updateElement == COLORS) {
  481. v = new float[4];
  482. PApplet.arrayCopy(colors, 4 * idx, v, 0, 4);
  483. } else if (updateElement == NORMALS) {
  484. v = new float[3];
  485. PApplet.arrayCopy(normals, 3 * idx, v, 0, 3);
  486. } else if (updateElement == TEXCOORDS) {
  487. v = new float[2];
  488. PApplet.arrayCopy(texcoords, 2 * idx, v, 0, 2);
  489. }
  490. return v;
  491. }
  492. public void set(int idx, float[] v) {
  493. if (updateElement == VERTICES) {
  494. PApplet.arrayCopy(v, 0, vertices, 3 * idx, 3);
  495. } else if (updateElement == COLORS) {
  496. PApplet.arrayCopy(v, 0, colors, 4 * idx, 4);
  497. } else if (updateElement == NORMALS) {
  498. PApplet.arrayCopy(v, 0, normals, 3 * idx, 3);
  499. } else if (updateElement == TEXCOORDS) {
  500. PApplet.arrayCopy(v, 0, texcoords, 2 * idx, 2);
  501. }
  502. }
  503. public void set(int idx, int c) {
  504. set(idx, rgba(c));
  505. }
  506. public void set(int idx, float x, float y) {
  507. if (updateElement == VERTICES) {
  508. set(idx, new float[] {x, y, 0});
  509. } else if (updateElement == TEXCOORDS) {
  510. set(idx, new float[] {x, y});
  511. }
  512. }
  513. public void set(int idx, float x, float y, float z) {
  514. if (updateElement == VERTICES) {
  515. set(idx, new float[] {x, y, z});
  516. } else if (updateElement == NORMALS) {
  517. set(idx, new float[] {x, y, z});
  518. } else if (updateElement == COLORS) {
  519. set(idx, new float[] {x, y, z, 1});
  520. }
  521. }
  522. public void set(int idx, float x, float y, float z, float w) {
  523. if (updateElement == COLORS) {
  524. set(idx, new float[] {x, y, z, w});
  525. }
  526. }
  527. static public int color(float[] rgba) {
  528. int r = (int)(rgba[0] * 255);
  529. int g = (int)(rgba[1] * 255);
  530. int b = (int)(rgba[2] * 255);
  531. int a = (int)(rgba[3] * 255);
  532. return a << 24 | r << 16 | g << 8 | b;
  533. }
  534. static public float[] rgba(int c) {
  535. int a = (c >> 24) & 0xFF;
  536. int r = (c >> 16) & 0xFF;
  537. int g = (c >> 8) & 0xFF;
  538. int b = (c >> 0) & 0xFF;
  539. float[] res = new float[4];
  540. res[0] = r / 255.0f;
  541. res[1] = g / 255.0f;
  542. res[2] = b / 255.0f;
  543. res[3] = a / 255.0f;
  544. return res;
  545. }
  546. public void autoBounds(boolean value) {
  547. root.autoBounds = value;
  548. }
  549. public void updateBounds() {
  550. updateBounds(firstVertex, lastVertex);
  551. }
  552. protected void updateBounds(int first, int last) {
  553. if (first <= firstVertex && lastVertex <= last) {
  554. resetBounds();
  555. }
  556. if (family == GROUP) {
  557. if (root == this && childCount == 0) {
  558. // This might happen: the vertices has been set
  559. // first but children still not initialized. So we
  560. // need to calculate the bounding box directly:
  561. for (int i = firstVertex; i <= lastVertex; i++) {
  562. updateBounds(vertices[3 * i + 0], vertices[3 * i + 1], vertices[3 * i + 2]);
  563. }
  564. } else {
  565. for (int i = 0; i < childCount; i++) {
  566. PShape3D child = (PShape3D)children[i];
  567. child.updateBounds(first, last);
  568. xmin = PApplet.min(xmin, child.xmin);
  569. xmax = PApplet.max(xmax, child.xmax);
  570. ymin = PApplet.min(ymin, child.ymin);
  571. ymax = PApplet.max(ymax, child.ymax);
  572. zmin = PApplet.min(zmin, child.zmin);
  573. zmax = PApplet.max(zmax, child.zmax);
  574. width = xmax - xmin;
  575. height = ymax - ymin;
  576. depth = zmax - zmin;
  577. }
  578. }
  579. } else {
  580. // TODO: extract minimum and maximum values using some sorting algorithm (maybe).
  581. int n0 = PApplet.max(first, firstVertex);
  582. int n1 = PApplet.min(last, lastVertex);
  583. for (int i = n0; i <= n1; i++) {
  584. updateBounds(vertices[3 * i + 0], vertices[3 * i + 1], vertices[3 * i + 2]);
  585. }
  586. }
  587. }
  588. protected void resetBounds() {
  589. if (family == GROUP) {
  590. for (int i = 0; i < childCount; i++) {
  591. ((PShape3D)children[i]).resetBounds();
  592. }
  593. }
  594. width = height = depth = 0;
  595. xmin = ymin = zmin = 10000;
  596. xmax = ymax = zmax = -10000;
  597. }
  598. protected void updateBounds(float x, float y, float z) {
  599. xmin = PApplet.min(xmin, x);
  600. xmax = PApplet.max(xmax, x);
  601. ymin = PApplet.min(ymin, y);
  602. ymax = PApplet.max(ymax, y);
  603. zmin = PApplet.min(zmin, z);
  604. zmax = PApplet.max(zmax, z);
  605. width = xmax - xmin;
  606. height = ymax - ymin;
  607. depth = zmax - zmin;
  608. }
  609. // Convert texture coordinates given by the user to values required by
  610. // the GPU (non-necessarily normalized because of texture size being smaller
  611. // than image size, for instance).
  612. protected void convertTexcoords() {
  613. PTexture tex;
  614. float u, v;
  615. PTexture tex0 = null;
  616. float uscale = 1.0f;
  617. float vscale = 1.0f;
  618. float cx = 0.0f;
  619. float sx = +1.0f;
  620. float cy = 0.0f;
  621. float sy = +1.0f;
  622. for (int i = firstUpdateIdx; i <= lastUpdateIdx; i++) {
  623. if (vertexChild[i] != null && vertexChild[i].textures[updateTexunit] != null) {
  624. PImage img = vertexChild[i].textures[updateTexunit];
  625. tex = a3d.getTexture(img);
  626. if (tex != tex0) {
  627. uscale = 1.0f;
  628. vscale = 1.0f;
  629. cx = 0.0f;
  630. sx = +1.0f;
  631. cy = 0.0f;
  632. sy = +1.0f;
  633. if (tex != null) {
  634. if (tex.isFlippedX()) {
  635. cx = 1.0f;
  636. sx = -1.0f;
  637. }
  638. if (tex.isFlippedY()) {
  639. cy = 1.0f;
  640. sy = -1.0f;
  641. }
  642. uscale *= tex.getMaxTexCoordU();
  643. vscale *= tex.getMaxTexCoordV();
  644. }
  645. tex0 = tex;
  646. }
  647. u = texcoords[2 * i + 0];
  648. v = texcoords[2 * i + 1];
  649. u = (cx + sx * u) * uscale;
  650. v = (cy + sy * v) * vscale;
  651. convTexcoords[2 * i + 0] = u;
  652. convTexcoords[2 * i + 1] = v;
  653. }
  654. }
  655. }
  656. ////////////////////////////////////////////////////////////
  657. // Child shapes
  658. static public PShape createChild(int n0, int n1) {
  659. return createChild(null, n0, n1, POINTS, 0, null);
  660. }
  661. static public PShape createChild(String name, int n0, int n1) {
  662. return createChild(name, n0, n1, POINTS, 0, null);
  663. }
  664. static public PShape createChild(String name, int n0, int n1, int mode) {
  665. return createChild(name, n0, n1, mode, 0, null);
  666. }
  667. static public PShape createChild(String name, int n0, int n1, int mode, float weight) {
  668. return createChild(name, n0, n1, mode, weight, null);
  669. }
  670. static public PShape createChild(String name, int n0, int n1, int i0, int i1, int mode, float weight, PImage[] tex) {
  671. PShape3D child = (PShape3D)createChild(name, n0, n1, mode, weight, tex);
  672. child.firstIndex = i0;
  673. child.lastIndex = i1;
  674. return child;
  675. }
  676. static public PShape createChild(String name, int n0, int n1, int mode, float weight, PImage[] tex) {
  677. PShape3D child = new PShape3D();
  678. child.family = PShape.GEOMETRY;
  679. child.name = name;
  680. child.firstVertex = n0;
  681. child.lastVertex = n1;
  682. child.setDrawModeImpl(mode);
  683. child.strokeWeight = weight;
  684. child.textures = new PImage[PGraphicsAndroid3D.MAX_TEXTURES];
  685. child.renderTextures = new PTexture[PGraphicsAndroid3D.MAX_TEXTURES];
  686. java.util.Arrays.fill(child.textures, null);
  687. if (tex != null) {
  688. int n = PApplet.min(tex.length, child.textures.length);
  689. PApplet.arrayCopy(tex, 0, child.textures, 0, n);
  690. }
  691. return child;
  692. }
  693. public void addChild(String name, int n0, int n1) {
  694. PShape child = createChild(name, n0, n1, getDrawModeImpl());
  695. addChild(child);
  696. }
  697. public void addChild(String name, int n0, int n1, int mode) {
  698. PShape child = createChild(name, n0, n1, mode);
  699. addChild(child);
  700. }
  701. public void addChild(String name, int n0, int n1, int mode, float weight) {
  702. PShape child = createChild(name, n0, n1, mode, weight);
  703. addChild(child);
  704. }
  705. public void addChild(String name, int n0, int n1, int mode, float weight, PImage[] tex) {
  706. PShape child = createChild(name, n0, n1, mode, weight, tex);
  707. addChild(child);
  708. }
  709. public void addChild(PShape who) {
  710. addChildImpl(who, true);
  711. }
  712. protected void addChildImpl(PShape who, boolean newShape) {
  713. if (family == GROUP) {
  714. super.addChild(who);
  715. if (newShape) {
  716. PShape3D who3d = (PShape3D)who;
  717. who3d.papplet = papplet;
  718. who3d.a3d = a3d;
  719. who3d.root = root;
  720. // So we can use the load/update methods in the child geometries.
  721. who3d.numTexBuffers = root.numTexBuffers;
  722. who3d.glVertexBufferID = root.glVertexBufferID;
  723. who3d.glColorBufferID = root.glColorBufferID;
  724. who3d.glNormalBufferID = root.glNormalBufferID;
  725. who3d.glTexCoordBufferID = root.glTexCoordBufferID;
  726. who3d.glIndexBufferID = root.glIndexBufferID;
  727. who3d.vertexBuffer = root.vertexBuffer;
  728. who3d.colorBuffer = root.colorBuffer;
  729. who3d.normalBuffer = root.normalBuffer;
  730. who3d.texCoordBuffer = root.texCoordBuffer;
  731. who3d.vertices = root.vertices;
  732. who3d.colors = root.colors;
  733. who3d.normals = root.normals;
  734. who3d.texcoords = root.texcoords;
  735. who3d.convTexcoords = root.convTexcoords;
  736. who3d.allTexcoords = root.allTexcoords;
  737. who3d.vertexChild = root.vertexChild;
  738. who3d.texCoordSet = root.texCoordSet;
  739. // In case the style was disabled from the root.
  740. who3d.style = root.style;
  741. // Updating vertex information.
  742. for (int n = who3d.firstVertex; n <= who3d.lastVertex; n++) {
  743. who3d.vertexChild[n] = who3d;
  744. }
  745. // If this new child shape has textures, then we should update the texture coordinates
  746. // for the vertices involved. All we need to do is to call loadTexcoords and updateTexcoords
  747. // so the current texture coordinates are converted into values that take into account
  748. // the texture flipping, max UV ranges, etc.
  749. for (int i = 0; i < who3d.textures.length; i++) {
  750. if (who3d.textures[i] != null && who3d.texCoordSet[i]) {
  751. who3d.loadTexcoords(i);
  752. who3d.updateTexcoords();
  753. }
  754. }
  755. }
  756. } else {
  757. PGraphics.showWarning("PShape3D: Child shapes can only be added to a group shape.");
  758. }
  759. }
  760. /**
  761. * Add a shape to the name lookup table.
  762. */
  763. public void addName(String nom, PShape shape) {
  764. if (nameTable == null) {
  765. nameTable = new HashMap<String,PShape>();
  766. }
  767. nameTable.put(nom, shape);
  768. }
  769. protected void addDefaultChild() {
  770. PShape child = createChild("geometry", 0, vertexCount - 1, getDrawModeImpl(), 0, null);
  771. addChild(child);
  772. }
  773. public PShape groupChildren(int cidx0, int cidx1, String gname) {
  774. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  775. return groupChildren(new int[] {cidx0, cidx1}, gname);
  776. }
  777. public PShape groupChildren(int cidx0, int cidx1, int cidx2, String gname) {
  778. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  779. return groupChildren(new int[] {cidx0, cidx1, cidx2}, gname);
  780. }
  781. public PShape groupChildren(int[] cidxs, String gname) {
  782. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  783. PShape[] temp = new PShape[cidxs.length];
  784. int nsel = 0;
  785. for (int i = 0; i < cidxs.length; i++) {
  786. PShape child = getChild(cidxs[i]);
  787. if (child != null) {
  788. temp[nsel] = child;
  789. nsel++;
  790. }
  791. }
  792. PShape[] schildren = new PShape[nsel];
  793. PApplet.arrayCopy(temp, schildren, nsel);
  794. return groupChildren(schildren, gname);
  795. }
  796. public PShape groupChildren(String cname0, String cname1, String gname) {
  797. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  798. return groupChildren(new String[] {cname0, cname1}, gname);
  799. }
  800. public PShape groupChildren(String cname0, String cname1, String cname2, String gname) {
  801. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  802. return groupChildren(new String[] {cname0, cname1, cname2}, gname);
  803. }
  804. public PShape groupChildren(String[] cnames, String gname) {
  805. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  806. PShape[] temp = new PShape[cnames.length];
  807. int nsel = 0;
  808. for (int i = 0; i < cnames.length; i++) {
  809. PShape child = getChild(cnames[i]);
  810. if (child != null) {
  811. temp[nsel] = child;
  812. nsel++;
  813. }
  814. }
  815. PShape[] schildren = new PShape[nsel];
  816. PApplet.arrayCopy(temp, schildren, nsel);
  817. return groupChildren(schildren, gname);
  818. }
  819. public PShape groupChildren(PShape[] gchildren, String gname) {
  820. if (family != GROUP) return null; // Can be done only in a GROUP shape.
  821. // Creating the new group containing the children.
  822. PShape3D group = new PShape3D();
  823. group.family = PShape.GROUP;
  824. group.name = gname;
  825. group.papplet = papplet;
  826. group.a3d = a3d;
  827. group.root = root;
  828. PShape child, p;
  829. int idx;
  830. // Inserting the new group at the position of the first
  831. // child shape in the group (in its original parent).
  832. child = gchildren[0];
  833. p = child.parent;
  834. if (p != null) {
  835. idx = p.getChildIndex(child);
  836. if (idx < 0) idx = 0;
  837. } else {
  838. p = this;
  839. idx = 0;
  840. }
  841. p.addChild(group, idx);
  842. // Removing the children in the new group from their
  843. // respective parents.
  844. for (int i = 0; i < gchildren.length; i++) {
  845. child = gchildren[i];
  846. p = child.parent;
  847. if (p != null) {
  848. idx = p.getChildIndex(child);
  849. if (-1 < idx) {
  850. p.removeChild(idx);
  851. }
  852. }
  853. }
  854. group.firstVertex = root.vertexCount;
  855. group.lastVertex = 0;
  856. for (int i = 0; i < gchildren.length; i++) {
  857. group.firstVertex = PApplet.min(group.firstVertex, ((PShape3D)gchildren[i]).firstVertex);
  858. group.lastVertex = PApplet.max(group.lastVertex, ((PShape3D)gchildren[i]).lastVertex);
  859. }
  860. // Adding the children shapes to the new group.
  861. for (int i = 0; i < gchildren.length; i++) {
  862. group.addChildImpl(gchildren[i], false);
  863. }
  864. return group;
  865. }
  866. public int getFirstVertex() {
  867. return firstVertex;
  868. }
  869. public int getFirstVertex(int idx) {
  870. if (0 <= idx && idx < childCount) {
  871. return ((PShape3D)children[idx]).getFirstVertex();
  872. }
  873. return -1;
  874. }
  875. public void setFirstVertex(int n0) {
  876. firstVertex = n0;
  877. }
  878. public void setFirstVertex(int idx, int n0) {
  879. if (0 <= idx && idx < childCount) {
  880. ((PShape3D)children[idx]).setFirstVertex(n0);
  881. }
  882. }
  883. public int getLastVertex() {
  884. return lastVertex;
  885. }
  886. public int getLastVertex(int idx) {
  887. if (0 <= idx && idx < childCount) {
  888. return ((PShape3D)children[idx]).getLastVertex();
  889. }
  890. return -1;
  891. }
  892. public void setLastVertex(int n1) {
  893. lastVertex = n1;
  894. }
  895. public void setLastVertex(int idx, int n1) {
  896. if (0 <= idx && idx < childCount) {
  897. ((PShape3D)children[idx]).setLastVertex(n1);
  898. }
  899. }
  900. public void setDrawMode(int mode) {
  901. if (family == GROUP) {
  902. init();
  903. setDrawModeImpl(mode);
  904. for (int n = 0; n < childCount; n++) {
  905. setDrawMode(n, mode);
  906. }
  907. } else {
  908. setDrawModeImpl(mode);
  909. }
  910. }
  911. public void setDrawMode(int idx, int mode) {
  912. if (0 <= idx && idx < childCount) {
  913. ((PShape3D)children[idx]).setDrawMode(mode);
  914. }
  915. }
  916. protected void setDrawModeImpl(int mode) {
  917. pointSprites = false;
  918. if (mode == POINTS) glMode = GL11.GL_POINTS;
  919. else if (mode == POINT_SPRITES) {
  920. glMode = GL11.GL_POINTS;
  921. pointSprites = true;
  922. }
  923. else if (mode == LINES) glMode = GL11.GL_LINES;
  924. else if (mode == LINE_STRIP) glMode = GL11.GL_LINE_STRIP;
  925. else if (mode == LINE_LOOP) glMode = GL11.GL_LINE_LOOP;
  926. else if (mode == TRIANGLES) glMode = GL11.GL_TRIANGLES;
  927. else if (mode == TRIANGLE_FAN) glMode = GL11.GL_TRIANGLE_FAN;
  928. else if (mode == TRIANGLE_STRIP) glMode = GL11.GL_TRIANGLE_STRIP;
  929. else {
  930. throw new RuntimeException("PShape3D: Unknown draw mode");
  931. }
  932. }
  933. protected boolean isTexturable() {
  934. return glMode == GL11.GL_TRIANGLES ||
  935. glMode == GL11.GL_TRIANGLE_FAN ||
  936. glMode == GL11.GL_TRIANGLE_STRIP ||
  937. pointSprites;
  938. }
  939. public int getDrawMode() {
  940. if (family == GROUP) {
  941. init();
  942. return getDrawMode(0);
  943. } else {
  944. return getDrawModeImpl();
  945. }
  946. }
  947. public int getDrawMode(int idx) {
  948. if (0 <= idx && idx < childCount) {
  949. return ((PShape3D)children[idx]).getDrawMode();
  950. }
  951. return -1;
  952. }
  953. protected int getDrawModeImpl() {
  954. if (glMode == GL11.GL_POINTS) {
  955. if (pointSprites) return POINT_SPRITES;
  956. else return POINTS;
  957. } else if (glMode == GL11.GL_LINES) return LINES;
  958. else if (glMode == GL11.GL_LINE_STRIP) return LINE_STRIP;
  959. else if (glMode == GL11.GL_LINE_LOOP) return LINE_LOOP;
  960. else if (glMode == GL11.GL_TRIANGLES) return TRIANGLES;
  961. else if (glMode == GL11.GL_TRIANGLE_FAN) return TRIANGLE_FAN;
  962. else if (glMode == GL11.GL_TRIANGLE_STRIP) return TRIANGLE_STRIP;
  963. else return -1;
  964. }
  965. public void setTexture(PImage tex) {
  966. if (family == GROUP) {
  967. init();
  968. for (int i = 0; i < childCount; i++) {
  969. setTexture(i, tex);
  970. }
  971. } else {
  972. setTextureImpl(tex, 0);
  973. }
  974. }
  975. public void setTexture(PImage tex0, PImage tex1) {
  976. if (family == GROUP) {
  977. init();
  978. for (int i = 0; i < childCount; i++) {
  979. setTexture(i, tex0, tex1);
  980. }
  981. } else {
  982. setTextureImpl(tex0, 0);
  983. setTextureImpl(tex1, 1);
  984. }
  985. }
  986. public void setTexture(PImage tex0, PImage tex1, PImage tex2) {
  987. if (family == GROUP) {
  988. init();
  989. for (int i = 0; i < childCount; i++) {
  990. setTexture(i, tex0, tex1, tex2);
  991. }
  992. } else {
  993. setTextureImpl(tex0, 0);
  994. setTextureImpl(tex1, 1);
  995. setTextureImpl(tex2, 2);
  996. }
  997. }
  998. public void setTexture(PImage tex0, PImage tex1, PImage tex2, PImage tex3) {
  999. if (family == GROUP) {
  1000. init();
  1001. for (int i = 0; i < childCount; i++) {
  1002. setTexture(i, tex0, tex1, tex2, tex3);
  1003. }
  1004. } else {
  1005. setTextureImpl(tex0, 0);
  1006. setTextureImpl(tex1, 1);
  1007. setTextureImpl(tex2, 2);
  1008. setTextureImpl(tex3, 3);
  1009. }
  1010. }
  1011. public void setTexture(PImage[] tex) {
  1012. if (family == GROUP) {
  1013. init();
  1014. for (int i = 0; i < childCount; i++) {
  1015. setTexture(i, tex);
  1016. }
  1017. } else {
  1018. for (int i = 0; i < tex.length; i++) {
  1019. setTextureImpl(tex[i], i);
  1020. }
  1021. }
  1022. }
  1023. public void setTexture(int idx, PImage tex) {
  1024. if (0 <= idx && idx < childCount) {
  1025. ((PShape3D)children[idx]).setTexture(tex);
  1026. }
  1027. }
  1028. public void setTexture(int idx, PImage tex0, PImage tex1) {
  1029. if (0 <= idx && idx < childCount) {
  1030. ((PShape3D)children[idx]).setTexture(tex0, tex1);
  1031. }
  1032. }
  1033. public void setTexture(int idx, PImage tex0, PImage tex1, PImage tex2) {
  1034. if (0 <= idx && idx < childCount) {
  1035. ((PShape3D)children[idx]).setTexture(tex0, tex1, tex2);
  1036. }
  1037. }
  1038. public void setTexture(int idx, PImage tex0, PImage tex1, PImage tex2, PImage tex3) {
  1039. if (0 <= idx && idx < childCount) {
  1040. ((PShape3D)children[idx]).setTexture(tex0, tex1, tex2, tex3);
  1041. }
  1042. }
  1043. public void setTexture(int idx, PImage[] tex) {
  1044. if (0 <= idx && idx < childCount) {
  1045. ((PShape3D)children[idx]).setTexture(tex);
  1046. }
  1047. }
  1048. protected void setTextureImpl(PImage tex, int unit) {
  1049. if (unit < 0 || PGraphicsAndroid3D.maxTextureUnits <= unit) {
  1050. System.err.println("PShape3D: Wrong texture unit.");
  1051. return;
  1052. }
  1053. if (numTexBuffers <= unit) {
  1054. root.addTexBuffers(unit - numTexBuffers + 1);
  1055. }
  1056. if (tex == null) {
  1057. throw new RuntimeException("PShape3D: trying to set null texture.");
  1058. }
  1059. if (texCoordSet[unit] && isTexturable()) {
  1060. // Ok, setting a new texture, when texture coordinates have already been set.
  1061. // What is the problem? the new texture might have different max UV coords,
  1062. // flippedX/Y values, so the texture coordinates need to be updated accordingly...
  1063. // The way to do it is just load the texcoords array (in the parent)...
  1064. loadTexcoords(unit);
  1065. // ... then replacing the old texture with the new and...
  1066. textures[unit] = tex;
  1067. // ...,finally, updating the texture coordinates, step in which the texcoords
  1068. // array is converted, this time using the new texture.
  1069. updateTexcoords();
  1070. } else {
  1071. textures[unit] = tex;
  1072. }
  1073. }
  1074. public PImage[] getTexture() {
  1075. if (family == GROUP) {
  1076. init();
  1077. return getTexture(0);
  1078. } else {
  1079. return textures;
  1080. }
  1081. }
  1082. public PImage[] getTexture(int idx) {
  1083. if (0 <= idx && idx < childCount) {
  1084. return ((PShape3D)children[idx]).getTexture();
  1085. }
  1086. return null;
  1087. }
  1088. public float getStrokeWeight() {
  1089. if (family == GROUP) {
  1090. init();
  1091. return getStrokeWeight(0);
  1092. } else {
  1093. return strokeWeight;
  1094. }
  1095. }
  1096. public float getStrokeWeight(int idx) {
  1097. if (0 <= idx && idx < childCount) {
  1098. return ((PShape3D)children[idx]).getStrokeWeight();
  1099. }
  1100. return 0;
  1101. }
  1102. public void setStrokeWeight(float sw) {
  1103. if (family == GROUP) {
  1104. init();
  1105. for (int i = 0; i < childCount; i++) {
  1106. setStrokeWeight(i, sw);
  1107. }
  1108. } else {
  1109. strokeWeight = sw;
  1110. }
  1111. }
  1112. public void setStrokeWeight(int idx, float sw) {
  1113. if (0 <= idx && idx < childCount) {
  1114. ((PShape3D)children[idx]).setStrokeWeight(sw);
  1115. }
  1116. }
  1117. public float getMaxSpriteSize() {
  1118. if (family == GROUP) {
  1119. init();
  1120. return getMaxSpriteSize(0);
  1121. } else {
  1122. return maxSpriteSize;
  1123. }
  1124. }
  1125. public float getMaxSpriteSize(int idx) {
  1126. if (0 <= idx && idx < childCount) {
  1127. return ((PShape3D)children[idx]).getMaxSpriteSize();
  1128. }
  1129. return 0;
  1130. }
  1131. public void setMaxSpriteSize(float s) {
  1132. if (family == GROUP) {
  1133. init();
  1134. for (int i = 0; i < childCount; i++) {
  1135. setMaxSpriteSize(i, s);
  1136. }
  1137. } else {
  1138. setMaxSpriteSizeImpl(s);
  1139. }
  1140. }
  1141. public void setMaxSpriteSize(int idx, float s) {
  1142. if (0 <= idx && idx < childCount) {
  1143. ((PShape3D)children[idx]).setMaxSpriteSize(s);
  1144. }
  1145. }
  1146. protected void setMaxSpriteSizeImpl(float s) {
  1147. maxSpriteSize = PApplet.min(s, PGraphicsAndroid3D.maxPointSize);
  1148. }
  1149. public void setSpriteSize(float s) {
  1150. if (family == GROUP) {
  1151. init();
  1152. for (int i = 0; i < childCount; i++) {
  1153. setSpriteSize(i, s);
  1154. }
  1155. } else {
  1156. setSpriteSizeImpl(s);
  1157. }
  1158. }
  1159. public void setSpriteSize(float s, float d, int mode) {
  1160. if (family == GROUP) {
  1161. init();
  1162. for (int i = 0; i < childCount; i++) {
  1163. setSpriteSize(i, s, d, mode);
  1164. }
  1165. } else {
  1166. setSpriteSizeImpl(s, d, mode);
  1167. }
  1168. }
  1169. public void setSpriteSize(int idx, float s) {
  1170. if (0 <= idx && idx < childCount) {
  1171. ((PShape3D)children[idx]).setSpriteSize(s);
  1172. }
  1173. }
  1174. public void setSpriteSize(int idx, float s, float d, int mode) {
  1175. if (0 <= idx && idx < childCount) {
  1176. ((PShape3D)children[idx]).setSpriteSize(s, d, mode);
  1177. }
  1178. }
  1179. // Sets the coefficient of the distance attenuation function so that the
  1180. // size of the sprite is exactly s when its distance from the camera is d.
  1181. protected void setSpriteSizeImpl(float s, float d, int mode) {
  1182. float s0 = maxSpriteSize;
  1183. if (mode == LINEAR) {
  1184. spriteDistAtt[1] = (s0 - s) / (d * s);
  1185. spriteDistAtt[2] = 0;
  1186. } else if (mode == QUADRATIC) {
  1187. spriteDistAtt[1] = 0;
  1188. spriteDistAtt[2] = (s0 - s) / (d * d * s);
  1189. } else {
  1190. PGraphics.showWarning("Invalid point sprite mode");
  1191. }
  1192. }
  1193. // Sets constant sprite size equal to s.
  1194. protected void setSpriteSizeImpl(float s) {
  1195. setMaxSpriteSizeImpl(s);
  1196. spriteDistAtt[1] = 0;
  1197. spriteDistAtt[2] = 0;
  1198. }
  1199. public void setColor(int c) {
  1200. setColor(rgba(c));
  1201. }
  1202. public void setColor(float r, float g, float b, float a) {
  1203. setColor(new float[] {r, g, b, a});
  1204. }
  1205. public void setColor(float[] c) {
  1206. if (family == GROUP) {
  1207. init();
  1208. for (int i = 0; i < childCount; i++) {
  1209. setColor(i, c);
  1210. }
  1211. } else {
  1212. setColorImpl(c);
  1213. }
  1214. }
  1215. public void setColor(int idx, int c) {
  1216. setColor(idx, rgba(c));
  1217. }
  1218. public void setColor(int idx, float r, float g, float b, float a) {
  1219. setColor(idx, new float[] {r, g, b, a});
  1220. }
  1221. public void setColor(int idx, float[] c) {
  1222. if (0 <= idx && idx < childCount) {
  1223. ((PShape3D)children[idx]).setColor(c);
  1224. }
  1225. }
  1226. protected void setColorImpl(float[] c) {
  1227. PShape3D p = (PShape3D)root;
  1228. p.loadColors();
  1229. for (int i = firstVertex; i <= lastVertex; i++) {
  1230. p.set(i, c);
  1231. }
  1232. p.updateColors();
  1233. }
  1234. public void setNormal(float nx, float ny, float nz) {
  1235. setNormal(new float[] {nx, ny, nz});
  1236. }
  1237. public void setNormal(float[] n) {
  1238. if (family == GROUP) {
  1239. init();
  1240. for (int i = 0; i < childCount; i++) {
  1241. setNormal(i, n);
  1242. }
  1243. } else {
  1244. setNormalImpl(n);
  1245. }
  1246. }
  1247. public void setNormal(int idx, float nx, float ny, float nz) {
  1248. setNormal(idx, new float[] {nx, ny, nz});
  1249. }
  1250. public void setNormal(int idx, float[] n) {
  1251. if (0 <= idx && idx < childCount) {
  1252. ((PShape3D)children[idx]).setNormal(n);
  1253. }
  1254. }
  1255. protected void setNormalImpl(float[] n) {
  1256. PShape3D p = (PShape3D)root;
  1257. p.loadNormals();
  1258. for (int i = firstVertex; i <= lastVertex; i++) {
  1259. p.set(i, n);
  1260. }
  1261. p.updateNormals();
  1262. }
  1263. // Optimizes the array list containing children shapes so that shapes with identical
  1264. // parameters are removed. Also, making sure that the names are unique.
  1265. protected void optimizeChildren(ArrayList<PShape3D> childList) {
  1266. PShape3D child0, child1;
  1267. // Expanding identical, contiguous shapes. Names are taken into account (two
  1268. // shapes with different names are considered to be different, even though the
  1269. // rest of their parameters are identical).
  1270. child0 = (PShape3D)childList.get(0);
  1271. for (int i = 1; i < childList.size(); i++) {
  1272. child1 = (PShape3D)childList.get(i);
  1273. if (child0.equalTo(child1, false)) {
  1274. child0.lastVertex = child1.lastVertex; // Extending child0.
  1275. child0.lastIndex = child1.lastIndex;
  1276. // Updating the vertex data:
  1277. for (int n = child0.firstVertex; n <= child0.lastVertex; n++) {
  1278. vertexChild[n] = child0;
  1279. }
  1280. child1.firstVertex = child1.lastVertex = -1; // Marking for deletion.
  1281. } else {
  1282. child0 = child1;
  1283. }
  1284. }
  1285. // Deleting superfluous shapes.
  1286. for (int i = childList.size() - 1; i >= 0; i--) {
  1287. if (((PShape3D)childList.get(i)).lastVertex == -1) {
  1288. childList.remove(i);
  1289. }
  1290. }
  1291. // Making sure the names are unique.
  1292. for (int i = 1; i < childList.size(); i++) {
  1293. child1 = (PShape3D)childList.get(i);
  1294. for (int j = i - 1; j >= 0; j--) {
  1295. child0 = (PShape3D)childList.get(j);
  1296. if (child1.name.equals(child0.name)) {
  1297. int pos = child0.name.indexOf(':');
  1298. if (-1 < pos) {
  1299. // The name of the preceding child contains the ':'
  1300. // character so trying to use the following substring
  1301. // as a number.
  1302. String nstr = child0.name.substring(pos + 1);
  1303. int n = 1;
  1304. try {
  1305. n = Integer.parseInt(nstr);
  1306. } catch (NumberFormatException e) {
  1307. child0.name += ":1";
  1308. }
  1309. child1.name += ":" + (n + 1);
  1310. } else {
  1311. child0.name += ":1";
  1312. child1.name += ":2";
  1313. }
  1314. }
  1315. }
  1316. }
  1317. }
  1318. protected boolean equalTo(PShape3D child, boolean ignoreNames) {
  1319. boolean res = family == child.family &&
  1320. glMode == child.glMode &&
  1321. strokeWeight == child.strokeWeight &&
  1322. (ignoreNames || name.equals(child.name));
  1323. if (!res) return false;
  1324. for (int i = 0; i < textures.length; i++) {
  1325. if (textures[i] != child.textures[i]) {
  1326. res = false;
  1327. }
  1328. }
  1329. return res;
  1330. }
  1331. ////////////////////////////////////////////////////////////
  1332. // Some overloading of translate, rotate, scale
  1333. public void resetMatrix() {
  1334. checkMatrix(3);
  1335. matrix.reset();
  1336. }
  1337. public void translate(float tx, float ty) {
  1338. checkMatrix(3);
  1339. matrix.translate(tx, ty, 0);
  1340. }
  1341. public void rotate(float angle) {
  1342. checkMatrix(3);
  1343. matrix.rotate(angle);
  1344. }
  1345. public void scale(float s) {
  1346. checkMatrix(3);
  1347. matrix.scale(s);
  1348. }
  1349. public void scale(float x, float y) {
  1350. checkMatrix(3);
  1351. matrix.scale(x, y);
  1352. }
  1353. public void centerAt(float cx, float cy, float cz) {
  1354. float dx = cx - 0.5f * (xmin + xmax);
  1355. float dy = cy - 0.5f * (ymin + ymax);
  1356. float dz = cz - 0.5f * (zmin + zmax);
  1357. // Centering
  1358. loadVertices();
  1359. for (int i = 0; i < vertexCount; i++) {
  1360. vertices[3 * i + 0] += dx;
  1361. vertices[3 * i + 1] += dy;
  1362. vertices[3 * i + 2] += dz;
  1363. }
  1364. updateVertices();
  1365. }
  1366. ////////////////////////////////////////////////////////////
  1367. // Bulk vertex operations.
  1368. public void setVertices(ArrayList<PVector> vertexList) {
  1369. setVertices(vertexList, 0);
  1370. }
  1371. public void setVertices(ArrayList<PVector> vertexList, int offset) {
  1372. loadVertices();
  1373. for (int i = firstVertex; i <= lastVertex; i++) {
  1374. PVector v = (PVector)vertexList.get(i - firstVertex + offset);
  1375. set(i, v.x, v.y, v.z);
  1376. }
  1377. updateVertices();
  1378. }
  1379. public void setColors(ArrayList<float[]> colorList) {
  1380. setColors(colorList, 0);
  1381. }
  1382. public void setColors(ArrayList<float[]> colorList, int offset) {
  1383. loadColors();
  1384. for (int i = firstVertex; i <= lastVertex; i++) {
  1385. float[] c = (float[])colorList.get(i - firstVertex + offset);
  1386. set(i, c);
  1387. }
  1388. updateColors();
  1389. }
  1390. public void setNormals(ArrayList<PVector> normalList) {
  1391. setNormals(normalList, 0);
  1392. }
  1393. public void setNormals(ArrayList<PVector> normalList, int offset) {
  1394. loadNormals();
  1395. for (int i = firstVertex; i <= lastVertex; i++) {
  1396. PVector n = (PVector)normalList.get(i - firstVertex + offset);
  1397. set(i, n.x, n.y, n.z);
  1398. }
  1399. updateNormals();
  1400. }
  1401. public void setTexcoor