/core/src/processing/core/PShape3D.java
Java | 1796 lines | 1285 code | 391 blank | 120 comment | 342 complexity | e5272960b6bccf1d8a90847fc7cc14f2 MD5 | raw file
- /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
- /*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2010 Ben Fry and Casey Reas
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License version 2.1 as published by the Free Software Foundation.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General
- Public License along with this library; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
- */
-
- package processing.core;
-
- import java.nio.FloatBuffer;
- import java.nio.ByteBuffer;
- import java.nio.ByteOrder;
- import java.nio.ShortBuffer;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.Hashtable;
- import java.io.BufferedReader;
-
- import javax.microedition.khronos.opengles.*;
-
- /**
- * This class holds a 3D model composed of vertices, normals, colors (per vertex) and
- * texture coordinates (also per vertex). All this data is stored in Vertex Buffer Objects
- * (VBO) in GPU memory for very fast access.
- * OBJ loading implemented using code from Saito's OBJLoader library (http://code.google.com/p/saitoobjloader/)
- * and OBJReader from Ahmet Kizilay (http://www.openprocessing.org/visuals/?visualID=191).
- * By Andres Colubri
- *
- */
- public class PShape3D extends PShape implements PConstants {
- protected PApplet papplet;
- protected PGraphicsAndroid3D a3d;
-
- // Element types handled by PShape3D (vertices, normals, color, texture coordinates).
- protected static final int VERTICES = 0;
- protected static final int NORMALS = 1;
- protected static final int COLORS = 2;
- protected static final int TEXCOORDS = 3;
-
- // ROOT shape properties:
-
- // Number of texture buffers currently in use:
- protected int numTexBuffers;
-
- // STATIC or DYNAMIC
- // TODO: vertex, color, normal and texcoord data can potentially have
- // different usage modes.
- protected int glUsage;
-
- // The OpenGL IDs for the different VBOs
- public int glVertexBufferID;
- public int glColorBufferID;
- public int glNormalBufferID;
- public int[] glTexCoordBufferID;
-
- // The float buffers (directly allocated) used to put data into the VBOs
- protected FloatBuffer vertexBuffer;
- protected FloatBuffer colorBuffer;
- protected FloatBuffer normalBuffer;
- protected FloatBuffer texCoordBuffer;
-
- // Public arrays for setting/getting vertices, colors, normals, and
- // texture coordinates when using loadVertices/updateVertices,
- // loadNormals/updateNormals, etc. This is modeled following the
- // loadPixels/updatePixels API for setting/getting pixel data in
- // PImage.
- public float[] vertices;
- public float[] colors;
- public float[] normals;
- public float[] texcoords;
-
- // Indexed mode, testing:
- protected int glIndexBufferID = 0;
- protected ShortBuffer indexBuffer = null;
- protected int indexCount = 0;
- protected short[] indices;
- protected boolean useIndices;
-
- // To put the texture coordinate values adjusted according to texture
- // flipping mode, max UV range, etc.
- protected float[] convTexcoords;
- // The array of arrays holding the texture coordinates for all texture units.
- protected float[][] allTexcoords;
-
- // Child PShape3D associated to each vertex in the model.
- protected PShape3D[] vertexChild;
-
- // Some utility arrays.
- protected boolean[] texCoordSet;
-
- protected boolean autoBounds = true;
-
- // For OBJ loading. Only used by the root shape.
- boolean readFromOBJ = false;
- ArrayList<PVector> objVertices;
- ArrayList<PVector> objNormal;
- ArrayList<PVector> objTexCoords;
- ArrayList<OBJFace> objFaces;
- ArrayList<OBJMaterial> objMaterials;
-
- // GEOMETRY shape properties:
-
- // Draw mode, point sprites and textures.
- // Stroke weight is inherited from PShape.
- protected int glMode;
- protected boolean pointSprites;
- protected PImage[] textures;
- protected float maxSpriteSize = PGraphicsAndroid3D.maxPointSize;
- // Coefficients for point sprite distance attenuation function.
- // These default values correspond to the constant sprite size.
- protected float spriteDistAtt[] = { 1.0f, 0.0f, 0.0f };
- // Used in the drawGeometry() method.
- protected PTexture[] renderTextures;
-
- // GROUP and GEOMETRY properties:
-
- // The root group shape.
- protected PShape3D root;
-
- // Element type, vertex indices and texture units being currently updated.
- protected int updateElement;
- protected int updateTexunit;
- protected int firstUpdateIdx;
- protected int lastUpdateIdx;
-
- // first and last vertex in the shape. For the root group shape, these are 0 and
- // vertexCount - 1.
- protected int firstVertex;
- protected int lastVertex;
-
- protected int firstIndex;
- protected int lastIndex;
-
- // Bounding box (defined for all shapes, group and geometry):
- public float xmin, xmax;
- public float ymin, ymax;
- public float zmin, zmax;
-
- ////////////////////////////////////////////////////////////
-
- // Constructors.
-
- public PShape3D() {
- this.papplet = null;
- a3d = null;
-
- glVertexBufferID = 0;
- glColorBufferID = 0;
- glNormalBufferID = 0;
- glTexCoordBufferID = null;
- }
-
- public PShape3D(PApplet parent) {
- this();
- this.papplet = parent;
- a3d = (PGraphicsAndroid3D)parent.g;
- this.family = PShape.GROUP;
- this.name = "root";
- this.root = this;
- }
-
- public PShape3D(PApplet parent, int numVert) {
- this(parent, numVert, new Parameters());
- }
-
- public PShape3D(PApplet parent, String filename, Parameters params) {
- this.papplet = parent;
- a3d = (PGraphicsAndroid3D)parent.g;
-
- this.family = PShape.GROUP;
- this.name = "root";
- this.root = this;
- glVertexBufferID = 0;
- glColorBufferID = 0;
- glNormalBufferID = 0;
- glTexCoordBufferID = null;
-
- updateElement = -1;
-
- initShapeOBJ(filename, params);
- }
-
-
- public PShape3D(PApplet parent, int size, Parameters params) {
- this.papplet = parent;
- a3d = (PGraphicsAndroid3D)parent.g;
-
- this.family = PShape.GROUP;
- this.name = "root";
- this.root = this;
- glVertexBufferID = 0;
- glColorBufferID = 0;
- glNormalBufferID = 0;
- glTexCoordBufferID = null;
-
- updateElement = -1;
-
- initShape(size, params);
- }
-
-
- public void delete() {
- if (root != this) return; // Can be done only from the root shape.
- release();
- a3d.unregisterPGLObject(this);
-
- deleteVertexBuffer();
- deleteColorBuffer();
- deleteTexCoordBuffer();
- deleteNormalBuffer();
- deleteIndexBuffer();
- }
-
- public void backup() {
-
- }
-
- public void restore() {
- if (root != this) return; // Can be done only from the root shape.
-
- // Loading/updating each piece of data so the arrays on the CPU-side
- // are copied to the VBOs on the GPU.
-
- loadVertices();
- updateVertices();
-
- loadColors();
- updateColors();
-
- loadNormals();
- updateNormals();
-
- for (int i = 0; i < numTexBuffers; i++) {
- loadTexcoords(i);
- updateTexcoords();
- }
- }
-
- ////////////////////////////////////////////////////////////
-
- // SHAPE RECORDING HACK
-
- public void beginRecord() {
- a3d.beginRecord(this);
- }
-
- public void endRecord() {
- a3d.endRecord();
- }
-
- public void beginShape(int kind) {
- a3d.beginShape(kind);
- }
-
- public void endShape() {
- a3d.endShape();
- }
-
- public void endShape(int mode) {
- a3d.endShape(mode);
- }
-
- public void shapeName(String name) {
- a3d.shapeName(name);
- }
-
- public void mergeShapes(boolean val) {
- a3d.mergeShapes(val);
- }
-
- public void vertex(float x, float y, float u, float v) {
- a3d.vertex(x, y, u, v);
- }
-
- public void vertex(float x, float y, float z, float u, float v) {
- a3d.vertex(x, y, z, u, v);
- }
-
- public void vertex(float... values) {
- a3d.vertex(values);
- }
-
- public void normal(float nx, float ny, float nz) {
- a3d.normal(nx, ny, nz);
- }
-
- public void texture(PImage image) {
- a3d.texture(image);
- }
-
- public void texture(PImage... images) {
- a3d.texture(images);
- }
-
- public void sphereDetail(int res) {
- a3d.sphereDetail(res);
- }
-
- public void sphereDetail(int ures, int vres) {
- a3d.sphereDetail(ures, vres);
- }
-
- public void sphere(float r) {
- a3d.sphere(r);
- }
-
- public void box(float size) {
- a3d.box(size);
- }
-
- public void box(float w, float h, float d) {
- a3d.box(w, h, d);
- }
-
- public void noFill() {
- a3d.saveDrawingState();
- a3d.noFill();
- a3d.restoreDrawingState();
- }
-
- public void fill(int rgb) {
- a3d.saveDrawingState();
- a3d.fill(rgb);
- a3d.restoreDrawingState();
- }
-
- public void fill(int rgb, float alpha) {
- a3d.saveDrawingState();
- a3d.fill(rgb, alpha);
- a3d.restoreDrawingState();
- }
-
- public void fill(float gray) {
- a3d.saveDrawingState();
- a3d.fill(gray);
- a3d.restoreDrawingState();
- }
-
- public void fill(float gray, float alpha) {
- a3d.saveDrawingState();
- a3d.fill(gray, alpha);
- a3d.restoreDrawingState();
- }
-
- public void fill(float x, float y, float z) {
- a3d.saveDrawingState();
- a3d.fill(x, y, z);
- a3d.restoreDrawingState();
- }
-
- public void fill(float x, float y, float z, float a) {
- a3d.saveDrawingState();
- a3d.fill(x, y, z, a);
- a3d.restoreDrawingState();
- }
-
- public void noStroke() {
- a3d.saveDrawingState();
- a3d.noStroke();
- a3d.restoreDrawingState();
- }
-
- public void stroke(int rgb) {
- a3d.saveDrawingState();
- a3d.stroke(rgb);
- a3d.restoreDrawingState();
- }
-
- public void stroke(int rgb, float alpha) {
- a3d.saveDrawingState();
- a3d.stroke(rgb, alpha);
- a3d.restoreDrawingState();
- }
-
- public void stroke(float gray) {
- a3d.saveDrawingState();
- a3d.stroke(gray);
- a3d.restoreDrawingState();
- }
-
- public void stroke(float gray, float alpha) {
- a3d.saveDrawingState();
- a3d.stroke(gray, alpha);
- a3d.restoreDrawingState();
- }
-
- public void stroke(float x, float y, float z) {
- a3d.saveDrawingState();
- a3d.stroke(x, y, z);
- a3d.restoreDrawingState();
- }
-
- public void stroke(float x, float y, float z, float a) {
- a3d.saveDrawingState();
- a3d.stroke(x, y, z, a);
- a3d.restoreDrawingState();
- }
-
- ////////////////////////////////////////////////////////////
-
- // load/update/set/get methods
-
-
- public void loadVertices() {
- loadVertices(firstVertex, lastVertex);
- }
-
-
- public void loadVertices(int first, int last) {
- if (last < first || first < firstVertex || lastVertex < last) {
- PGraphics.showWarning("PShape3D: wrong vertex index");
- updateElement = -1;
- return;
- }
-
- if (updateElement != -1) {
- PGraphics.showWarning("PShape3D: can load only one type of data at the time");
- return;
- }
-
- updateElement = VERTICES;
- firstUpdateIdx = first;
- lastUpdateIdx = last;
-
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glVertexBufferID);
- }
-
-
- public void updateVertices() {
- if (updateElement == VERTICES) {
- int offset = firstUpdateIdx * 3;
- int size = (lastUpdateIdx - firstUpdateIdx + 1) * 3;
-
- if (root.autoBounds) {
- updateBounds(firstUpdateIdx, lastUpdateIdx);
- }
-
- vertexBuffer.position(0);
- vertexBuffer.put(vertices, offset, size);
- vertexBuffer.flip();
-
- getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
- size * PGraphicsAndroid3D.SIZEOF_FLOAT, vertexBuffer);
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
-
- updateElement = -1;
- } else {
- PGraphics.showWarning("PShape3D: need to call loadVertices() first");
- }
- }
-
-
- public void loadColors() {
- loadColors(firstVertex, lastVertex);
- }
-
-
- public void loadColors(int first, int last) {
- if (last < first || first < firstVertex || lastVertex < last) {
- PGraphics.showWarning("PShape3D: wrong vertex index");
- updateElement = -1;
- return;
- }
-
- if (updateElement != -1) {
- PGraphics.showWarning("PShape3D: can load only one type of data at the time");
- return;
- }
-
- updateElement = COLORS;
- firstUpdateIdx = first;
- lastUpdateIdx = last;
-
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glColorBufferID);
- }
-
-
- public void updateColors() {
- if (updateElement == COLORS) {
- int offset = firstUpdateIdx * 4;
- int size = (lastUpdateIdx - firstUpdateIdx + 1) * 4;
-
- colorBuffer.position(0);
- colorBuffer.put(colors, offset, size);
- colorBuffer.flip();
-
- getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
- size * PGraphicsAndroid3D.SIZEOF_FLOAT, colorBuffer);
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
-
- updateElement = -1;
- } else {
- PGraphics.showWarning("PShape3D: need to call loadColors() first");
- }
- }
-
-
- public void loadNormals() {
- loadNormals(firstVertex, lastVertex);
- }
-
-
- public void loadNormals(int first, int last) {
- if (last < first || first < firstVertex || lastVertex < last) {
- PGraphics.showWarning("PShape3D: wrong vertex index");
- updateElement = -1;
- return;
- }
-
- if (updateElement != -1) {
- PGraphics.showWarning("PShape3D: can load only one type of data at the time");
- return;
- }
-
- updateElement = NORMALS;
- firstUpdateIdx = first;
- lastUpdateIdx = last;
-
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glNormalBufferID);
- }
-
-
- public void updateNormals() {
- if (updateElement == NORMALS) {
- int offset = firstUpdateIdx * 3;
- int size = (lastUpdateIdx - firstUpdateIdx + 1) * 3;
-
- normalBuffer.position(0);
- normalBuffer.put(normals, offset, size);
- normalBuffer.flip();
-
- getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
- size * PGraphicsAndroid3D.SIZEOF_FLOAT, normalBuffer);
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
-
- updateElement = -1;
- } else {
- PGraphics.showWarning("PShape3D: need to call loadNormals() first");
- }
- }
-
-
- public void loadTexcoords() {
- loadTexcoords(0);
- }
-
-
- public void loadTexcoords(int unit) {
- loadTexcoords(unit, firstVertex, lastVertex);
- }
-
-
- protected void loadTexcoords(int unit, int first, int last) {
- if (last < first || first < firstVertex || lastVertex < last) {
- PGraphics.showWarning("PShape3D: wrong vertex index");
- updateElement = -1;
- return;
- }
-
- if (updateElement != -1) {
- PGraphics.showWarning("PShape3D: can load only one type of data at the time");
- return;
- }
-
- if (PGraphicsAndroid3D.maxTextureUnits <= unit) {
- PGraphics.showWarning("PShape3D: wrong texture unit");
- return;
- }
-
- updateElement = TEXCOORDS;
- firstUpdateIdx = first;
- lastUpdateIdx = last;
- updateTexunit = unit;
-
- if (numTexBuffers <= unit) {
- addTexBuffers(unit - numTexBuffers + 1);
- }
-
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, glTexCoordBufferID[unit]);
-
- texcoords = allTexcoords[unit];
- }
-
-
- public void updateTexcoords() {
- if (updateElement == TEXCOORDS) {
- int offset = firstUpdateIdx * 2;
- int size = (lastUpdateIdx - firstUpdateIdx + 1) * 2;
-
- convertTexcoords();
-
- texCoordBuffer.position(0);
- texCoordBuffer.put(convTexcoords, offset, size);
- texCoordBuffer.flip();
-
- getGl().glBufferSubData(GL11.GL_ARRAY_BUFFER, offset * PGraphicsAndroid3D.SIZEOF_FLOAT,
- size * PGraphicsAndroid3D.SIZEOF_FLOAT, texCoordBuffer);
- getGl().glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
-
- texCoordSet[updateTexunit] = true;
-
- updateElement = -1;
- } else {
- PGraphics.showWarning("PShape3D: need to call loadTexcoords() first");
- }
- }
-
-
- public float[] get(int idx) {
- float[] v = null;
- if (updateElement == VERTICES) {
- v = new float[3];
- PApplet.arrayCopy(vertices, 3 * idx, v, 0, 3);
- } else if (updateElement == COLORS) {
- v = new float[4];
- PApplet.arrayCopy(colors, 4 * idx, v, 0, 4);
- } else if (updateElement == NORMALS) {
- v = new float[3];
- PApplet.arrayCopy(normals, 3 * idx, v, 0, 3);
- } else if (updateElement == TEXCOORDS) {
- v = new float[2];
- PApplet.arrayCopy(texcoords, 2 * idx, v, 0, 2);
- }
- return v;
- }
-
-
- public void set(int idx, float[] v) {
- if (updateElement == VERTICES) {
- PApplet.arrayCopy(v, 0, vertices, 3 * idx, 3);
- } else if (updateElement == COLORS) {
- PApplet.arrayCopy(v, 0, colors, 4 * idx, 4);
- } else if (updateElement == NORMALS) {
- PApplet.arrayCopy(v, 0, normals, 3 * idx, 3);
- } else if (updateElement == TEXCOORDS) {
- PApplet.arrayCopy(v, 0, texcoords, 2 * idx, 2);
- }
- }
-
-
- public void set(int idx, int c) {
- set(idx, rgba(c));
- }
-
-
- public void set(int idx, float x, float y) {
- if (updateElement == VERTICES) {
- set(idx, new float[] {x, y, 0});
- } else if (updateElement == TEXCOORDS) {
- set(idx, new float[] {x, y});
- }
- }
-
-
- public void set(int idx, float x, float y, float z) {
- if (updateElement == VERTICES) {
- set(idx, new float[] {x, y, z});
- } else if (updateElement == NORMALS) {
- set(idx, new float[] {x, y, z});
- } else if (updateElement == COLORS) {
- set(idx, new float[] {x, y, z, 1});
- }
- }
-
-
- public void set(int idx, float x, float y, float z, float w) {
- if (updateElement == COLORS) {
- set(idx, new float[] {x, y, z, w});
- }
- }
-
-
- static public int color(float[] rgba) {
- int r = (int)(rgba[0] * 255);
- int g = (int)(rgba[1] * 255);
- int b = (int)(rgba[2] * 255);
- int a = (int)(rgba[3] * 255);
-
- return a << 24 | r << 16 | g << 8 | b;
- }
-
-
- static public float[] rgba(int c) {
- int a = (c >> 24) & 0xFF;
- int r = (c >> 16) & 0xFF;
- int g = (c >> 8) & 0xFF;
- int b = (c >> 0) & 0xFF;
-
- float[] res = new float[4];
- res[0] = r / 255.0f;
- res[1] = g / 255.0f;
- res[2] = b / 255.0f;
- res[3] = a / 255.0f;
-
- return res;
- }
-
- public void autoBounds(boolean value) {
- root.autoBounds = value;
- }
-
- public void updateBounds() {
- updateBounds(firstVertex, lastVertex);
- }
-
- protected void updateBounds(int first, int last) {
- if (first <= firstVertex && lastVertex <= last) {
- resetBounds();
- }
-
- if (family == GROUP) {
- if (root == this && childCount == 0) {
- // This might happen: the vertices has been set
- // first but children still not initialized. So we
- // need to calculate the bounding box directly:
- for (int i = firstVertex; i <= lastVertex; i++) {
- updateBounds(vertices[3 * i + 0], vertices[3 * i + 1], vertices[3 * i + 2]);
- }
- } else {
- for (int i = 0; i < childCount; i++) {
- PShape3D child = (PShape3D)children[i];
- child.updateBounds(first, last);
- xmin = PApplet.min(xmin, child.xmin);
- xmax = PApplet.max(xmax, child.xmax);
-
- ymin = PApplet.min(ymin, child.ymin);
- ymax = PApplet.max(ymax, child.ymax);
-
- zmin = PApplet.min(zmin, child.zmin);
- zmax = PApplet.max(zmax, child.zmax);
-
- width = xmax - xmin;
- height = ymax - ymin;
- depth = zmax - zmin;
- }
- }
- } else {
- // TODO: extract minimum and maximum values using some sorting algorithm (maybe).
- int n0 = PApplet.max(first, firstVertex);
- int n1 = PApplet.min(last, lastVertex);
-
- for (int i = n0; i <= n1; i++) {
- updateBounds(vertices[3 * i + 0], vertices[3 * i + 1], vertices[3 * i + 2]);
- }
- }
- }
-
- protected void resetBounds() {
- if (family == GROUP) {
- for (int i = 0; i < childCount; i++) {
- ((PShape3D)children[i]).resetBounds();
- }
- }
- width = height = depth = 0;
- xmin = ymin = zmin = 10000;
- xmax = ymax = zmax = -10000;
- }
-
- protected void updateBounds(float x, float y, float z) {
- xmin = PApplet.min(xmin, x);
- xmax = PApplet.max(xmax, x);
-
- ymin = PApplet.min(ymin, y);
- ymax = PApplet.max(ymax, y);
-
- zmin = PApplet.min(zmin, z);
- zmax = PApplet.max(zmax, z);
-
- width = xmax - xmin;
- height = ymax - ymin;
- depth = zmax - zmin;
- }
-
-
- // Convert texture coordinates given by the user to values required by
- // the GPU (non-necessarily normalized because of texture size being smaller
- // than image size, for instance).
- protected void convertTexcoords() {
- PTexture tex;
- float u, v;
-
- PTexture tex0 = null;
- float uscale = 1.0f;
- float vscale = 1.0f;
- float cx = 0.0f;
- float sx = +1.0f;
- float cy = 0.0f;
- float sy = +1.0f;
- for (int i = firstUpdateIdx; i <= lastUpdateIdx; i++) {
- if (vertexChild[i] != null && vertexChild[i].textures[updateTexunit] != null) {
- PImage img = vertexChild[i].textures[updateTexunit];
- tex = a3d.getTexture(img);
-
- if (tex != tex0) {
- uscale = 1.0f;
- vscale = 1.0f;
- cx = 0.0f;
- sx = +1.0f;
- cy = 0.0f;
- sy = +1.0f;
-
- if (tex != null) {
- if (tex.isFlippedX()) {
- cx = 1.0f;
- sx = -1.0f;
- }
-
- if (tex.isFlippedY()) {
- cy = 1.0f;
- sy = -1.0f;
- }
-
- uscale *= tex.getMaxTexCoordU();
- vscale *= tex.getMaxTexCoordV();
- }
- tex0 = tex;
- }
-
- u = texcoords[2 * i + 0];
- v = texcoords[2 * i + 1];
-
- u = (cx + sx * u) * uscale;
- v = (cy + sy * v) * vscale;
-
- convTexcoords[2 * i + 0] = u;
- convTexcoords[2 * i + 1] = v;
- }
- }
- }
-
- ////////////////////////////////////////////////////////////
-
- // Child shapes
-
-
- static public PShape createChild(int n0, int n1) {
- return createChild(null, n0, n1, POINTS, 0, null);
- }
-
-
- static public PShape createChild(String name, int n0, int n1) {
- return createChild(name, n0, n1, POINTS, 0, null);
- }
-
-
- static public PShape createChild(String name, int n0, int n1, int mode) {
- return createChild(name, n0, n1, mode, 0, null);
- }
-
-
- static public PShape createChild(String name, int n0, int n1, int mode, float weight) {
- return createChild(name, n0, n1, mode, weight, null);
- }
-
- static public PShape createChild(String name, int n0, int n1, int i0, int i1, int mode, float weight, PImage[] tex) {
- PShape3D child = (PShape3D)createChild(name, n0, n1, mode, weight, tex);
- child.firstIndex = i0;
- child.lastIndex = i1;
- return child;
- }
-
- static public PShape createChild(String name, int n0, int n1, int mode, float weight, PImage[] tex) {
- PShape3D child = new PShape3D();
- child.family = PShape.GEOMETRY;
- child.name = name;
- child.firstVertex = n0;
- child.lastVertex = n1;
- child.setDrawModeImpl(mode);
- child.strokeWeight = weight;
- child.textures = new PImage[PGraphicsAndroid3D.MAX_TEXTURES];
- child.renderTextures = new PTexture[PGraphicsAndroid3D.MAX_TEXTURES];
-
- java.util.Arrays.fill(child.textures, null);
- if (tex != null) {
- int n = PApplet.min(tex.length, child.textures.length);
- PApplet.arrayCopy(tex, 0, child.textures, 0, n);
- }
- return child;
- }
-
-
- public void addChild(String name, int n0, int n1) {
- PShape child = createChild(name, n0, n1, getDrawModeImpl());
- addChild(child);
- }
-
-
- public void addChild(String name, int n0, int n1, int mode) {
- PShape child = createChild(name, n0, n1, mode);
- addChild(child);
- }
-
-
- public void addChild(String name, int n0, int n1, int mode, float weight) {
- PShape child = createChild(name, n0, n1, mode, weight);
- addChild(child);
- }
-
-
- public void addChild(String name, int n0, int n1, int mode, float weight, PImage[] tex) {
- PShape child = createChild(name, n0, n1, mode, weight, tex);
- addChild(child);
- }
-
-
- public void addChild(PShape who) {
- addChildImpl(who, true);
- }
-
-
- protected void addChildImpl(PShape who, boolean newShape) {
- if (family == GROUP) {
- super.addChild(who);
-
- if (newShape) {
- PShape3D who3d = (PShape3D)who;
- who3d.papplet = papplet;
- who3d.a3d = a3d;
- who3d.root = root;
-
- // So we can use the load/update methods in the child geometries.
- who3d.numTexBuffers = root.numTexBuffers;
-
- who3d.glVertexBufferID = root.glVertexBufferID;
- who3d.glColorBufferID = root.glColorBufferID;
- who3d.glNormalBufferID = root.glNormalBufferID;
- who3d.glTexCoordBufferID = root.glTexCoordBufferID;
- who3d.glIndexBufferID = root.glIndexBufferID;
-
- who3d.vertexBuffer = root.vertexBuffer;
- who3d.colorBuffer = root.colorBuffer;
- who3d.normalBuffer = root.normalBuffer;
- who3d.texCoordBuffer = root.texCoordBuffer;
-
- who3d.vertices = root.vertices;
- who3d.colors = root.colors;
- who3d.normals = root.normals;
- who3d.texcoords = root.texcoords;
-
- who3d.convTexcoords = root.convTexcoords;
- who3d.allTexcoords = root.allTexcoords;
- who3d.vertexChild = root.vertexChild;
- who3d.texCoordSet = root.texCoordSet;
-
- // In case the style was disabled from the root.
- who3d.style = root.style;
-
- // Updating vertex information.
- for (int n = who3d.firstVertex; n <= who3d.lastVertex; n++) {
- who3d.vertexChild[n] = who3d;
- }
-
- // If this new child shape has textures, then we should update the texture coordinates
- // for the vertices involved. All we need to do is to call loadTexcoords and updateTexcoords
- // so the current texture coordinates are converted into values that take into account
- // the texture flipping, max UV ranges, etc.
- for (int i = 0; i < who3d.textures.length; i++) {
- if (who3d.textures[i] != null && who3d.texCoordSet[i]) {
- who3d.loadTexcoords(i);
- who3d.updateTexcoords();
- }
- }
- }
- } else {
- PGraphics.showWarning("PShape3D: Child shapes can only be added to a group shape.");
- }
- }
-
- /**
- * Add a shape to the name lookup table.
- */
- public void addName(String nom, PShape shape) {
- if (nameTable == null) {
- nameTable = new HashMap<String,PShape>();
- }
- nameTable.put(nom, shape);
- }
-
- protected void addDefaultChild() {
- PShape child = createChild("geometry", 0, vertexCount - 1, getDrawModeImpl(), 0, null);
- addChild(child);
- }
-
-
- public PShape groupChildren(int cidx0, int cidx1, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
- return groupChildren(new int[] {cidx0, cidx1}, gname);
- }
-
-
- public PShape groupChildren(int cidx0, int cidx1, int cidx2, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
- return groupChildren(new int[] {cidx0, cidx1, cidx2}, gname);
- }
-
-
- public PShape groupChildren(int[] cidxs, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
- PShape[] temp = new PShape[cidxs.length];
-
- int nsel = 0;
- for (int i = 0; i < cidxs.length; i++) {
- PShape child = getChild(cidxs[i]);
- if (child != null) {
- temp[nsel] = child;
- nsel++;
- }
- }
-
- PShape[] schildren = new PShape[nsel];
- PApplet.arrayCopy(temp, schildren, nsel);
-
- return groupChildren(schildren, gname);
- }
-
-
- public PShape groupChildren(String cname0, String cname1, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
- return groupChildren(new String[] {cname0, cname1}, gname);
- }
-
-
- public PShape groupChildren(String cname0, String cname1, String cname2, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
- return groupChildren(new String[] {cname0, cname1, cname2}, gname);
- }
-
-
- public PShape groupChildren(String[] cnames, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
-
- PShape[] temp = new PShape[cnames.length];
-
- int nsel = 0;
- for (int i = 0; i < cnames.length; i++) {
- PShape child = getChild(cnames[i]);
- if (child != null) {
- temp[nsel] = child;
- nsel++;
- }
- }
-
- PShape[] schildren = new PShape[nsel];
- PApplet.arrayCopy(temp, schildren, nsel);
-
- return groupChildren(schildren, gname);
- }
-
-
- public PShape groupChildren(PShape[] gchildren, String gname) {
- if (family != GROUP) return null; // Can be done only in a GROUP shape.
-
- // Creating the new group containing the children.
- PShape3D group = new PShape3D();
- group.family = PShape.GROUP;
- group.name = gname;
- group.papplet = papplet;
- group.a3d = a3d;
- group.root = root;
-
- PShape child, p;
- int idx;
-
- // Inserting the new group at the position of the first
- // child shape in the group (in its original parent).
- child = gchildren[0];
- p = child.parent;
- if (p != null) {
- idx = p.getChildIndex(child);
- if (idx < 0) idx = 0;
- } else {
- p = this;
- idx = 0;
- }
- p.addChild(group, idx);
-
- // Removing the children in the new group from their
- // respective parents.
- for (int i = 0; i < gchildren.length; i++) {
- child = gchildren[i];
- p = child.parent;
- if (p != null) {
- idx = p.getChildIndex(child);
- if (-1 < idx) {
- p.removeChild(idx);
- }
- }
- }
-
- group.firstVertex = root.vertexCount;
- group.lastVertex = 0;
- for (int i = 0; i < gchildren.length; i++) {
- group.firstVertex = PApplet.min(group.firstVertex, ((PShape3D)gchildren[i]).firstVertex);
- group.lastVertex = PApplet.max(group.lastVertex, ((PShape3D)gchildren[i]).lastVertex);
- }
-
- // Adding the children shapes to the new group.
- for (int i = 0; i < gchildren.length; i++) {
- group.addChildImpl(gchildren[i], false);
- }
-
- return group;
- }
-
-
- public int getFirstVertex() {
- return firstVertex;
- }
-
-
- public int getFirstVertex(int idx) {
- if (0 <= idx && idx < childCount) {
- return ((PShape3D)children[idx]).getFirstVertex();
- }
- return -1;
- }
-
-
- public void setFirstVertex(int n0) {
- firstVertex = n0;
- }
-
-
- public void setFirstVertex(int idx, int n0) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setFirstVertex(n0);
- }
- }
-
-
- public int getLastVertex() {
- return lastVertex;
- }
-
-
- public int getLastVertex(int idx) {
- if (0 <= idx && idx < childCount) {
- return ((PShape3D)children[idx]).getLastVertex();
- }
- return -1;
- }
-
-
- public void setLastVertex(int n1) {
- lastVertex = n1;
- }
-
-
- public void setLastVertex(int idx, int n1) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setLastVertex(n1);
- }
- }
-
-
- public void setDrawMode(int mode) {
- if (family == GROUP) {
- init();
- setDrawModeImpl(mode);
- for (int n = 0; n < childCount; n++) {
- setDrawMode(n, mode);
- }
- } else {
- setDrawModeImpl(mode);
- }
- }
-
-
- public void setDrawMode(int idx, int mode) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setDrawMode(mode);
- }
- }
-
-
- protected void setDrawModeImpl(int mode) {
- pointSprites = false;
- if (mode == POINTS) glMode = GL11.GL_POINTS;
- else if (mode == POINT_SPRITES) {
- glMode = GL11.GL_POINTS;
- pointSprites = true;
- }
- else if (mode == LINES) glMode = GL11.GL_LINES;
- else if (mode == LINE_STRIP) glMode = GL11.GL_LINE_STRIP;
- else if (mode == LINE_LOOP) glMode = GL11.GL_LINE_LOOP;
- else if (mode == TRIANGLES) glMode = GL11.GL_TRIANGLES;
- else if (mode == TRIANGLE_FAN) glMode = GL11.GL_TRIANGLE_FAN;
- else if (mode == TRIANGLE_STRIP) glMode = GL11.GL_TRIANGLE_STRIP;
- else {
- throw new RuntimeException("PShape3D: Unknown draw mode");
- }
- }
-
-
- protected boolean isTexturable() {
- return glMode == GL11.GL_TRIANGLES ||
- glMode == GL11.GL_TRIANGLE_FAN ||
- glMode == GL11.GL_TRIANGLE_STRIP ||
- pointSprites;
- }
-
-
- public int getDrawMode() {
- if (family == GROUP) {
- init();
- return getDrawMode(0);
- } else {
- return getDrawModeImpl();
- }
- }
-
-
- public int getDrawMode(int idx) {
- if (0 <= idx && idx < childCount) {
- return ((PShape3D)children[idx]).getDrawMode();
- }
- return -1;
- }
-
-
- protected int getDrawModeImpl() {
- if (glMode == GL11.GL_POINTS) {
- if (pointSprites) return POINT_SPRITES;
- else return POINTS;
- } else if (glMode == GL11.GL_LINES) return LINES;
- else if (glMode == GL11.GL_LINE_STRIP) return LINE_STRIP;
- else if (glMode == GL11.GL_LINE_LOOP) return LINE_LOOP;
- else if (glMode == GL11.GL_TRIANGLES) return TRIANGLES;
- else if (glMode == GL11.GL_TRIANGLE_FAN) return TRIANGLE_FAN;
- else if (glMode == GL11.GL_TRIANGLE_STRIP) return TRIANGLE_STRIP;
- else return -1;
- }
-
-
- public void setTexture(PImage tex) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setTexture(i, tex);
- }
- } else {
- setTextureImpl(tex, 0);
- }
- }
-
-
- public void setTexture(PImage tex0, PImage tex1) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setTexture(i, tex0, tex1);
- }
- } else {
- setTextureImpl(tex0, 0);
- setTextureImpl(tex1, 1);
- }
- }
-
-
- public void setTexture(PImage tex0, PImage tex1, PImage tex2) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setTexture(i, tex0, tex1, tex2);
- }
- } else {
- setTextureImpl(tex0, 0);
- setTextureImpl(tex1, 1);
- setTextureImpl(tex2, 2);
- }
- }
-
-
- public void setTexture(PImage tex0, PImage tex1, PImage tex2, PImage tex3) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setTexture(i, tex0, tex1, tex2, tex3);
- }
- } else {
- setTextureImpl(tex0, 0);
- setTextureImpl(tex1, 1);
- setTextureImpl(tex2, 2);
- setTextureImpl(tex3, 3);
- }
- }
-
-
- public void setTexture(PImage[] tex) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setTexture(i, tex);
- }
- } else {
- for (int i = 0; i < tex.length; i++) {
- setTextureImpl(tex[i], i);
- }
- }
- }
-
-
- public void setTexture(int idx, PImage tex) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setTexture(tex);
- }
- }
-
-
- public void setTexture(int idx, PImage tex0, PImage tex1) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setTexture(tex0, tex1);
- }
- }
-
-
- public void setTexture(int idx, PImage tex0, PImage tex1, PImage tex2) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setTexture(tex0, tex1, tex2);
- }
- }
-
-
- public void setTexture(int idx, PImage tex0, PImage tex1, PImage tex2, PImage tex3) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setTexture(tex0, tex1, tex2, tex3);
- }
- }
-
-
- public void setTexture(int idx, PImage[] tex) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setTexture(tex);
- }
- }
-
-
- protected void setTextureImpl(PImage tex, int unit) {
- if (unit < 0 || PGraphicsAndroid3D.maxTextureUnits <= unit) {
- System.err.println("PShape3D: Wrong texture unit.");
- return;
- }
-
- if (numTexBuffers <= unit) {
- root.addTexBuffers(unit - numTexBuffers + 1);
- }
-
- if (tex == null) {
- throw new RuntimeException("PShape3D: trying to set null texture.");
- }
-
- if (texCoordSet[unit] && isTexturable()) {
- // Ok, setting a new texture, when texture coordinates have already been set.
- // What is the problem? the new texture might have different max UV coords,
- // flippedX/Y values, so the texture coordinates need to be updated accordingly...
-
- // The way to do it is just load the texcoords array (in the parent)...
- loadTexcoords(unit);
- // ... then replacing the old texture with the new and...
- textures[unit] = tex;
- // ...,finally, updating the texture coordinates, step in which the texcoords
- // array is converted, this time using the new texture.
- updateTexcoords();
- } else {
- textures[unit] = tex;
- }
- }
-
-
- public PImage[] getTexture() {
- if (family == GROUP) {
- init();
- return getTexture(0);
- } else {
- return textures;
- }
- }
-
-
- public PImage[] getTexture(int idx) {
- if (0 <= idx && idx < childCount) {
- return ((PShape3D)children[idx]).getTexture();
- }
- return null;
- }
-
-
- public float getStrokeWeight() {
- if (family == GROUP) {
- init();
- return getStrokeWeight(0);
- } else {
- return strokeWeight;
- }
- }
-
-
- public float getStrokeWeight(int idx) {
- if (0 <= idx && idx < childCount) {
- return ((PShape3D)children[idx]).getStrokeWeight();
- }
- return 0;
- }
-
-
- public void setStrokeWeight(float sw) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setStrokeWeight(i, sw);
- }
- } else {
- strokeWeight = sw;
- }
- }
-
-
- public void setStrokeWeight(int idx, float sw) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setStrokeWeight(sw);
- }
- }
-
-
- public float getMaxSpriteSize() {
- if (family == GROUP) {
- init();
- return getMaxSpriteSize(0);
- } else {
- return maxSpriteSize;
- }
- }
-
-
- public float getMaxSpriteSize(int idx) {
- if (0 <= idx && idx < childCount) {
- return ((PShape3D)children[idx]).getMaxSpriteSize();
- }
- return 0;
- }
-
-
- public void setMaxSpriteSize(float s) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setMaxSpriteSize(i, s);
- }
- } else {
- setMaxSpriteSizeImpl(s);
- }
- }
-
-
- public void setMaxSpriteSize(int idx, float s) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setMaxSpriteSize(s);
- }
- }
-
-
- protected void setMaxSpriteSizeImpl(float s) {
- maxSpriteSize = PApplet.min(s, PGraphicsAndroid3D.maxPointSize);
- }
-
-
- public void setSpriteSize(float s) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setSpriteSize(i, s);
- }
- } else {
- setSpriteSizeImpl(s);
- }
- }
-
-
- public void setSpriteSize(float s, float d, int mode) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setSpriteSize(i, s, d, mode);
- }
- } else {
- setSpriteSizeImpl(s, d, mode);
- }
- }
-
-
- public void setSpriteSize(int idx, float s) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setSpriteSize(s);
- }
- }
-
-
- public void setSpriteSize(int idx, float s, float d, int mode) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setSpriteSize(s, d, mode);
- }
- }
-
-
- // Sets the coefficient of the distance attenuation function so that the
- // size of the sprite is exactly s when its distance from the camera is d.
- protected void setSpriteSizeImpl(float s, float d, int mode) {
- float s0 = maxSpriteSize;
- if (mode == LINEAR) {
- spriteDistAtt[1] = (s0 - s) / (d * s);
- spriteDistAtt[2] = 0;
- } else if (mode == QUADRATIC) {
- spriteDistAtt[1] = 0;
- spriteDistAtt[2] = (s0 - s) / (d * d * s);
- } else {
- PGraphics.showWarning("Invalid point sprite mode");
- }
- }
-
-
- // Sets constant sprite size equal to s.
- protected void setSpriteSizeImpl(float s) {
- setMaxSpriteSizeImpl(s);
- spriteDistAtt[1] = 0;
- spriteDistAtt[2] = 0;
- }
-
-
- public void setColor(int c) {
- setColor(rgba(c));
- }
-
-
- public void setColor(float r, float g, float b, float a) {
- setColor(new float[] {r, g, b, a});
- }
-
-
- public void setColor(float[] c) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setColor(i, c);
- }
- } else {
- setColorImpl(c);
- }
- }
-
-
- public void setColor(int idx, int c) {
- setColor(idx, rgba(c));
- }
-
-
- public void setColor(int idx, float r, float g, float b, float a) {
- setColor(idx, new float[] {r, g, b, a});
- }
-
-
- public void setColor(int idx, float[] c) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setColor(c);
- }
- }
-
-
- protected void setColorImpl(float[] c) {
- PShape3D p = (PShape3D)root;
- p.loadColors();
- for (int i = firstVertex; i <= lastVertex; i++) {
- p.set(i, c);
- }
- p.updateColors();
- }
-
-
- public void setNormal(float nx, float ny, float nz) {
- setNormal(new float[] {nx, ny, nz});
- }
-
-
- public void setNormal(float[] n) {
- if (family == GROUP) {
- init();
- for (int i = 0; i < childCount; i++) {
- setNormal(i, n);
- }
- } else {
- setNormalImpl(n);
- }
- }
-
-
- public void setNormal(int idx, float nx, float ny, float nz) {
- setNormal(idx, new float[] {nx, ny, nz});
- }
-
-
- public void setNormal(int idx, float[] n) {
- if (0 <= idx && idx < childCount) {
- ((PShape3D)children[idx]).setNormal(n);
- }
- }
-
-
- protected void setNormalImpl(float[] n) {
- PShape3D p = (PShape3D)root;
- p.loadNormals();
- for (int i = firstVertex; i <= lastVertex; i++) {
- p.set(i, n);
- }
- p.updateNormals();
- }
-
- // Optimizes the array list containing children shapes so that shapes with identical
- // parameters are removed. Also, making sure that the names are unique.
- protected void optimizeChildren(ArrayList<PShape3D> childList) {
- PShape3D child0, child1;
-
- // Expanding identical, contiguous shapes. Names are taken into account (two
- // shapes with different names are considered to be different, even though the
- // rest of their parameters are identical).
- child0 = (PShape3D)childList.get(0);
- for (int i = 1; i < childList.size(); i++) {
- child1 = (PShape3D)childList.get(i);
- if (child0.equalTo(child1, false)) {
- child0.lastVertex = child1.lastVertex; // Extending child0.
- child0.lastIndex = child1.lastIndex;
- // Updating the vertex data:
- for (int n = child0.firstVertex; n <= child0.lastVertex; n++) {
- vertexChild[n] = child0;
- }
- child1.firstVertex = child1.lastVertex = -1; // Marking for deletion.
- } else {
- child0 = child1;
- }
- }
-
- // Deleting superfluous shapes.
- for (int i = childList.size() - 1; i >= 0; i--) {
- if (((PShape3D)childList.get(i)).lastVertex == -1) {
- childList.remove(i);
- }
- }
-
- // Making sure the names are unique.
- for (int i = 1; i < childList.size(); i++) {
- child1 = (PShape3D)childList.get(i);
- for (int j = i - 1; j >= 0; j--) {
- child0 = (PShape3D)childList.get(j);
- if (child1.name.equals(child0.name)) {
- int pos = child0.name.indexOf(':');
- if (-1 < pos) {
- // The name of the preceding child contains the ':'
- // character so trying to use the following substring
- // as a number.
- String nstr = child0.name.substring(pos + 1);
- int n = 1;
- try {
- n = Integer.parseInt(nstr);
- } catch (NumberFormatException e) {
- child0.name += ":1";
- }
- child1.name += ":" + (n + 1);
- } else {
- child0.name += ":1";
- child1.name += ":2";
- }
- }
- }
- }
- }
-
-
- protected boolean equalTo(PShape3D child, boolean ignoreNames) {
- boolean res = family == child.family &&
- glMode == child.glMode &&
- strokeWeight == child.strokeWeight &&
- (ignoreNames || name.equals(child.name));
- if (!res) return false;
- for (int i = 0; i < textures.length; i++) {
- if (textures[i] != child.textures[i]) {
- res = false;
- }
- }
- return res;
- }
-
- ////////////////////////////////////////////////////////////
-
-
- // Some overloading of translate, rotate, scale
-
- public void resetMatrix() {
- checkMatrix(3);
- matrix.reset();
- }
-
- public void translate(float tx, float ty) {
- checkMatrix(3);
- matrix.translate(tx, ty, 0);
- }
-
- public void rotate(float angle) {
- checkMatrix(3);
- matrix.rotate(angle);
- }
-
- public void scale(float s) {
- checkMatrix(3);
- matrix.scale(s);
- }
-
- public void scale(float x, float y) {
- checkMatrix(3);
- matrix.scale(x, y);
- }
-
- public void centerAt(float cx, float cy, float cz) {
- float dx = cx - 0.5f * (xmin + xmax);
- float dy = cy - 0.5f * (ymin + ymax);
- float dz = cz - 0.5f * (zmin + zmax);
- // Centering
- loadVertices();
- for (int i = 0; i < vertexCount; i++) {
- vertices[3 * i + 0] += dx;
- vertices[3 * i + 1] += dy;
- vertices[3 * i + 2] += dz;
- }
- updateVertices();
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Bulk vertex operations.
-
- public void setVertices(ArrayList<PVector> vertexList) {
- setVertices(vertexList, 0);
- }
-
- public void setVertices(ArrayList<PVector> vertexList, int offset) {
- loadVertices();
- for (int i = firstVertex; i <= lastVertex; i++) {
- PVector v = (PVector)vertexList.get(i - firstVertex + offset);
- set(i, v.x, v.y, v.z);
- }
- updateVertices();
- }
-
- public void setColors(ArrayList<float[]> colorList) {
- setColors(colorList, 0);
- }
-
- public void setColors(ArrayList<float[]> colorList, int offset) {
- loadColors();
- for (int i = firstVertex; i <= lastVertex; i++) {
- float[] c = (float[])colorList.get(i - firstVertex + offset);
- set(i, c);
- }
- updateColors();
- }
-
-
- public void setNormals(ArrayList<PVector> normalList) {
- setNormals(normalList, 0);
- }
-
- public void setNormals(ArrayList<PVector> normalList, int offset) {
- loadNormals();
- for (int i = firstVertex; i <= lastVertex; i++) {
- PVector n = (PVector)normalList.get(i - firstVertex + offset);
- set(i, n.x, n.y, n.z);
- }
- updateNormals();
- }
-
-
- public void setTexcoor