/* * __ .__ .__ ._____. * _/ |_ _______ __|__| ____ | | |__\_ |__ ______ * \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/ * | | ( <_> > <| \ \___| |_| || \_\ \\___ \ * |__| \____/__/\_ \__|\___ >____/__||___ /____ > * \/ \/ \/ \/ * * Copyright (c) 2006-2011 Karsten Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * http://creativecommons.org/licenses/LGPL/2.1/ * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ package toxi.processing; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import processing.core.PApplet; import processing.core.PConstants; import processing.core.PGraphics; import processing.core.PImage; import toxi.color.ReadonlyTColor; import toxi.geom.AABB; import toxi.geom.AxisAlignedCylinder; import toxi.geom.Cone; import toxi.geom.Ellipse; import toxi.geom.Line2D; import toxi.geom.Line3D; import toxi.geom.LineStrip2D; import toxi.geom.LineStrip3D; import toxi.geom.Plane; import toxi.geom.Polygon2D; import toxi.geom.Ray2D; import toxi.geom.Ray3D; import toxi.geom.ReadonlyVec2D; import toxi.geom.ReadonlyVec3D; import toxi.geom.ReadonlyVec4D; import toxi.geom.Rect; import toxi.geom.Sphere; import toxi.geom.Triangle2D; import toxi.geom.Triangle3D; import toxi.geom.Vec2D; import toxi.geom.Vec3D; import toxi.geom.Vec4D; import toxi.geom.mesh.Mesh3D; /** * In addition to providing new drawing commands, this class provides wrappers * for using datatypes of the toxiclibs core package directly with Processing's * drawing commands. The class can be configured to work with any PGraphics * instance (incl. offscreen buffers) using a constructor argument or the * {@link #setGraphics(PGraphics)} method. */ public class ToxiclibsSupport { /** * */ protected static final Logger logger = Logger .getLogger(ToxiclibsSupport.class.getName()); /** * */ protected PApplet app; /** * */ protected PGraphics gfx; /** * * @param app */ public ToxiclibsSupport(PApplet app) { this(app, app.g); } /** * * @param app * @param gfx */ public ToxiclibsSupport(PApplet app, PGraphics gfx) { this.app = app; this.gfx = gfx; } /** * * @param box */ public final void box(AABB box) { mesh(box.toMesh(), false, 0); } /** * * @param box * @param smooth */ public final void box(AABB box, boolean smooth) { Mesh3D mesh = box.toMesh(); if (smooth) { mesh.computeVertexNormals(); } mesh(mesh, smooth, 0); } /** * * @param isWireframe * @param stroke * @param fill */ public final void chooseStrokeFill(boolean isWireframe, ReadonlyTColor stroke, ReadonlyTColor fill) { if (isWireframe) { gfx.noFill(); gfx.stroke(stroke.toARGB()); } else { gfx.noStroke(); gfx.fill(fill.toARGB()); } } /** * * @param p * @param radius */ public final void circle(Vec2D p, float radius) { gfx.ellipse(p.x, p.y, radius, radius); } /** * * @param cone */ public final void cone(Cone cone) { mesh(cone.toMesh(null, 6, 0, true, true), false, 0); } /** * * @param cone * @param topClosed * @param bottomClosed */ public final void cone(Cone cone, boolean topClosed, boolean bottomClosed) { mesh(cone.toMesh(null, 6, 0, topClosed, bottomClosed), false, 0); } /** * * @param cone * @param res * @param smooth */ public final void cone(Cone cone, int res, boolean smooth) { cone(cone, res, true, true, smooth); } /** * * @param cone * @param res * @param topClosed * @param bottomClosed * @param smooth */ public final void cone(Cone cone, int res, boolean topClosed, boolean bottomClosed, boolean smooth) { Mesh3D mesh = cone.toMesh(res); if (smooth) { mesh.computeVertexNormals(); } mesh(mesh, smooth, 0); } /** * * @param cylinder */ public final void cylinder(AxisAlignedCylinder cylinder) { mesh(cylinder.toMesh(), false, 0); } /** * * @param cylinder * @param res * @param smooth */ public final void cylinder(AxisAlignedCylinder cylinder, int res, boolean smooth) { Mesh3D mesh = cylinder.toMesh(res, 0); if (smooth) { mesh.computeVertexNormals(); } mesh(mesh, smooth, 0); } /** * * @param e */ public final void ellipse(Ellipse e) { Vec2D r = e.getRadii(); switch (gfx.ellipseMode) { case PConstants.CENTER: gfx.ellipse(e.x, e.y, r.x * 2, r.y * 2); break; case PConstants.RADIUS: gfx.ellipse(e.x, e.y, r.x, r.y); break; case PConstants.CORNER: case PConstants.CORNERS: gfx.ellipse(e.x - r.x, e.y - r.y, r.x * 2, r.y * 2); break; default: logger.log(Level.WARNING, "invalid ellipse mode: {0}", gfx.ellipseMode); } } /** * * @param col */ public final void fill(ReadonlyTColor col) { gfx.fill(col.toARGB()); } /** * @return the gfx */ public final PGraphics getGraphics() { return gfx; } /** * * @param line */ public final void line(Line2D line) { gfx.line(line.a.x, line.a.y, line.b.x, line.b.y); } /** * * @param l * @param modifier */ public final void line(Line2D l, Line2DRenderModifier modifier) { modifier.apply(this, l.a, l.b); } /** * * @param line */ public final void line(Line3D line) { gfx.line(line.a.x, line.a.y, line.a.z, line.b.x, line.b.y, line.b.z); } /** * * @param a * @param b */ public final void line(ReadonlyVec2D a, ReadonlyVec2D b) { gfx.line(a.x(), a.y(), b.x(), b.y()); } /** * * @param a * @param b * @param modifier */ public final void line(ReadonlyVec2D a, ReadonlyVec2D b, Line2DRenderModifier modifier) { modifier.apply(this, a, b); } /** * * @param a * @param b */ public final void line(ReadonlyVec3D a, ReadonlyVec3D b) { gfx.line(a.x(), a.y(), a.z(), b.x(), b.y(), b.z()); } /** * * @param a * @param b */ public final void line(ReadonlyVec4D a, ReadonlyVec4D b) { gfx.line(a.x(), a.y(), a.z(), b.x(), b.y(), b.z()); } /** * * @param a * @param b */ public final void line(Vec2D a, Vec2D b) { gfx.line(a.x, a.y, b.x, b.y); } /** * * @param a * @param b */ public final void line(Vec3D a, Vec3D b) { gfx.line(a.x, a.y, a.z, b.x, b.y, b.z); } /** * * @param a * @param b */ public final void line(Vec4D a, Vec4D b) { gfx.line(a.x, a.y, a.z, b.x, b.y, b.z); } /** * * @param lines */ public final void lines2D(List lines) { lines.stream().forEach((l) -> { gfx.line(l.a.x, l.a.y, l.b.x, l.b.y); }); } /** * * @param lines */ public final void lines3D(List lines) { lines.stream().forEach((l) -> { gfx.line(l.a.x, l.a.y, l.a.z, l.b.x, l.b.y, l.b.z); }); } /** * * @param strip */ public final void lineStrip2D(LineStrip2D strip) { lineStrip2D(strip.getVertices()); } /** * Draws a 2D line strip using all points in the given list of vectors. * * @param points * point list */ public final void lineStrip2D(List points) { boolean isFilled = gfx.fill; gfx.fill = false; processVertices2D(points.iterator(), PConstants.POLYGON, false); gfx.fill = isFilled; } /** * * @param points * @param scale */ public final void lineStrip2D(List points, float scale) { boolean isFilled = gfx.fill; gfx.fill = false; processVertices2D(points.iterator(), PConstants.POLYGON, false, scale); gfx.fill = isFilled; } /** * * @param strip */ public final void lineStrip3D(LineStrip3D strip) { lineStrip3D(strip.getVertices()); } /** * Draws a 3D line strip using all points in the given list of vectors. * * @param points * point list */ public final void lineStrip3D(List points) { boolean isFilled = gfx.fill; gfx.fill = false; processVertices3D(points.iterator(), PConstants.POLYGON, false); gfx.fill = isFilled; } /** * * @param points * @param scale */ public final void lineStrip3D(List points, float scale) { boolean isFilled = gfx.fill; gfx.fill = false; processVertices3D(points.iterator(), PConstants.POLYGON, false, scale); gfx.fill = isFilled; } /** * Draws a 3D line strip using all points in the given list of 4D vectors. * The w component of the vectors is ignored. * * @param points * point list */ public final void lineStrip4D(List points) { boolean isFilled = gfx.fill; gfx.fill = false; processVertices4D(points.iterator(), PConstants.POLYGON, false); gfx.fill = isFilled; } /** * * @param points * @param scale */ public final void lineStrip4D(List points, float scale) { boolean isFilled = gfx.fill; gfx.fill = false; processVertices4D(points.iterator(), PConstants.POLYGON, false, scale); gfx.fill = isFilled; } /** * Draws a mesh instance using flat shading. * * @param mesh */ public final void mesh(Mesh3D mesh) { mesh(mesh, false, 0); } /** * Draws a mesh instance. * * @param mesh * @param smooth * true to enable Gouraud shading (uses vertex normals, which * should have been computed beforehand) or false for flat * shading */ public final void mesh(Mesh3D mesh, boolean smooth) { mesh(mesh, smooth, 0); } /** * Draws a mesh instance. * * @param mesh * @param smooth * true to enable gouroud shading (uses vertex normals, which * should have been computed beforehand) or false for flat * shading * @param normalLength * if >0 then face (or vertex) normals are rendered at this * length */ public final void mesh(Mesh3D mesh, boolean smooth, float normalLength) { gfx.beginShape(PConstants.TRIANGLES); if (smooth) { mesh.getFaces().stream().map((f) -> { gfx.normal(f.a.normal.x, f.a.normal.y, f.a.normal.z); return f; }).map((f) -> { gfx.vertex(f.a.x, f.a.y, f.a.z); return f; }).map((f) -> { gfx.normal(f.b.normal.x, f.b.normal.y, f.b.normal.z); return f; }).map((f) -> { gfx.vertex(f.b.x, f.b.y, f.b.z); return f; }).map((f) -> { gfx.normal(f.c.normal.x, f.c.normal.y, f.c.normal.z); return f; }).forEach((f) -> { gfx.vertex(f.c.x, f.c.y, f.c.z); }); } else { mesh.getFaces().stream().map((f) -> { gfx.normal(f.normal.x, f.normal.y, f.normal.z); return f; }).map((f) -> { gfx.vertex(f.a.x, f.a.y, f.a.z); return f; }).map((f) -> { gfx.vertex(f.b.x, f.b.y, f.b.z); return f; }).forEach((f) -> { gfx.vertex(f.c.x, f.c.y, f.c.z); }); } gfx.endShape(); if (normalLength > 0) { int strokeCol = 0; boolean isStroked = gfx.stroke; if (isStroked) { strokeCol = gfx.strokeColor; } if (smooth) { mesh.getVertices().stream().forEach((v) -> { Vec3D w = v.add(v.normal.scale(normalLength)); Vec3D n = v.normal.scale(127); gfx.stroke(n.x + 128, n.y + 128, n.z + 128); gfx.line(v.x, v.y, v.z, w.x, w.y, w.z); }); } else { float third = 1f / 3; mesh.getFaces().stream().forEach((f) -> { Vec3D c = f.a.add(f.b).addSelf(f.c).scaleSelf(third); Vec3D d = c.add(f.normal.scale(normalLength)); Vec3D n = f.normal.scale(127); gfx.stroke(n.x + 128, n.y + 128, n.z + 128); gfx.line(c.x, c.y, c.z, d.x, d.y, d.z); }); } if (isStroked) { gfx.stroke(strokeCol); } else { gfx.noStroke(); } } } /** * Draws the given mesh with each face or vertex tinted using its related * normal vector as RGB color. Normals can also optionally be shown as * lines. * * @param mesh * @param vertexNormals * true, if using vertex normals (else face normals only) */ public final void meshNormalMapped(Mesh3D mesh, boolean vertexNormals) { meshNormalMapped(mesh, new XYZNormalMapper(), vertexNormals); } /** * * @param mesh * @param mapper * @param vertexNormals */ public final void meshNormalMapped(Mesh3D mesh, NormalMapper mapper, boolean vertexNormals) { final boolean isWireframe = gfx.stroke; gfx.beginShape(PConstants.TRIANGLES); if (vertexNormals) { mesh.getFaces().stream().map((f) -> { setStrokeFill(isWireframe, mapper.getRGBForNormal(f.a.normal)); return f; }).map((f) -> { gfx.normal(f.a.normal.x, f.a.normal.y, f.a.normal.z); return f; }).map((f) -> { gfx.vertex(f.a.x, f.a.y, f.a.z); return f; }).map((f) -> { setStrokeFill(isWireframe, mapper.getRGBForNormal(f.b.normal)); return f; }).map((f) -> { gfx.normal(f.b.normal.x, f.b.normal.y, f.b.normal.z); return f; }).map((f) -> { gfx.vertex(f.b.x, f.b.y, f.b.z); return f; }).map((f) -> { setStrokeFill(isWireframe, mapper.getRGBForNormal(f.c.normal)); return f; }).map((f) -> { gfx.normal(f.c.normal.x, f.c.normal.y, f.c.normal.z); return f; }).forEach((f) -> { gfx.vertex(f.c.x, f.c.y, f.c.z); }); } else { mesh.getFaces().stream().map((f) -> { setStrokeFill(isWireframe, mapper.getRGBForNormal(f.normal)); return f; }).map((f) -> { gfx.normal(f.normal.x, f.normal.y, f.normal.z); return f; }).map((f) -> { gfx.vertex(f.a.x, f.a.y, f.a.z); return f; }).map((f) -> { gfx.vertex(f.b.x, f.b.y, f.b.z); return f; }).forEach((f) -> { gfx.vertex(f.c.x, f.c.y, f.c.z); }); } gfx.endShape(); } /** * * @param len */ public void origin(float len) { origin(Vec3D.ZERO, len); } /** * Draws the major axes from the given point. * * @param o * origin point * @param len * axis length */ public final void origin(ReadonlyVec3D o, float len) { final float x = o.x(); final float y = o.y(); final float z = o.z(); gfx.stroke(255, 0, 0); gfx.line(x, y, z, x + len, y, z); gfx.stroke(0, 255, 0); gfx.line(x, y, z, x, y + len, z); gfx.stroke(0, 0, 255); gfx.line(x, y, z, x, y, z + len); } /** * Draws a square section of a plane at the given size. * * @param plane * plane to draw * @param size * edge length */ public final void plane(Plane plane, float size) { mesh(plane.toMesh(size), false, 0); } /** * * @param v */ public final void point(ReadonlyVec2D v) { gfx.point(v.x(), v.y()); } /** * * @param v */ public final void point(ReadonlyVec3D v) { gfx.point(v.x(), v.y(), v.z()); } /** * * @param v */ public final void point(ReadonlyVec4D v) { gfx.point(v.x(), v.y(), v.z()); } /** * Draws a 2D point at the given position. * * @param v */ public final void point(Vec2D v) { gfx.point(v.x, v.y); } /** * Draws a 3D point at the given position. * * @param v */ public final void point(Vec3D v) { gfx.point(v.x, v.y, v.z); } /** * * @param v */ public final void point(Vec4D v) { gfx.point(v.x, v.y, v.z); } /** * * @param iterator */ public final void points2D(Iterator iterator) { processVertices2D(iterator, PConstants.POINTS, false); } /** * * @param points */ public final void points2D(List points) { processVertices2D(points.iterator(), PConstants.POINTS, false); } /** * * @param points * @param scale */ public final void points2D(List points, float scale) { processVertices2D(points.iterator(), PConstants.POINTS, false, scale); } /** * * @param iterator */ public final void points3D(Iterator iterator) { processVertices3D(iterator, PConstants.POINTS, false); } /** * * @param points */ public final void points3D(List points) { processVertices3D(points.iterator(), PConstants.POINTS, false); } /** * * @param points * @param scale */ public final void points3D(List points, float scale) { processVertices3D(points.iterator(), PConstants.POINTS, false, scale); } /** * * @param iterator */ public final void points4D(Iterator iterator) { processVertices4D(iterator, PConstants.POINTS, false); } /** * * @param points */ public final void points4D(List points) { processVertices4D(points.iterator(), PConstants.POINTS, false); } /** * * @param points * @param scale */ public final void points4D(List points, float scale) { processVertices4D(points.iterator(), PConstants.POINTS, false, scale); } /** * * @param poly */ public final void polygon2D(Polygon2D poly) { processVertices2D(poly.vertices.iterator(), PConstants.POLYGON, true); } /** * * @param iterator * @param shapeID * @param closed */ public final void processVertices2D(Iterator iterator, int shapeID, boolean closed) { gfx.beginShape(shapeID); while (iterator.hasNext()) { Vec2D v = iterator.next(); gfx.vertex(v.x, v.y); } if (closed) { gfx.endShape(PConstants.CLOSE); } else { gfx.endShape(); } } /** * * @param iterator * @param shapeID * @param closed * @param scale */ public final void processVertices2D(Iterator iterator, int shapeID, boolean closed, float scale) { gfx.beginShape(shapeID); while (iterator.hasNext()) { Vec2D v = iterator.next(); gfx.vertex(v.x * scale, v.y * scale); } if (closed) { gfx.endShape(PConstants.CLOSE); } else { gfx.endShape(); } } /** * * @param iterator * @param shapeID * @param closed */ public final void processVertices3D(Iterator iterator, int shapeID, boolean closed) { gfx.beginShape(shapeID); while (iterator.hasNext()) { Vec3D v = iterator.next(); gfx.vertex(v.x, v.y, v.z); } if (closed) { gfx.endShape(PConstants.CLOSE); } else { gfx.endShape(); } } /** * * @param iterator * @param shapeID * @param closed * @param scale */ public final void processVertices3D(Iterator iterator, int shapeID, boolean closed, float scale) { gfx.beginShape(shapeID); while (iterator.hasNext()) { Vec3D v = iterator.next(); gfx.vertex(v.x * scale, v.y * scale, v.z * scale); } if (closed) { gfx.endShape(PConstants.CLOSE); } else { gfx.endShape(); } } /** * * @param iterator * @param shapeID * @param closed */ public final void processVertices4D(Iterator iterator, int shapeID, boolean closed) { gfx.beginShape(shapeID); while (iterator.hasNext()) { Vec4D v = iterator.next(); gfx.vertex(v.x, v.y, v.z); } if (closed) { gfx.endShape(PConstants.CLOSE); } else { gfx.endShape(); } } /** * * @param iterator * @param shapeID * @param closed * @param scale */ public final void processVertices4D(Iterator iterator, int shapeID, boolean closed, float scale) { gfx.beginShape(shapeID); while (iterator.hasNext()) { Vec4D v = iterator.next(); gfx.vertex(v.x * scale, v.y * scale, v.z * scale); } if (closed) { gfx.endShape(PConstants.CLOSE); } else { gfx.endShape(); } } /** * * @param ray * @param length */ public final void ray(Ray2D ray, float length) { Vec2D e = ray.getPointAtDistance(length); gfx.line(ray.x, ray.y, e.x, e.y); } /** * * @param ray * @param length */ public final void ray(Ray3D ray, float length) { Vec3D e = ray.getPointAtDistance(length); gfx.line(ray.x, ray.y, ray.z, e.x, e.y, e.z); } /** * * @param r */ public final void rect(Rect r) { switch (gfx.rectMode) { case PConstants.CORNER: gfx.rect(r.x, r.y, r.width, r.height); break; case PConstants.CORNERS: gfx.rect(r.x, r.y, r.x + r.width, r.y + r.height); break; case PConstants.CENTER: gfx.rect(r.x + r.width * 0.5f, r.y + r.height * 0.5f, r.width, r.height); break; case PConstants.RADIUS: float rw = r.width * 0.5f; float rh = r.height * 0.5f; gfx.rect(r.x + rw, r.y + rh, rw, rh); break; default: logger.log(Level.WARNING, "invalid rect mode: {0}", gfx.rectMode); } } /** * * @param theta * @param v */ public final void rotate(float theta, ReadonlyVec3D v) { gfx.rotate(theta, v.x(), v.y(), v.z()); } /** * * @param v */ public final void scale(ReadonlyVec2D v) { gfx.scale(v.x(), v.y()); } /** * * @param v */ public final void scale(ReadonlyVec3D v) { gfx.scale(v.x(), v.y(), v.z()); } /** * * @param v */ public final void scale(Vec2D v) { gfx.scale(v.x, v.y); } /** * * @param v */ public final void scale(Vec3D v) { gfx.scale(v.x, v.y, v.z); } /** * @param gfx * the gfx to set */ public final void setGraphics(PGraphics gfx) { this.gfx = gfx; } /** * * @param isWireframe * @param r * @param g * @param b */ public final void setStrokeFill(final boolean isWireframe, final float r, final float g, final float b) { if (isWireframe) { gfx.fill(r, g, b); } else { gfx.stroke(r, g, b); } } /** * * @param isWireframe * @param col */ public final void setStrokeFill(final boolean isWireframe, final ReadonlyTColor col) { if (isWireframe) { gfx.stroke(col.toARGB()); } else { gfx.fill(col.toARGB()); } } /** * * @param sphere * @param res */ public final void sphere(Sphere sphere, int res) { mesh(sphere.toMesh(res)); } /** * * @param sphere * @param res * @param smooth */ public final void sphere(Sphere sphere, int res, boolean smooth) { mesh(sphere.toMesh(res), smooth); } /** * * @param col */ public final void stroke(ReadonlyTColor col) { gfx.stroke(col.toARGB()); } /** * * @param mesh * @param tex * @param smooth */ public final void texturedMesh(Mesh3D mesh, PImage tex, boolean smooth) { gfx.beginShape(PConstants.TRIANGLES); gfx.texture(tex); if (smooth) { mesh.getFaces().stream().forEach((f) -> { if (f.uvA != null && f.uvB != null && f.uvC != null) { gfx.normal(f.a.normal.x, f.a.normal.y, f.a.normal.z); gfx.vertex(f.a.x, f.a.y, f.a.z, f.uvA.x, f.uvA.y); gfx.normal(f.b.normal.x, f.b.normal.y, f.b.normal.z); gfx.vertex(f.b.x, f.b.y, f.b.z, f.uvB.x, f.uvB.y); gfx.normal(f.c.normal.x, f.c.normal.y, f.c.normal.z); gfx.vertex(f.c.x, f.c.y, f.c.z, f.uvC.x, f.uvC.y); } else { gfx.vertex(f.a.x, f.a.y, f.a.z); gfx.vertex(f.b.x, f.b.y, f.b.z); gfx.vertex(f.c.x, f.c.y, f.c.z); } }); } else { mesh.getFaces().stream().map((f) -> { gfx.normal(f.normal.x, f.normal.y, f.normal.z); return f; }).forEach((f) -> { if (f.uvA != null && f.uvB != null && f.uvC != null) { gfx.vertex(f.a.x, f.a.y, f.a.z, f.uvA.x, f.uvA.y); gfx.vertex(f.b.x, f.b.y, f.b.z, f.uvB.x, f.uvB.y); gfx.vertex(f.c.x, f.c.y, f.c.z, f.uvC.x, f.uvC.y); } else { gfx.vertex(f.a.x, f.a.y, f.a.z); gfx.vertex(f.b.x, f.b.y, f.b.z); gfx.vertex(f.c.x, f.c.y, f.c.z); } }); } gfx.endShape(); } /** * * @param v */ public final void translate(ReadonlyVec2D v) { gfx.translate(v.x(), v.y()); } /** * * @param v */ public final void translate(ReadonlyVec3D v) { gfx.translate(v.x(), v.y(), v.z()); } /** * * @param v */ public final void translate(Vec2D v) { gfx.translate(v.x, v.y); } /** * * @param v */ public final void translate(Vec3D v) { gfx.translate(v.x, v.y, v.z); } /** * * @param tri */ public final void triangle(Triangle2D tri) { triangle(tri, true); } /** * * @param tri * @param isFullShape */ public final void triangle(Triangle2D tri, boolean isFullShape) { if (isFullShape) { gfx.beginShape(PConstants.TRIANGLES); } gfx.vertex(tri.a.x, tri.a.y); gfx.vertex(tri.b.x, tri.b.y); gfx.vertex(tri.c.x, tri.c.y); if (isFullShape) { gfx.endShape(); } } /** * * @param tri */ public final void triangle(Triangle3D tri) { triangle(tri, true); } /** * * @param tri * @param isFullShape */ public final void triangle(Triangle3D tri, boolean isFullShape) { if (isFullShape) { gfx.beginShape(PConstants.TRIANGLES); } Vec3D n = tri.computeNormal(); gfx.normal(n.x, n.y, n.z); gfx.vertex(tri.a.x, tri.a.y, tri.a.z); gfx.vertex(tri.b.x, tri.b.y, tri.b.z); gfx.vertex(tri.c.x, tri.c.y, tri.c.z); if (isFullShape) { gfx.endShape(); } } /** * * @param v */ public final void vertex(ReadonlyVec2D v) { gfx.vertex(v.x(), v.y()); } /** * * @param v */ public final void vertex(ReadonlyVec3D v) { gfx.vertex(v.x(), v.y(), v.z()); } /** * * @param v */ public final void vertex(Vec2D v) { gfx.vertex(v.x, v.y); } /** * * @param v */ public final void vertex(Vec3D v) { gfx.vertex(v.x, v.y, v.z); } }