moving opengl into the core

This commit is contained in:
benfry
2012-07-20 20:18:20 +00:00
parent 2a7aad98dc
commit b30328bb66
23 changed files with 0 additions and 0 deletions
@@ -1,465 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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 as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
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.opengl;
import processing.core.PApplet;
import processing.core.PConstants;
import java.nio.IntBuffer;
/**
* Encapsulates a Frame Buffer Object for offscreen rendering.
* When created with onscreen == true, it represents the normal
* framebuffer. Needed by the stack mechanism in OPENGL2 to return
* to onscreen rendering after a sequence of pushFramebuffer calls.
* It transparently handles the situations when the FBO extension is
* not available.
*
* By Andres Colubri.
*/
public class FrameBuffer implements PConstants {
protected PApplet parent;
protected PGraphicsOpenGL pg;
protected PGL pgl;
protected PGL.Context context; // The context that created this framebuffer.
public int glFbo;
public int glDepth;
public int glStencil;
public int glDepthStencil;
public int glMultisample;
public int width;
public int height;
protected int depthBits;
protected int stencilBits;
protected boolean packedDepthStencil;
protected boolean multisample;
protected int nsamples;
protected int numColorBuffers;
protected Texture[] colorBufferTex;
protected boolean screenFb;
protected boolean noDepth;
protected IntBuffer pixelBuffer;
FrameBuffer(PApplet parent, int w, int h) {
this(parent, w, h, 1, 1, 0, 0, false, false);
}
FrameBuffer(PApplet parent, int w, int h, boolean screen) {
this(parent, w, h, 1, 1, 0, 0, false, screen);
}
FrameBuffer(PApplet parent, int w, int h, int samples, int colorBuffers,
int depthBits, int stencilBits, boolean packedDepthStencil,
boolean screen) {
this.parent = parent;
pg = (PGraphicsOpenGL)parent.g;
pgl = pg.pgl;
context = pgl.createEmptyContext();
glFbo = 0;
glDepth = 0;
glStencil = 0;
glDepthStencil = 0;
glMultisample = 0;
if (screen) {
// If this framebuffer is used to represent a on-screen buffer,
// then it doesn't make it sense for it to have multisampling,
// color, depth or stencil buffers.
depthBits = stencilBits = samples = colorBuffers = 0;
}
width = w;
height = h;
if (1 < samples) {
multisample = true;
nsamples = samples;
} else {
multisample = false;
nsamples = 1;
}
numColorBuffers = colorBuffers;
colorBufferTex = new Texture[numColorBuffers];
for (int i = 0; i < numColorBuffers; i++) {
colorBufferTex[i] = null;
}
if (depthBits < 1 && stencilBits < 1) {
this.depthBits = 0;
this.stencilBits = 0;
this.packedDepthStencil = false;
} else {
if (packedDepthStencil) {
// When combined depth/stencil format is required, the depth and stencil bits
// are overriden and the 24/8 combination for a 32 bits surface is used.
this.depthBits = 24;
this.stencilBits = 8;
this.packedDepthStencil = true;
} else {
this.depthBits = depthBits;
this.stencilBits = stencilBits;
this.packedDepthStencil = false;
}
}
screenFb = screen;
allocate();
noDepth = false;
pixelBuffer = null;
}
protected void finalize() throws Throwable {
try {
if (glFbo != 0) {
pg.finalizeFrameBufferObject(glFbo, context.code());
}
if (glDepth != 0) {
pg.finalizeRenderBufferObject(glDepth, context.code());
}
if (glStencil != 0) {
pg.finalizeRenderBufferObject(glStencil, context.code());
}
if (glMultisample != 0) {
pg.finalizeRenderBufferObject(glMultisample, context.code());
}
if (glDepthStencil != 0) {
pg.finalizeRenderBufferObject(glDepthStencil, context.code());
}
} finally {
super.finalize();
}
}
public void clear() {
pg.pushFramebuffer();
pg.setFramebuffer(this);
pgl.glClearDepth(1);
pgl.glClearStencil(0);
pgl.glClearColor(0, 0, 0, 0);
pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT | PGL.GL_STENCIL_BUFFER_BIT | PGL.GL_COLOR_BUFFER_BIT);
pg.popFramebuffer();
}
public void copy(FrameBuffer dest) {
pgl.glBindFramebuffer(PGL.GL_READ_FRAMEBUFFER, this.glFbo);
pgl.glBindFramebuffer(PGL.GL_DRAW_FRAMEBUFFER, dest.glFbo);
pgl.glBlitFramebuffer(0, 0, this.width, this.height,
0, 0, dest.width, dest.height,
PGL.GL_COLOR_BUFFER_BIT, PGL.GL_NEAREST);
}
public void bind() {
pgl.glBindFramebuffer(PGL.GL_FRAMEBUFFER, glFbo);
}
public void disableDepthTest() {
noDepth = true;
}
public void finish() {
if (noDepth) {
// No need to clear depth buffer because depth testing was disabled.
if (pg.hintEnabled(ENABLE_DEPTH_TEST)) {
pgl.glEnable(PGL.GL_DEPTH_TEST);
} else {
pgl.glDisable(PGL.GL_DEPTH_TEST);
}
}
}
public void readPixels() {
if (pixelBuffer == null) createPixelBuffer();
pixelBuffer.rewind();
pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer);
}
public void getPixels(int[] pixels) {
if (pixelBuffer != null) {
pixelBuffer.get(pixels, 0, pixels.length);
pixelBuffer.rewind();
}
}
public IntBuffer getPixelBuffer() {
return pixelBuffer;
}
public boolean hasDepthBuffer() {
return 0 < depthBits;
}
public boolean hasStencilBuffer() {
return 0 < stencilBits;
}
///////////////////////////////////////////////////////////
// Color buffer setters.
public void setColorBuffer(Texture tex) {
setColorBuffers(new Texture[] { tex }, 1);
}
public void setColorBuffers(Texture[] textures) {
setColorBuffers(textures, textures.length);
}
public void setColorBuffers(Texture[] textures, int n) {
if (screenFb) return;
if (numColorBuffers != PApplet.min(n, textures.length)) {
throw new RuntimeException("Wrong number of textures to set the color buffers.");
}
for (int i = 0; i < numColorBuffers; i++) {
colorBufferTex[i] = textures[i];
}
pg.pushFramebuffer();
pg.setFramebuffer(this);
// Making sure nothing is attached.
for (int i = 0; i < numColorBuffers; i++) {
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, PGL.GL_TEXTURE_2D, 0, 0);
}
for (int i = 0; i < numColorBuffers; i++) {
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, colorBufferTex[i].glTarget, colorBufferTex[i].glName, 0);
}
pgl.validateFramebuffer();
pg.popFramebuffer();
}
///////////////////////////////////////////////////////////
// Allocate/release framebuffer.
protected void allocate() {
release(); // Just in the case this object is being re-allocated.
context = pgl.getCurrentContext();
if (screenFb) {
glFbo = 0;
} else {
glFbo = pg.createFrameBufferObject(context.code());
}
// create the rest of the stuff...
if (multisample) {
createColorBufferMultisample();
}
if (packedDepthStencil) {
createPackedDepthStencilBuffer();
} else {
if (0 < depthBits) {
createDepthBuffer();
}
if (0 < stencilBits) {
createStencilBuffer();
}
}
}
protected void release() {
if (glFbo != 0) {
pg.finalizeFrameBufferObject(glFbo, context.code());
glFbo = 0;
}
if (glDepth != 0) {
pg.finalizeRenderBufferObject(glDepth, context.code());
glDepth = 0;
}
if (glStencil != 0) {
pg.finalizeRenderBufferObject(glStencil, context.code());
glStencil = 0;
}
if (glMultisample != 0) {
pg.finalizeRenderBufferObject(glMultisample, context.code());
glMultisample = 0;
}
if (glDepthStencil != 0) {
pg.finalizeRenderBufferObject(glDepthStencil, context.code());
glDepthStencil = 0;
}
}
protected boolean contextIsOutdated() {
boolean outdated = !pgl.contextIsCurrent(context);
if (outdated) {
pg.removeFrameBufferObject(glFbo, context.code());
pg.removeRenderBufferObject(glDepth, context.code());
pg.removeRenderBufferObject(glStencil, context.code());
pg.removeRenderBufferObject(glDepthStencil, context.code());
pg.removeRenderBufferObject(glMultisample, context.code());
glFbo = 0;
glDepth = 0;
glStencil = 0;
glDepthStencil = 0;
glMultisample = 0;
for (int i = 0; i < numColorBuffers; i++) {
colorBufferTex[i] = null;
}
}
return outdated;
}
protected void createColorBufferMultisample() {
if (screenFb) return;
pg.pushFramebuffer();
pg.setFramebuffer(this);
glMultisample = pg.createRenderBufferObject(context.code());
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glMultisample);
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, PGL.GL_RGBA8, width, height);
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0, PGL.GL_RENDERBUFFER, glMultisample);
pg.popFramebuffer();
}
protected void createPackedDepthStencilBuffer() {
if (screenFb) return;
if (width == 0 || height == 0) {
throw new RuntimeException("PFramebuffer: size undefined.");
}
pg.pushFramebuffer();
pg.setFramebuffer(this);
glDepthStencil = pg.createRenderBufferObject(context.code());
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glDepthStencil);
if (multisample) {
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, PGL.GL_DEPTH24_STENCIL8, width, height);
} else {
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, PGL.GL_DEPTH24_STENCIL8, width, height);
}
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_DEPTH_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthStencil);
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_STENCIL_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthStencil);
pg.popFramebuffer();
}
protected void createDepthBuffer() {
if (screenFb) return;
if (width == 0 || height == 0) {
throw new RuntimeException("PFramebuffer: size undefined.");
}
pg.pushFramebuffer();
pg.setFramebuffer(this);
glDepth = pg.createRenderBufferObject(context.code());
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glDepth);
int glConst = PGL.GL_DEPTH_COMPONENT16;
if (depthBits == 16) {
glConst = PGL.GL_DEPTH_COMPONENT16;
} else if (depthBits == 24) {
glConst = PGL.GL_DEPTH_COMPONENT24;
} else if (depthBits == 32) {
glConst = PGL.GL_DEPTH_COMPONENT32;
}
if (multisample) {
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, glConst, width, height);
} else {
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, glConst, width, height);
}
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_DEPTH_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepth);
pg.popFramebuffer();
}
protected void createStencilBuffer() {
if (screenFb) return;
if (width == 0 || height == 0) {
throw new RuntimeException("PFramebuffer: size undefined.");
}
pg.pushFramebuffer();
pg.setFramebuffer(this);
glStencil = pg.createRenderBufferObject(context.code());
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glStencil);
int glConst = PGL.GL_STENCIL_INDEX1;
if (stencilBits == 1) {
glConst = PGL.GL_STENCIL_INDEX1;
} else if (stencilBits == 4) {
glConst = PGL.GL_STENCIL_INDEX4;
} else if (stencilBits == 8) {
glConst = PGL.GL_STENCIL_INDEX8;
}
if (multisample) {
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, glConst, width, height);
} else {
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, glConst, width, height);
}
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_STENCIL_ATTACHMENT, PGL.GL_RENDERBUFFER, glStencil);
pg.popFramebuffer();
}
protected void createPixelBuffer() {
pixelBuffer = IntBuffer.allocate(width * height);
pixelBuffer.rewind();
}
}
@@ -1,563 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package processing.opengl;
import processing.core.PMatrix2D;
/**
* The {@code LinePath} class allows to represent polygonal paths,
* potentially composed by several disjoint polygonal segments.
* It can be iterated by the {@link PathIterator} class including all
* of its segment types and winding rules
*
*/
public class LinePath {
/**
* The winding rule constant for specifying an even-odd rule
* for determining the interior of a path.
* The even-odd rule specifies that a point lies inside the
* path if a ray drawn in any direction from that point to
* infinity is crossed by path segments an odd number of times.
*/
public static final int WIND_EVEN_ODD = 0;
/**
* The winding rule constant for specifying a non-zero rule
* for determining the interior of a path.
* The non-zero rule specifies that a point lies inside the
* path if a ray drawn in any direction from that point to
* infinity is crossed by path segments a different number
* of times in the counter-clockwise direction than the
* clockwise direction.
*/
public static final int WIND_NON_ZERO = 1;
/**
* Starts segment at a given position.
*/
public static final byte SEG_MOVETO = 0;
/**
* Extends segment by adding a line to a given position.
*/
public static final byte SEG_LINETO = 1;
/**
* Closes segment at current position.
*/
public static final byte SEG_CLOSE = 2;
/**
* Joins path segments by extending their outside edges until they meet.
*/
public final static int JOIN_MITER = 0;
/**
* Joins path segments by rounding off the corner at a radius of half the line
* width.
*/
public final static int JOIN_ROUND = 1;
/**
* Joins path segments by connecting the outer corners of their wide outlines
* with a straight segment.
*/
public final static int JOIN_BEVEL = 2;
/**
* Ends unclosed subpaths and dash segments with no added decoration.
*/
public final static int CAP_BUTT = 0;
/**
* Ends unclosed subpaths and dash segments with a round decoration that has a
* radius equal to half of the width of the pen.
*/
public final static int CAP_ROUND = 1;
/**
* Ends unclosed subpaths and dash segments with a square projection that
* extends beyond the end of the segment to a distance equal to half of the
* line width.
*/
public final static int CAP_SQUARE = 2;
private static PMatrix2D identity = new PMatrix2D();
private static float defaultMiterlimit = 10.0f;
static final int INIT_SIZE = 20;
static final int EXPAND_MAX = 500;
protected byte[] pointTypes;
protected float[] floatCoords;
protected int numTypes;
protected int numCoords;
protected int windingRule;
/**
* Constructs a new empty single precision {@code LinePath} object with a
* default winding rule of {@link #WIND_NON_ZERO}.
*/
public LinePath() {
this(WIND_NON_ZERO, INIT_SIZE);
}
/**
* Constructs a new empty single precision {@code LinePath} object with the
* specified winding rule to control operations that require the interior of
* the path to be defined.
*
* @param rule
* the winding rule
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
*/
public LinePath(int rule) {
this(rule, INIT_SIZE);
}
/**
* Constructs a new {@code LinePath} object from the given specified initial
* values. This method is only intended for internal use and should not be
* made public if the other constructors for this class are ever exposed.
*
* @param rule
* the winding rule
* @param initialTypes
* the size to make the initial array to store the path segment types
*/
public LinePath(int rule, int initialCapacity) {
setWindingRule(rule);
this.pointTypes = new byte[initialCapacity];
floatCoords = new float[initialCapacity * 2];
}
void needRoom(boolean needMove, int newCoords) {
if (needMove && numTypes == 0) {
throw new RuntimeException("missing initial moveto "
+ "in path definition");
}
int size = pointTypes.length;
if (numTypes >= size) {
int grow = size;
if (grow > EXPAND_MAX) {
grow = EXPAND_MAX;
}
pointTypes = copyOf(pointTypes, size + grow);
}
size = floatCoords.length;
if (numCoords + newCoords > size) {
int grow = size;
if (grow > EXPAND_MAX * 2) {
grow = EXPAND_MAX * 2;
}
if (grow < newCoords) {
grow = newCoords;
}
floatCoords = copyOf(floatCoords, size + grow);
}
}
/**
* Adds a point to the path by moving to the specified coordinates specified
* in float precision.
* <p>
* This method provides a single precision variant of the double precision
* {@code moveTo()} method on the base {@code LinePath} class.
*
* @param x
* the specified X coordinate
* @param y
* the specified Y coordinate
* @see LinePath#moveTo
*/
public final void moveTo(float x, float y) {
if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
floatCoords[numCoords - 2] = x;
floatCoords[numCoords - 1] = y;
} else {
needRoom(false, 2);
pointTypes[numTypes++] = SEG_MOVETO;
floatCoords[numCoords++] = x;
floatCoords[numCoords++] = y;
}
}
/**
* Adds a point to the path by drawing a straight line from the current
* coordinates to the new specified coordinates specified in float precision.
* <p>
* This method provides a single precision variant of the double precision
* {@code lineTo()} method on the base {@code LinePath} class.
*
* @param x
* the specified X coordinate
* @param y
* the specified Y coordinate
* @see LinePath#lineTo
*/
public final void lineTo(float x, float y) {
needRoom(true, 2);
pointTypes[numTypes++] = SEG_LINETO;
floatCoords[numCoords++] = x;
floatCoords[numCoords++] = y;
}
/**
* The iterator for this class is not multi-threaded safe, which means that
* the {@code LinePath} class does not guarantee that modifications to the
* geometry of this {@code LinePath} object do not affect any iterations of that
* geometry that are already in process.
*/
public PathIterator getPathIterator() {
return new PathIterator(this);
}
/**
* Closes the current subpath by drawing a straight line back to the
* coordinates of the last {@code moveTo}. If the path is already closed then
* this method has no effect.
*/
public final void closePath() {
if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
needRoom(false, 0);
pointTypes[numTypes++] = SEG_CLOSE;
}
}
/**
* Returns the fill style winding rule.
*
* @return an integer representing the current winding rule.
* @see #WIND_EVEN_ODD
* @see #WIND_NON_ZERO
* @see #setWindingRule
*/
public final int getWindingRule() {
return windingRule;
}
/**
* Sets the winding rule for this path to the specified value.
*
* @param rule
* an integer representing the specified winding rule
* @exception IllegalArgumentException
* if {@code rule} is not either {@link #WIND_EVEN_ODD} or
* {@link #WIND_NON_ZERO}
* @see #getWindingRule
*/
public final void setWindingRule(int rule) {
if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
throw new IllegalArgumentException("winding rule must be "
+ "WIND_EVEN_ODD or " + "WIND_NON_ZERO");
}
windingRule = rule;
}
/**
* Resets the path to empty. The append position is set back to the beginning
* of the path and all coordinates and point types are forgotten.
*/
public final void reset() {
numTypes = numCoords = 0;
}
static public class PathIterator {
float floatCoords[];
int typeIdx;
int pointIdx;
LinePath path;
static final int curvecoords[] = { 2, 2, 0 };
PathIterator(LinePath p2df) {
this.path = p2df;
this.floatCoords = p2df.floatCoords;
}
public int currentSegment(float[] coords) {
int type = path.pointTypes[typeIdx];
int numCoords = curvecoords[type];
if (numCoords > 0) {
System.arraycopy(floatCoords, pointIdx, coords, 0, numCoords);
}
return type;
}
public int currentSegment(double[] coords) {
int type = path.pointTypes[typeIdx];
int numCoords = curvecoords[type];
if (numCoords > 0) {
for (int i = 0; i < numCoords; i++) {
coords[i] = floatCoords[pointIdx + i];
}
}
return type;
}
public int getWindingRule() {
return path.getWindingRule();
}
public boolean isDone() {
return (typeIdx >= path.numTypes);
}
public void next() {
int type = path.pointTypes[typeIdx++];
pointIdx += curvecoords[type];
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Stroked path methods
static public LinePath createStrokedPath(LinePath src, float weight,
int caps, int join) {
return createStrokedPath(src, weight, caps, join, defaultMiterlimit, null);
}
static public LinePath createStrokedPath(LinePath src, float weight,
int caps, int join, float miterlimit) {
return createStrokedPath(src, weight, caps, join, miterlimit, null);
}
/**
* Constructs a solid <code>LinePath</code> with the specified attributes.
*
* @param src
* the original path to be stroked
* @param weight
* the weight of the stroked path
* @param cap
* the decoration of the ends of the segments in the path
* @param join
* the decoration applied where path segments meet
* @param miterlimit
* @param transform
*
*/
static public LinePath createStrokedPath(LinePath src, float weight,
int caps, int join,
float miterlimit, PMatrix2D transform) {
final LinePath dest = new LinePath();
strokeTo(src, weight, caps, join, miterlimit, transform, new LineStroker() {
public void moveTo(int x0, int y0) {
dest.moveTo(S15_16ToFloat(x0), S15_16ToFloat(y0));
}
public void lineJoin() {
}
public void lineTo(int x1, int y1) {
dest.lineTo(S15_16ToFloat(x1), S15_16ToFloat(y1));
}
public void close() {
dest.closePath();
}
public void end() {
}
});
return dest;
}
private static void strokeTo(LinePath src, float width, int caps, int join,
float miterlimit, PMatrix2D transform,
LineStroker lsink) {
lsink = new LineStroker(lsink, FloatToS15_16(width), caps, join,
FloatToS15_16(miterlimit),
transform == null ? identity : transform);
PathIterator pi = src.getPathIterator();
pathTo(pi, lsink);
}
private static void pathTo(PathIterator pi, LineStroker lsink) {
float coords[] = new float[2];
while (!pi.isDone()) {
switch (pi.currentSegment(coords)) {
case SEG_MOVETO:
lsink.moveTo(FloatToS15_16(coords[0]), FloatToS15_16(coords[1]));
break;
case SEG_LINETO:
lsink.lineJoin();
lsink.lineTo(FloatToS15_16(coords[0]), FloatToS15_16(coords[1]));
break;
case SEG_CLOSE:
lsink.lineJoin();
lsink.close();
break;
default:
throw new InternalError("unknown flattened segment type");
}
pi.next();
}
lsink.end();
}
/////////////////////////////////////////////////////////////////////////////
//
// Utility methods
public static float[] copyOf(float[] source, int length) {
float[] target = new float[length];
for (int i = 0; i < target.length; i++) {
if (i > source.length - 1)
target[i] = 0f;
else
target[i] = source[i];
}
return target;
}
public static byte[] copyOf(byte[] source, int length) {
byte[] target = new byte[length];
for (int i = 0; i < target.length; i++) {
if (i > source.length - 1)
target[i] = 0;
else
target[i] = source[i];
}
return target;
}
// From Ken Turkowski, _Fixed-Point Square Root_, In Graphics Gems V
public static int isqrt(int x) {
int fracbits = 16;
int root = 0;
int remHi = 0;
int remLo = x;
int count = 15 + fracbits / 2;
do {
remHi = (remHi << 2) | (remLo >>> 30); // N.B. - unsigned shift R
remLo <<= 2;
root <<= 1;
int testdiv = (root << 1) + 1;
if (remHi >= testdiv) {
remHi -= testdiv;
root++;
}
} while (count-- != 0);
return root;
}
public static long lsqrt(long x) {
int fracbits = 16;
long root = 0;
long remHi = 0;
long remLo = x;
int count = 31 + fracbits / 2;
do {
remHi = (remHi << 2) | (remLo >>> 62); // N.B. - unsigned shift R
remLo <<= 2;
root <<= 1;
long testDiv = (root << 1) + 1;
if (remHi >= testDiv) {
remHi -= testDiv;
root++;
}
} while (count-- != 0);
return root;
}
public static double hypot(double x, double y) {
return Math.sqrt(x * x + y * y);
}
public static int hypot(int x, int y) {
return (int) ((lsqrt((long) x * x + (long) y * y) + 128) >> 8);
}
public static long hypot(long x, long y) {
return (lsqrt(x * x + y * y) + 128) >> 8;
}
static int FloatToS15_16(float flt) {
flt = flt * 65536f + 0.5f;
if (flt <= -(65536f * 65536f)) {
return Integer.MIN_VALUE;
} else if (flt >= (65536f * 65536f)) {
return Integer.MAX_VALUE;
} else {
return (int) Math.floor(flt);
}
}
static float S15_16ToFloat(int fix) {
return (fix / 65536f);
}
}
@@ -1,30 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor;
void main() {
gl_FragColor = vertColor;
}
@@ -1,86 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
uniform mat4 modelviewMatrix;
uniform mat4 projectionMatrix;
uniform vec4 viewport;
uniform int perspective;
uniform float zfactor;
attribute vec4 inVertex;
attribute vec4 inColor;
attribute vec4 inLine;
varying vec4 vertColor;
vec3 clipToWindow(vec4 clip, vec4 viewport) {
vec3 post_div = clip.xyz / clip.w;
vec2 xypos = (post_div.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw;
return vec3(xypos, post_div.z * 0.5 + 0.5);
}
vec4 windowToClipVector(vec2 window, vec4 viewport, float clip_w) {
vec2 xypos = (window / viewport.zw) * 2.0;
return vec4(xypos, 0.0, 0.0) * clip_w;
}
void main() {
vec4 pos_p = inVertex;
vec4 v_p = modelviewMatrix * pos_p;
// Moving vertices slightly toward the camera (if zfactor < 1)
// to avoid depth-fighting with the fill triangles.
// Discussed here:
// http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848
v_p.xyz = v_p.xyz * zfactor;
vec4 clip_p = projectionMatrix * v_p;
float thickness = inLine.w;
if (thickness != 0.0) {
vec4 pos_q = vec4(inLine.xyz, 1);
vec4 v_q = modelviewMatrix * pos_q;
v_q.xyz = v_q.xyz * zfactor;
vec4 clip_q = projectionMatrix * v_q;
vec3 window_p = clipToWindow(clip_p, viewport);
vec3 window_q = clipToWindow(clip_q, viewport);
vec3 tangent = window_q - window_p;
float segment_length = length(tangent.xy);
vec2 perp = normalize(vec2(-tangent.y, tangent.x));
vec2 window_offset = perp * thickness;
if (0 < perspective) {
// Perspective correction (lines will look thiner as they move away
// from the view position).
gl_Position.xy = clip_p.xy + window_offset.xy;
gl_Position.zw = clip_p.zw;
} else {
// No perspective correction.
float clip_p_w = clip_p.w;
vec4 offset_p = windowToClipVector(window_offset, viewport, clip_p_w);
gl_Position = clip_p + offset_p;
}
} else {
gl_Position = clip_p;
}
vertColor = inColor;
}
@@ -1,697 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package processing.opengl;
import processing.core.PMatrix2D;
public class LineStroker {
private LineStroker output;
// private int lineWidth;
private int capStyle;
private int joinStyle;
// private int miterLimit;
private int m00, m01;
private int m10, m11;
private int lineWidth2;
private long scaledLineWidth2;
// For any pen offset (pen_dx, pen_dy) that does not depend on
// the line orientation, the pen should be transformed so that:
//
// pen_dx' = m00*pen_dx + m01*pen_dy
// pen_dy' = m10*pen_dx + m11*pen_dy
//
// For a round pen, this means:
//
// pen_dx(r, theta) = r*cos(theta)
// pen_dy(r, theta) = r*sin(theta)
//
// pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta))
// pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta))
private int numPenSegments;
private int[] pen_dx;
private int[] pen_dy;
private boolean[] penIncluded;
private int[] join;
private int[] offset = new int[2];
private int[] reverse = new int[100];
private int[] miter = new int[2];
private long miterLimitSq;
private int prev;
private int rindex;
private boolean started;
private boolean lineToOrigin;
private boolean joinToOrigin;
// private int sx0, sy0, sx1, sy1, x0, y0, x1, y1;
// private int mx0, my0, mx1, my1, omx, omy;
// private int lx0, ly0, lx1, ly1, lx0p, ly0p, px0, py0;
private int sx0, sy0, sx1, sy1, x0, y0;
private int mx0, my0, omx, omy;
private int px0, py0;
private double m00_2_m01_2;
private double m10_2_m11_2;
private double m00_m10_m01_m11;
/**
* Empty constructor. <code>setOutput</code> and <code>setParameters</code>
* must be called prior to calling any other methods.
*/
public LineStroker() {
}
/**
* Constructs a <code>LineStroker</code>.
*
* @param output
* an output <code>LineStroker</code>.
* @param lineWidth
* the desired line width in pixels, in S15.16 format.
* @param capStyle
* the desired end cap style, one of <code>CAP_BUTT</code>,
* <code>CAP_ROUND</code> or <code>CAP_SQUARE</code>.
* @param joinStyle
* the desired line join style, one of <code>JOIN_MITER</code>,
* <code>JOIN_ROUND</code> or <code>JOIN_BEVEL</code>.
* @param miterLimit
* the desired miter limit, in S15.16 format.
* @param transform
* a <code>Transform4</code> object indicating the transform that has
* been previously applied to all incoming coordinates. This is
* required in order to produce consistently shaped end caps and
* joins.
*/
public LineStroker(LineStroker output, int lineWidth, int capStyle, int joinStyle,
int miterLimit, PMatrix2D transform) {
setOutput(output);
setParameters(lineWidth, capStyle, joinStyle, miterLimit, transform);
}
/**
* Sets the output <code>LineStroker</code> of this <code>LineStroker</code>.
*
* @param output
* an output <code>LineStroker</code>.
*/
public void setOutput(LineStroker output) {
this.output = output;
}
/**
* Sets the parameters of this <code>LineStroker</code>.
*
* @param lineWidth
* the desired line width in pixels, in S15.16 format.
* @param capStyle
* the desired end cap style, one of <code>CAP_BUTT</code>,
* <code>CAP_ROUND</code> or <code>CAP_SQUARE</code>.
* @param joinStyle
* the desired line join style, one of <code>JOIN_MITER</code>,
* <code>JOIN_ROUND</code> or <code>JOIN_BEVEL</code>.
* @param miterLimit
* the desired miter limit, in S15.16 format.
* @param transform
* a <code>Transform4</code> object indicating the transform that has
* been previously applied to all incoming coordinates. This is
* required in order to produce consistently shaped end caps and
* joins.
*/
public void setParameters(int lineWidth, int capStyle, int joinStyle,
int miterLimit, PMatrix2D transform) {
this.m00 = LinePath.FloatToS15_16(transform.m00);
this.m01 = LinePath.FloatToS15_16(transform.m01);
this.m10 = LinePath.FloatToS15_16(transform.m10);
this.m11 = LinePath.FloatToS15_16(transform.m11);
// this.lineWidth = lineWidth;
this.lineWidth2 = lineWidth >> 1;
this.scaledLineWidth2 = ((long) m00 * lineWidth2) >> 16;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
// this.miterLimit = miterLimit;
this.m00_2_m01_2 = (double) m00 * m00 + (double) m01 * m01;
this.m10_2_m11_2 = (double) m10 * m10 + (double) m11 * m11;
this.m00_m10_m01_m11 = (double) m00 * m10 + (double) m01 * m11;
double dm00 = m00 / 65536.0;
double dm01 = m01 / 65536.0;
double dm10 = m10 / 65536.0;
double dm11 = m11 / 65536.0;
double determinant = dm00 * dm11 - dm01 * dm10;
if (joinStyle == LinePath.JOIN_MITER) {
double limit = (miterLimit / 65536.0) * (lineWidth2 / 65536.0)
* determinant;
double limitSq = limit * limit;
this.miterLimitSq = (long) (limitSq * 65536.0 * 65536.0);
}
this.numPenSegments = (int) (3.14159f * lineWidth / 65536.0f);
if (pen_dx == null || pen_dx.length < numPenSegments) {
this.pen_dx = new int[numPenSegments];
this.pen_dy = new int[numPenSegments];
this.penIncluded = new boolean[numPenSegments];
this.join = new int[2 * numPenSegments];
}
for (int i = 0; i < numPenSegments; i++) {
double r = lineWidth / 2.0;
double theta = i * 2 * Math.PI / numPenSegments;
double cos = Math.cos(theta);
double sin = Math.sin(theta);
pen_dx[i] = (int) (r * (dm00 * cos + dm01 * sin));
pen_dy[i] = (int) (r * (dm10 * cos + dm11 * sin));
}
prev = LinePath.SEG_CLOSE;
rindex = 0;
started = false;
lineToOrigin = false;
}
private void computeOffset(int x0, int y0, int x1, int y1, int[] m) {
long lx = (long) x1 - (long) x0;
long ly = (long) y1 - (long) y0;
int dx, dy;
if (m00 > 0 && m00 == m11 && m01 == 0 & m10 == 0) {
long ilen = LinePath.hypot(lx, ly);
if (ilen == 0) {
dx = dy = 0;
} else {
dx = (int) ((ly * scaledLineWidth2) / ilen);
dy = (int) (-(lx * scaledLineWidth2) / ilen);
}
} else {
double dlx = x1 - x0;
double dly = y1 - y0;
double det = (double) m00 * m11 - (double) m01 * m10;
int sdet = (det > 0) ? 1 : -1;
double a = dly * m00 - dlx * m10;
double b = dly * m01 - dlx * m11;
double dh = LinePath.hypot(a, b);
double div = sdet * lineWidth2 / (65536.0 * dh);
double ddx = dly * m00_2_m01_2 - dlx * m00_m10_m01_m11;
double ddy = dly * m00_m10_m01_m11 - dlx * m10_2_m11_2;
dx = (int) (ddx * div);
dy = (int) (ddy * div);
}
m[0] = dx;
m[1] = dy;
}
private void ensureCapacity(int newrindex) {
if (reverse.length < newrindex) {
int[] tmp = new int[Math.max(newrindex, 6 * reverse.length / 5)];
System.arraycopy(reverse, 0, tmp, 0, rindex);
this.reverse = tmp;
}
}
private boolean isCCW(int x0, int y0, int x1, int y1, int x2, int y2) {
int dx0 = x1 - x0;
int dy0 = y1 - y0;
int dx1 = x2 - x1;
int dy1 = y2 - y1;
return (long) dx0 * dy1 < (long) dy0 * dx1;
}
private boolean side(int x, int y, int x0, int y0, int x1, int y1) {
long lx = x;
long ly = y;
long lx0 = x0;
long ly0 = y0;
long lx1 = x1;
long ly1 = y1;
return (ly0 - ly1) * lx + (lx1 - lx0) * ly + (lx0 * ly1 - lx1 * ly0) > 0;
}
private int computeRoundJoin(int cx, int cy, int xa, int ya, int xb, int yb,
int side, boolean flip, int[] join) {
int px, py;
int ncoords = 0;
boolean centerSide;
if (side == 0) {
centerSide = side(cx, cy, xa, ya, xb, yb);
} else {
centerSide = (side == 1) ? true : false;
}
for (int i = 0; i < numPenSegments; i++) {
px = cx + pen_dx[i];
py = cy + pen_dy[i];
boolean penSide = side(px, py, xa, ya, xb, yb);
if (penSide != centerSide) {
penIncluded[i] = true;
} else {
penIncluded[i] = false;
}
}
int start = -1, end = -1;
for (int i = 0; i < numPenSegments; i++) {
if (penIncluded[i]
&& !penIncluded[(i + numPenSegments - 1) % numPenSegments]) {
start = i;
}
if (penIncluded[i] && !penIncluded[(i + 1) % numPenSegments]) {
end = i;
}
}
if (end < start) {
end += numPenSegments;
}
if (start != -1 && end != -1) {
long dxa = cx + pen_dx[start] - xa;
long dya = cy + pen_dy[start] - ya;
long dxb = cx + pen_dx[start] - xb;
long dyb = cy + pen_dy[start] - yb;
boolean rev = (dxa * dxa + dya * dya > dxb * dxb + dyb * dyb);
int i = rev ? end : start;
int incr = rev ? -1 : 1;
while (true) {
int idx = i % numPenSegments;
px = cx + pen_dx[idx];
py = cy + pen_dy[idx];
join[ncoords++] = px;
join[ncoords++] = py;
if (i == (rev ? start : end)) {
break;
}
i += incr;
}
}
return ncoords / 2;
}
private static final long ROUND_JOIN_THRESHOLD = 1000L;
private static final long ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000L;
private void drawRoundJoin(int x, int y, int omx, int omy, int mx, int my,
int side, boolean flip, boolean rev, long threshold) {
if ((omx == 0 && omy == 0) || (mx == 0 && my == 0)) {
return;
}
long domx = (long) omx - mx;
long domy = (long) omy - my;
long len = domx * domx + domy * domy;
if (len < threshold) {
return;
}
if (rev) {
omx = -omx;
omy = -omy;
mx = -mx;
my = -my;
}
int bx0 = x + omx;
int by0 = y + omy;
int bx1 = x + mx;
int by1 = y + my;
int npoints = computeRoundJoin(x, y, bx0, by0, bx1, by1, side, flip, join);
for (int i = 0; i < npoints; i++) {
emitLineTo(join[2 * i], join[2 * i + 1], rev);
}
}
// Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
// and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
private void computeMiter(int ix0, int iy0, int ix1, int iy1, int ix0p,
int iy0p, int ix1p, int iy1p, int[] m) {
long x0 = ix0;
long y0 = iy0;
long x1 = ix1;
long y1 = iy1;
long x0p = ix0p;
long y0p = iy0p;
long x1p = ix1p;
long y1p = iy1p;
long x10 = x1 - x0;
long y10 = y1 - y0;
long x10p = x1p - x0p;
long y10p = y1p - y0p;
long den = (x10 * y10p - x10p * y10) >> 16;
if (den == 0) {
m[0] = ix0;
m[1] = iy0;
return;
}
long t = (x1p * (y0 - y0p) - x0 * y10p + x0p * (y1p - y0)) >> 16;
m[0] = (int) (x0 + (t * x10) / den);
m[1] = (int) (y0 + (t * y10) / den);
}
private void drawMiter(int px0, int py0, int x0, int y0, int x1, int y1,
int omx, int omy, int mx, int my, boolean rev) {
if (mx == omx && my == omy) {
return;
}
if (px0 == x0 && py0 == y0) {
return;
}
if (x0 == x1 && y0 == y1) {
return;
}
if (rev) {
omx = -omx;
omy = -omy;
mx = -mx;
my = -my;
}
computeMiter(px0 + omx, py0 + omy, x0 + omx, y0 + omy, x0 + mx, y0 + my, x1
+ mx, y1 + my, miter);
// Compute miter length in untransformed coordinates
long dx = (long) miter[0] - x0;
long dy = (long) miter[1] - y0;
long a = (dy * m00 - dx * m10) >> 16;
long b = (dy * m01 - dx * m11) >> 16;
long lenSq = a * a + b * b;
if (lenSq < miterLimitSq) {
emitLineTo(miter[0], miter[1], rev);
}
}
public void moveTo(int x0, int y0) {
// System.out.println("LineStroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
if (lineToOrigin) {
// not closing the path, do the previous lineTo
lineToImpl(sx0, sy0, joinToOrigin);
lineToOrigin = false;
}
if (prev == LinePath.SEG_LINETO) {
finish();
}
this.sx0 = this.x0 = x0;
this.sy0 = this.y0 = y0;
this.rindex = 0;
this.started = false;
this.joinSegment = false;
this.prev = LinePath.SEG_MOVETO;
}
boolean joinSegment = false;
public void lineJoin() {
// System.out.println("LineStroker.lineJoin()");
this.joinSegment = true;
}
public void lineTo(int x1, int y1) {
// System.out.println("LineStroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
if (lineToOrigin) {
if (x1 == sx0 && y1 == sy0) {
// staying in the starting point
return;
}
// not closing the path, do the previous lineTo
lineToImpl(sx0, sy0, joinToOrigin);
lineToOrigin = false;
} else if (x1 == x0 && y1 == y0) {
return;
} else if (x1 == sx0 && y1 == sy0) {
lineToOrigin = true;
joinToOrigin = joinSegment;
joinSegment = false;
return;
}
lineToImpl(x1, y1, joinSegment);
joinSegment = false;
}
private void lineToImpl(int x1, int y1, boolean joinSegment) {
computeOffset(x0, y0, x1, y1, offset);
int mx = offset[0];
int my = offset[1];
if (!started) {
emitMoveTo(x0 + mx, y0 + my);
this.sx1 = x1;
this.sy1 = y1;
this.mx0 = mx;
this.my0 = my;
started = true;
} else {
boolean ccw = isCCW(px0, py0, x0, y0, x1, y1);
if (joinSegment) {
if (joinStyle == LinePath.JOIN_MITER) {
drawMiter(px0, py0, x0, y0, x1, y1, omx, omy, mx, my, ccw);
} else if (joinStyle == LinePath.JOIN_ROUND) {
drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
ROUND_JOIN_THRESHOLD);
}
} else {
// Draw internal joins as round
drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
ROUND_JOIN_INTERNAL_THRESHOLD);
}
emitLineTo(x0, y0, !ccw);
}
emitLineTo(x0 + mx, y0 + my, false);
emitLineTo(x1 + mx, y1 + my, false);
emitLineTo(x0 - mx, y0 - my, true);
emitLineTo(x1 - mx, y1 - my, true);
// lx0 = x1 + mx;
// ly0 = y1 + my;
// lx0p = x1 - mx;
// ly0p = y1 - my;
// lx1 = x1;
// ly1 = y1;
this.omx = mx;
this.omy = my;
this.px0 = x0;
this.py0 = y0;
this.x0 = x1;
this.y0 = y1;
this.prev = LinePath.SEG_LINETO;
}
public void close() {
// System.out.println("LineStroker.close()");
if (lineToOrigin) {
// ignore the previous lineTo
lineToOrigin = false;
}
if (!started) {
finish();
return;
}
computeOffset(x0, y0, sx0, sy0, offset);
int mx = offset[0];
int my = offset[1];
// Draw penultimate join
boolean ccw = isCCW(px0, py0, x0, y0, sx0, sy0);
if (joinSegment) {
if (joinStyle == LinePath.JOIN_MITER) {
drawMiter(px0, py0, x0, y0, sx0, sy0, omx, omy, mx, my, ccw);
} else if (joinStyle == LinePath.JOIN_ROUND) {
drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
ROUND_JOIN_THRESHOLD);
}
} else {
// Draw internal joins as round
drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
ROUND_JOIN_INTERNAL_THRESHOLD);
}
emitLineTo(x0 + mx, y0 + my);
emitLineTo(sx0 + mx, sy0 + my);
ccw = isCCW(x0, y0, sx0, sy0, sx1, sy1);
// Draw final join on the outside
if (!ccw) {
if (joinStyle == LinePath.JOIN_MITER) {
drawMiter(x0, y0, sx0, sy0, sx1, sy1, mx, my, mx0, my0, false);
} else if (joinStyle == LinePath.JOIN_ROUND) {
drawRoundJoin(sx0, sy0, mx, my, mx0, my0, 0, false, false,
ROUND_JOIN_THRESHOLD);
}
}
emitLineTo(sx0 + mx0, sy0 + my0);
emitLineTo(sx0 - mx0, sy0 - my0); // same as reverse[0], reverse[1]
// Draw final join on the inside
if (ccw) {
if (joinStyle == LinePath.JOIN_MITER) {
drawMiter(x0, y0, sx0, sy0, sx1, sy1, -mx, -my, -mx0, -my0, false);
} else if (joinStyle == LinePath.JOIN_ROUND) {
drawRoundJoin(sx0, sy0, -mx, -my, -mx0, -my0, 0, true, false,
ROUND_JOIN_THRESHOLD);
}
}
emitLineTo(sx0 - mx, sy0 - my);
emitLineTo(x0 - mx, y0 - my);
for (int i = rindex - 2; i >= 0; i -= 2) {
emitLineTo(reverse[i], reverse[i + 1]);
}
this.x0 = this.sx0;
this.y0 = this.sy0;
this.rindex = 0;
this.started = false;
this.joinSegment = false;
this.prev = LinePath.SEG_CLOSE;
emitClose();
}
public void end() {
// System.out.println("LineStroker.end()");
if (lineToOrigin) {
// not closing the path, do the previous lineTo
lineToImpl(sx0, sy0, joinToOrigin);
lineToOrigin = false;
}
if (prev == LinePath.SEG_LINETO) {
finish();
}
output.end();
this.joinSegment = false;
this.prev = LinePath.SEG_MOVETO;
}
long lineLength(long ldx, long ldy) {
long ldet = ((long) m00 * m11 - (long) m01 * m10) >> 16;
long la = (ldy * m00 - ldx * m10) / ldet;
long lb = (ldy * m01 - ldx * m11) / ldet;
long llen = (int) LinePath.hypot(la, lb);
return llen;
}
private void finish() {
if (capStyle == LinePath.CAP_ROUND) {
drawRoundJoin(x0, y0, omx, omy, -omx, -omy, 1, false, false,
ROUND_JOIN_THRESHOLD);
} else if (capStyle == LinePath.CAP_SQUARE) {
long ldx = px0 - x0;
long ldy = py0 - y0;
long llen = lineLength(ldx, ldy);
if (0 < llen) {
long s = (long) lineWidth2 * 65536 / llen;
int capx = x0 - (int) (ldx * s >> 16);
int capy = y0 - (int) (ldy * s >> 16);
emitLineTo(capx + omx, capy + omy);
emitLineTo(capx - omx, capy - omy);
}
}
for (int i = rindex - 2; i >= 0; i -= 2) {
emitLineTo(reverse[i], reverse[i + 1]);
}
this.rindex = 0;
if (capStyle == LinePath.CAP_ROUND) {
drawRoundJoin(sx0, sy0, -mx0, -my0, mx0, my0, 1, false, false,
ROUND_JOIN_THRESHOLD);
} else if (capStyle == LinePath.CAP_SQUARE) {
long ldx = sx1 - sx0;
long ldy = sy1 - sy0;
long llen = lineLength(ldx, ldy);
if (0 < llen) {
long s = (long) lineWidth2 * 65536 / llen;
int capx = sx0 - (int) (ldx * s >> 16);
int capy = sy0 - (int) (ldy * s >> 16);
emitLineTo(capx - mx0, capy - my0);
emitLineTo(capx + mx0, capy + my0);
}
}
emitClose();
this.joinSegment = false;
}
private void emitMoveTo(int x0, int y0) {
// System.out.println("LineStroker.emitMoveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
output.moveTo(x0, y0);
}
private void emitLineTo(int x1, int y1) {
// System.out.println("LineStroker.emitLineTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
output.lineTo(x1, y1);
}
private void emitLineTo(int x1, int y1, boolean rev) {
if (rev) {
ensureCapacity(rindex + 2);
reverse[rindex++] = x1;
reverse[rindex++] = y1;
} else {
emitLineTo(x1, y1);
}
}
private void emitClose() {
// System.out.println("LineStroker.emitClose()");
output.close();
}
}
@@ -1,376 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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 as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
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.opengl;
import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PFont;
import processing.core.PImage;
import java.util.HashMap;
/**
* All the infrastructure needed for optimized font rendering
* in OpenGL. Basically, this special class is needed because
* fonts in Processing are handled by a separate PImage for each
* gyph. For performance reasons, all these glyphs should be
* stored in a single OpenGL texture (otherwise, rendering a
* string of text would involve binding and unbinding several
* textures.
* PFontTexture manages the correspondence between individual
* glyphs and the large OpenGL texture containing them. Also,
* in the case that the font size is very large, one single
* OpenGL texture might not be enough to store all the glyphs,
* so PFontTexture also takes care of spreading a single font
* over several textures.
* By Andres Colubri
*
*/
class PFontTexture implements PConstants {
protected PApplet parent;
protected PGraphicsOpenGL pg;
protected PGL pgl;
protected PFont font;
protected boolean is3D;
protected int maxTexWidth;
protected int maxTexHeight;
protected int offsetX;
protected int offsetY;
protected int lineHeight;
protected Texture[] textures = null;
protected PImage[] images = null;
protected int currentTex;
protected int lastTex;
protected TextureInfo[] glyphTexinfos;
protected HashMap<PFont.Glyph, TextureInfo> texinfoMap;
public PFontTexture(PApplet parent, PFont font, int maxw, int maxh, boolean is3D) {
this.parent = parent;
this.font = font;
pg = (PGraphicsOpenGL)parent.g;
pgl = pg.pgl;
this.is3D = is3D;
initTexture(maxw, maxh);
}
protected void allocate() {
// Nothing to do here: the font textures will allocate
// themselves.
}
protected void initTexture(int w, int h) {
maxTexWidth = w;
maxTexHeight = h;
currentTex = -1;
lastTex = -1;
addTexture();
offsetX = 0;
offsetY = 0;
lineHeight = 0;
texinfoMap = new HashMap<PFont.Glyph, TextureInfo>();
glyphTexinfos = new TextureInfo[font.getGlyphCount()];
addAllGlyphsToTexture();
}
public boolean addTexture() {
int w, h;
boolean resize;
w = maxTexWidth;
if (-1 < currentTex && textures[currentTex].glHeight < maxTexHeight) {
// The height of the current texture is less than the maximum, this
// means we can replace it with a larger texture.
h = PApplet.min(2 * textures[currentTex].glHeight, maxTexHeight);
resize = true;
} else {
h = PApplet.min(PGraphicsOpenGL.maxTextureSize, PGL.MAX_FONT_TEX_SIZE / 2, maxTexHeight / 4);
resize = false;
}
Texture tex;
if (is3D) {
// Bilinear sampling ensures that the texture doesn't look pixelated either
// when it is magnified or minified...
tex = new Texture(parent, w, h, new Texture.Parameters(ARGB, Texture.BILINEAR, false));
} else {
// ...however, the effect of bilinear sampling is to add some blurriness to the text
// in its original size. In 2D, we assume that text will be shown at its original
// size, so linear sampling is chosen instead (which only affects minimized text).
tex = new Texture(parent, w, h, new Texture.Parameters(ARGB, Texture.LINEAR, false));
}
if (textures == null) {
textures = new Texture[1];
textures[0] = tex;
images = new PImage[1];
images[0] = pg.wrapTexture(tex);
currentTex = 0;
} else if (resize) {
// Replacing old smaller texture with larger one.
// But first we must copy the contents of the older
// texture into the new one.
Texture tex0 = textures[currentTex];
tex.put(tex0);
textures[currentTex] = tex;
images[currentTex].setCache(pg, tex);
images[currentTex].width = tex.width;
images[currentTex].height = tex.height;
} else {
// Adding new texture to the list.
Texture[] tempTex = textures;
textures = new Texture[textures.length + 1];
PApplet.arrayCopy(tempTex, textures, tempTex.length);
textures[tempTex.length] = tex;
currentTex = textures.length - 1;
PImage[] tempImg = images;
images = new PImage[textures.length + 1];
PApplet.arrayCopy(tempImg, images, tempImg.length);
images[tempImg.length] = pg.wrapTexture(tex);
}
lastTex = currentTex;
// Make sure that the current texture is bound.
//tex.bind();
return resize;
}
public void setFirstTexture() {
setTexture(0);
}
public void setTexture(int idx) {
if (0 <= idx && idx < textures.length) {
currentTex = idx;
}
}
public PImage getTexture(int idx) {
if (0 <= idx && idx < images.length) {
return images[idx];
}
return null;
}
public PImage getCurrentTexture() {
return getTexture(currentTex);
}
// Add all the current glyphs to opengl texture.
public void addAllGlyphsToTexture() {
// loop over current glyphs.
for (int i = 0; i < font.getGlyphCount(); i++) {
addToTexture(i, font.getGlyph(i));
}
}
public void updateGlyphsTexCoords() {
// loop over current glyphs.
for (int i = 0; i < glyphTexinfos.length; i++) {
TextureInfo tinfo = glyphTexinfos[i];
if (tinfo != null && tinfo.texIndex == currentTex) {
tinfo.updateUV();
}
}
}
public TextureInfo getTexInfo(PFont.Glyph glyph) {
TextureInfo info = texinfoMap.get(glyph);
return info;
}
public TextureInfo addToTexture(PFont.Glyph glyph) {
int n = glyphTexinfos.length;
if (n == 0) {
glyphTexinfos = new TextureInfo[1];
}
addToTexture(n, glyph);
return glyphTexinfos[n];
}
public boolean contextIsOutdated() {
boolean outdated = false;
for (int i = 0; i < textures.length; i++) {
if (textures[i].contextIsOutdated()) {
outdated = true;
}
}
if (outdated) {
for (int i = 0; i < textures.length; i++) {
pg.removeTextureObject(textures[i].glName, textures[i].context.code());
textures[i].glName = 0;
}
}
return outdated;
}
// Adds this glyph to the opengl texture in PFont.
protected void addToTexture(int idx, PFont.Glyph glyph) {
// We add one pixel to avoid issues when sampling the font texture at fractional
// screen positions. I.e.: the pixel on the screen only contains half of the
// font rectangle, so it would sample half of the color from the glyph
// area in the texture, and the other half from the contiguous pixel. If the
// later contains a portion of the neighbor glyph and the former doesn't, this
// would result in a shaded pixel when the correct output is blank.
// This is a consequence of putting all the glyphs in a common texture with
// bilinear sampling.
int w = 1 + glyph.width + 1;
int h = 1 + glyph.height + 1;
// Converting the pixels array from the PImage into a valid RGBA array for OpenGL.
int[] rgba = new int[w * h];
int t = 0;
int p = 0;
if (PGL.BIG_ENDIAN) {
java.util.Arrays.fill(rgba, 0, w, 0xFFFFFF00); // Set the first row to blank pixels.
t = w;
for (int y = 0; y < glyph.height; y++) {
rgba[t++] = 0xFFFFFF00; // Set the leftmost pixel in this row as blank
for (int x = 0; x < glyph.width; x++) {
rgba[t++] = 0xFFFFFF00 | glyph.image.pixels[p++];
}
rgba[t++] = 0xFFFFFF00; // Set the rightmost pixel in this row as blank
}
java.util.Arrays.fill(rgba, (h - 1) * w, h * w, 0xFFFFFF00); // Set the last row to blank pixels.
} else {
java.util.Arrays.fill(rgba, 0, w, 0x00FFFFFF); // Set the first row to blank pixels.
t = w;
for (int y = 0; y < glyph.height; y++) {
rgba[t++] = 0x00FFFFFF; // Set the leftmost pixel in this row as blank
for (int x = 0; x < glyph.width; x++) {
rgba[t++] = (glyph.image.pixels[p++] << 24) | 0x00FFFFFF;
}
rgba[t++] = 0x00FFFFFF; // Set the rightmost pixel in this row as blank
}
java.util.Arrays.fill(rgba, (h - 1) * w, h * w, 0x00FFFFFF); // Set the last row to blank pixels.
}
// Is there room for this glyph in the current line?
if (offsetX + w > textures[currentTex].glWidth) {
// No room, go to the next line:
offsetX = 0;
offsetY += lineHeight;
lineHeight = 0;
}
lineHeight = Math.max(lineHeight, h);
boolean resized = false;
if (offsetY + lineHeight > textures[currentTex].glHeight) {
// We run out of space in the current texture, so we add a new texture:
resized = addTexture();
if (resized) {
// Because the current texture has been resized, we need to
// update the UV coordinates of all the glyphs associated to it:
updateGlyphsTexCoords();
} else {
// A new texture has been created. Reseting texture coordinates
// and line.
offsetX = 0;
offsetY = 0;
lineHeight = 0;
}
}
if (lastTex == -1) {
lastTex = 0;
}
if (currentTex != lastTex || resized) {
currentTex = idx;
}
TextureInfo tinfo = new TextureInfo(currentTex, offsetX, offsetY, w, h, rgba);
offsetX += w;
if (idx == glyphTexinfos.length) {
TextureInfo[] temp = new TextureInfo[glyphTexinfos.length + 1];
System.arraycopy(glyphTexinfos, 0, temp, 0, glyphTexinfos.length);
glyphTexinfos = temp;
}
glyphTexinfos[idx] = tinfo;
texinfoMap.put(glyph, tinfo);
}
public class TextureInfo {
public int texIndex;
public int width;
public int height;
public int[] crop;
public float u0, u1;
public float v0, v1;
public int[] pixels;
public TextureInfo(int tidx, int cropX, int cropY, int cropW, int cropH, int[] pix) {
texIndex = tidx;
crop = new int[4];
// The region of the texture corresponding to the glyph is surrounded by a
// 1-pixel wide border to avoid artifacts due to bilinear sampling. This is
// why the additions and subtractions to the crop values.
crop[0] = cropX + 1;
crop[1] = cropY + 1 + cropH - 2;
crop[2] = cropW - 2;
crop[3] = -cropH + 2;
pixels = pix;
updateUV();
updateTex();
}
void updateUV() {
width = textures[texIndex].glWidth;
height = textures[texIndex].glHeight;
u0 = (float)crop[0] / (float)width;
u1 = u0 + (float)crop[2] / (float)width;
v0 = (float)(crop[1] + crop[3]) / (float)height;
v1 = v0 - (float)crop[3] / (float)height;
}
void updateTex() {
textures[texIndex].setNative(pixels, 0, crop[0] - 1, crop[1] + crop[3] - 1, crop[2] + 2, -crop[3] + 2);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,552 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012 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.opengl;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PMatrix3D;
import processing.core.PShape;
import processing.core.PShapeSVG;
import processing.data.XML;
public class PGraphics2D extends PGraphicsOpenGL {
public PGraphics2D() {
super();
hints[ENABLE_PERSPECTIVE_CORRECTED_LINES] = false;
}
//////////////////////////////////////////////////////////////
// RENDERER SUPPORT QUERIES
public boolean is2D() {
return true;
}
public boolean is3D() {
return false;
}
//////////////////////////////////////////////////////////////
// HINTS
public void hint(int which) {
if (which == ENABLE_PERSPECTIVE_CORRECTED_LINES) {
showWarning("2D lines cannot be perspective-corrected.");
return;
}
super.hint(which);
}
//////////////////////////////////////////////////////////////
// PROJECTION
public void ortho() {
showMethodWarning("ortho");
}
public void ortho(float left, float right,
float bottom, float top) {
showMethodWarning("ortho");
}
public void ortho(float left, float right,
float bottom, float top,
float near, float far) {
showMethodWarning("ortho");
}
public void perspective() {
showMethodWarning("perspective");
}
public void perspective(float fov, float aspect, float zNear, float zFar) {
showMethodWarning("perspective");
}
public void frustum(float left, float right, float bottom, float top,
float znear, float zfar) {
showMethodWarning("frustum");
}
protected void defaultPerspective() {
super.ortho(-width/2, +width/2, -height/2, +height/2, -1, +1);
}
//////////////////////////////////////////////////////////////
// CAMERA
public void beginCamera() {
showMethodWarning("beginCamera");
}
public void endCamera() {
showMethodWarning("endCamera");
}
public void camera() {
showMethodWarning("camera");
}
public void camera(float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ) {
showMethodWarning("camera");
}
protected void defaultCamera() {
super.camera(width/2, height/2);
}
//////////////////////////////////////////////////////////////
// MATRIX MORE!
protected void begin2D() {
pushProjection();
defaultPerspective();
pushMatrix();
defaultCamera();
}
protected void end2D() {
popMatrix();
popProjection();
}
//////////////////////////////////////////////////////////////
// SHAPE
public void shape(PShape shape) {
if (shape.is2D()) {
super.shape(shape);
} else {
showWarning("The shape object is not 2D, cannot be displayed with this renderer");
}
}
public void shape(PShape shape, float x, float y) {
if (shape.is2D()) {
super.shape(shape, x, y);
} else {
showWarning("The shape object is not 2D, cannot be displayed with this renderer");
}
}
public void shape(PShape shape, float a, float b, float c, float d) {
if (shape.is2D()) {
super.shape(shape, a, b, c, d);
} else {
showWarning("The shape object is not 2D, cannot be displayed with this renderer");
}
}
public void shape(PShape shape, float x, float y, float z) {
showDepthWarningXYZ("shape");
}
public void shape(PShape shape, float x, float y, float z, float c, float d, float e) {
showDepthWarningXYZ("shape");
}
//////////////////////////////////////////////////////////////
// SHAPE I/O
static protected boolean isSupportedExtension(String extension) {
return extension.equals("svg") || extension.equals("svgz");
}
static protected PShape2D loadShapeImpl(PGraphics pg, String filename, String extension) {
PShapeSVG svg = null;
if (extension.equals("svg")) {
svg = new PShapeSVG(pg.parent, filename);
} else if (extension.equals("svgz")) {
try {
InputStream input = new GZIPInputStream(pg.parent.createInput(filename));
XML xml = new XML(PApplet.createReader(input));
svg = new PShapeSVG(xml);
} catch (IOException e) {
e.printStackTrace();
}
}
if (svg != null) {
PShape2D p2d = PShape2D.createShape(pg.parent, svg);
return p2d;
} else {
return null;
}
}
//////////////////////////////////////////////////////////////
// SHAPE CREATION
public PShape createShape(PShape source) {
return PShape2D.createShape(parent, source);
}
public PShape createShape() {
return createShape(POLYGON);
}
public PShape createShape(int type) {
return createShapeImpl(parent, type);
}
public PShape createShape(int kind, float... p) {
return createShapeImpl(parent, kind, p);
}
static protected PShape2D createShapeImpl(PApplet parent, int type) {
PShape2D shape = null;
if (type == PShape.GROUP) {
shape = new PShape2D(parent, PShape.GROUP);
} else if (type == PShape.PATH) {
shape = new PShape2D(parent, PShape.PATH);
} else if (type == POINTS) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(POINTS);
} else if (type == LINES) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(LINES);
} else if (type == TRIANGLE || type == TRIANGLES) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(TRIANGLES);
} else if (type == TRIANGLE_FAN) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(TRIANGLE_FAN);
} else if (type == TRIANGLE_STRIP) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(TRIANGLE_STRIP);
} else if (type == QUAD || type == QUADS) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(QUADS);
} else if (type == QUAD_STRIP) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(QUAD_STRIP);
} else if (type == POLYGON) {
shape = new PShape2D(parent, PShape.GEOMETRY);
shape.setKind(POLYGON);
}
return shape;
}
static protected PShape2D createShapeImpl(PApplet parent, int kind, float... p) {
PShape2D shape = null;
int len = p.length;
if (kind == POINT) {
if (len != 2) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(POINT);
} else if (kind == LINE) {
if (len != 4) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(LINE);
} else if (kind == TRIANGLE) {
if (len != 6) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(TRIANGLE);
} else if (kind == QUAD) {
if (len != 8) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(QUAD);
} else if (kind == RECT) {
if (len != 4 && len != 5 && len != 8) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(RECT);
} else if (kind == ELLIPSE) {
if (len != 4) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(ELLIPSE);
} else if (kind == ARC) {
if (len != 6) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape2D(parent, PShape.PRIMITIVE);
shape.setKind(ARC);
} else if (kind == BOX) {
showWarning("Primitive not supported in 2D");
} else if (kind == SPHERE) {
showWarning("Primitive not supported in 2D");
} else {
showWarning("Unrecognized primitive type");
}
if (shape != null) {
shape.setParams(p);
}
return shape;
}
//////////////////////////////////////////////////////////////
// BEZIER VERTICES
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
showDepthWarningXYZ("bezierVertex");
}
//////////////////////////////////////////////////////////////
// QUADRATIC BEZIER VERTICES
public void quadraticVertex(float x2, float y2, float z2,
float x4, float y4, float z4) {
showDepthWarningXYZ("quadVertex");
}
//////////////////////////////////////////////////////////////
// CURVE VERTICES
public void curveVertex(float x, float y, float z) {
showDepthWarningXYZ("curveVertex");
}
//////////////////////////////////////////////////////////////
// BOX
public void box(float w, float h, float d) {
showMethodWarning("box");
}
//////////////////////////////////////////////////////////////
// SPHERE
public void sphere(float r) {
showMethodWarning("sphere");
}
//////////////////////////////////////////////////////////////
// VERTEX SHAPES
public void vertex(float x, float y, float z) {
showDepthWarningXYZ("vertex");
}
public void vertex(float x, float y, float z, float u, float v) {
showDepthWarningXYZ("vertex");
}
//////////////////////////////////////////////////////////////
// MATRIX TRANSFORMATIONS
public void translate(float tx, float ty, float tz) {
showDepthWarningXYZ("translate");
}
public void rotateX(float angle) {
showDepthWarning("rotateX");
}
public void rotateY(float angle) {
showDepthWarning("rotateY");
}
public void rotateZ(float angle) {
showDepthWarning("rotateZ");
}
public void rotate(float angle, float vx, float vy, float vz) {
showVariationWarning("rotate");
}
public void applyMatrix(PMatrix3D source) {
showVariationWarning("applyMatrix");
}
public void applyMatrix(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
showVariationWarning("applyMatrix");
}
public void scale(float sx, float sy, float sz) {
showDepthWarningXYZ("scale");
}
//////////////////////////////////////////////////////////////
// SCREEN AND MODEL COORDS
public float screenX(float x, float y, float z) {
showDepthWarningXYZ("screenX");
return 0;
}
public float screenY(float x, float y, float z) {
showDepthWarningXYZ("screenY");
return 0;
}
public float screenZ(float x, float y, float z) {
showDepthWarningXYZ("screenZ");
return 0;
}
public PMatrix3D getMatrix(PMatrix3D target) {
showVariationWarning("getMatrix");
return target;
}
public void setMatrix(PMatrix3D source) {
showVariationWarning("setMatrix");
}
//////////////////////////////////////////////////////////////
// LIGHTS
public void lights() {
showMethodWarning("lights");
}
public void noLights() {
showMethodWarning("noLights");
}
public void ambientLight(float red, float green, float blue) {
showMethodWarning("ambientLight");
}
public void ambientLight(float red, float green, float blue,
float x, float y, float z) {
showMethodWarning("ambientLight");
}
public void directionalLight(float red, float green, float blue,
float nx, float ny, float nz) {
showMethodWarning("directionalLight");
}
public void pointLight(float red, float green, float blue,
float x, float y, float z) {
showMethodWarning("pointLight");
}
public void spotLight(float red, float green, float blue,
float x, float y, float z,
float nx, float ny, float nz,
float angle, float concentration) {
showMethodWarning("spotLight");
}
public void lightFalloff(float constant, float linear, float quadratic) {
showMethodWarning("lightFalloff");
}
public void lightSpecular(float v1, float v2, float v3) {
showMethodWarning("lightSpecular");
}
}
@@ -1,610 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012 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.opengl;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Hashtable;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PImage;
import processing.core.PShape;
import processing.core.PVector;
public class PGraphics3D extends PGraphicsOpenGL {
//////////////////////////////////////////////////////////////
// RENDERER SUPPORT QUERIES
public boolean is2D() {
return false;
}
public boolean is3D() {
return true;
}
//////////////////////////////////////////////////////////////
// PROJECTION
protected void defaultPerspective() {
perspective();
}
//////////////////////////////////////////////////////////////
// CAMERA
protected void defaultCamera() {
camera();
}
//////////////////////////////////////////////////////////////
// MATRIX MORE!
protected void begin2D() {
pushProjection();
ortho(-width/2, +width/2, -height/2, +height/2, -1, +1);
pushMatrix();
camera(width/2, height/2);
}
protected void end2D() {
popMatrix();
popProjection();
}
//////////////////////////////////////////////////////////////
// SHAPE I/O
static protected boolean isSupportedExtension(String extension) {
return extension.equals("obj");
}
static protected PShape loadShapeImpl(PGraphics pg, String filename, String ext) {
ArrayList<PVector> vertices = new ArrayList<PVector>();
ArrayList<PVector> normals = new ArrayList<PVector>();
ArrayList<PVector> textures = new ArrayList<PVector>();
ArrayList<OBJFace> faces = new ArrayList<OBJFace>();
ArrayList<OBJMaterial> materials = new ArrayList<OBJMaterial>();
BufferedReader reader = pg.parent.createReader(filename);
parseOBJ(pg.parent, reader, vertices, normals, textures, faces, materials);
int prevColorMode = pg.colorMode;
float prevColorModeX = pg.colorModeX;
float prevColorModeY = pg.colorModeY;
float prevColorModeZ = pg.colorModeZ;
float prevColorModeA = pg.colorModeA;
boolean prevStroke = pg.stroke;
int prevTextureMode = pg.textureMode;
pg.colorMode(RGB, 1);
pg.stroke = false;
pg.textureMode = NORMAL;
// The OBJ geometry is stored in a group shape,
// with each face in a separate child geometry
// shape.
PShape root = createShapeImpl(pg.parent, GROUP);
int mtlIdxCur = -1;
OBJMaterial mtl = null;
for (int i = 0; i < faces.size(); i++) {
OBJFace face = faces.get(i);
// Getting current material.
if (mtlIdxCur != face.matIdx) {
mtlIdxCur = PApplet.max(0, face.matIdx); // To make sure that at least we get the default material.
mtl = materials.get(mtlIdxCur);
}
// Creating child shape for current face.
PShape child;
if (face.vertIdx.size() == 3) {
child = createShapeImpl(pg.parent, TRIANGLES); // Face is a triangle, so using appropriate shape kind.
} else if (face.vertIdx.size() == 4) {
child = createShapeImpl(pg.parent, QUADS); // Face is a quad, so using appropriate shape kind.
} else {
child = createShapeImpl(pg.parent, POLYGON); // Face is a general polygon
}
// Setting material properties for the new face
child.fill(mtl.kd.x, mtl.kd.y, mtl.kd.z);
child.ambient(mtl.ka.x, mtl.ka.y, mtl.ka.z);
child.specular(mtl.ks.x, mtl.ks.y, mtl.ks.z);
child.shininess(mtl.ns);
if (mtl.kdMap != null) {
// If current material is textured, then tinting the texture using the diffuse color.
child.tint(mtl.kd.x, mtl.kd.y, mtl.kd.z, mtl.d);
}
for (int j = 0; j < face.vertIdx.size(); j++){
int vertIdx, normIdx;
PVector vert, norms;
vert = norms = null;
vertIdx = face.vertIdx.get(j).intValue() - 1;
vert = vertices.get(vertIdx);
if (j < face.normIdx.size()) {
normIdx = face.normIdx.get(j).intValue() - 1;
if (-1 < normIdx) {
norms = normals.get(normIdx);
}
}
if (mtl != null && mtl.kdMap != null) {
// This face is textured.
int texIdx;
PVector tex = null;
if (j < face.texIdx.size()) {
texIdx = face.texIdx.get(j).intValue() - 1;
if (-1 < texIdx) {
tex = textures.get(texIdx);
}
}
child.texture(mtl.kdMap);
if (norms != null) {
child.normal(norms.x, norms.y, norms.z);
}
if (tex != null) {
child.vertex(vert.x, vert.y, vert.z, tex.x, tex.y);
} else {
child.vertex(vert.x, vert.y, vert.z);
}
} else {
// This face is not textured.
if (norms != null) {
child.normal(norms.x, norms.y, norms.z);
}
child.vertex(vert.x, vert.y, vert.z);
}
}
child.end(CLOSE);
root.addChild(child);
}
pg.colorMode(prevColorMode, prevColorModeX, prevColorModeY, prevColorModeZ, prevColorModeA);
pg.stroke = prevStroke;
pg.textureMode = prevTextureMode;
return root;
}
//////////////////////////////////////////////////////////////
// SHAPE CREATION
public PShape createShape(PShape source) {
return PShape3D.createShape(parent, source);
}
public PShape createShape() {
return createShape(POLYGON);
}
public PShape createShape(int type) {
return createShapeImpl(parent, type);
}
public PShape createShape(int kind, float... p) {
return createShapeImpl(parent, kind, p);
}
static protected PShape3D createShapeImpl(PApplet parent, int type) {
PShape3D shape = null;
if (type == PShape.GROUP) {
shape = new PShape3D(parent, PShape.GROUP);
} else if (type == PShape.PATH) {
shape = new PShape3D(parent, PShape.PATH);
} else if (type == POINTS) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(POINTS);
} else if (type == LINES) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(LINES);
} else if (type == TRIANGLE || type == TRIANGLES) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(TRIANGLES);
} else if (type == TRIANGLE_FAN) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(TRIANGLE_FAN);
} else if (type == TRIANGLE_STRIP) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(TRIANGLE_STRIP);
} else if (type == QUAD || type == QUADS) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(QUADS);
} else if (type == QUAD_STRIP) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(QUAD_STRIP);
} else if (type == POLYGON) {
shape = new PShape3D(parent, PShape.GEOMETRY);
shape.setKind(POLYGON);
}
return shape;
}
static protected PShape3D createShapeImpl(PApplet parent, int kind, float... p) {
PShape3D shape = null;
int len = p.length;
if (kind == POINT) {
if (len != 2 && len != 3) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(POINT);
} else if (kind == LINE) {
if (len != 4 && len != 6) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(LINE);
} else if (kind == TRIANGLE) {
if (len != 6) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(TRIANGLE);
} else if (kind == QUAD) {
if (len != 8) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(QUAD);
} else if (kind == RECT) {
if (len != 4 && len != 5 && len != 8) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(RECT);
} else if (kind == ELLIPSE) {
if (len != 4) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(ELLIPSE);
} else if (kind == ARC) {
if (len != 6) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(ARC);
} else if (kind == BOX) {
if (len != 1 && len != 3) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(BOX);
} else if (kind == SPHERE) {
if (len != 1) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShape3D(parent, PShape.PRIMITIVE);
shape.setKind(SPHERE);
} else {
showWarning("Unrecognized primitive type");
}
if (shape != null) {
shape.setParams(p);
}
return shape;
}
//////////////////////////////////////////////////////////////
// OBJ LOADING
static protected void parseOBJ(PApplet parent,
BufferedReader reader, ArrayList<PVector> vertices,
ArrayList<PVector> normals,
ArrayList<PVector> textures,
ArrayList<OBJFace> faces,
ArrayList<OBJMaterial> materials) {
Hashtable<String, Integer> mtlTable = new Hashtable<String, Integer>();
int mtlIdxCur = -1;
boolean readv, readvn, readvt;
try {
readv = readvn = readvt = false;
String line;
String gname = "object";
while ((line = reader.readLine()) != null) {
// Parse the line.
// The below patch/hack comes from Carlos Tomas Marti and is a
// fix for single backslashes in Rhino obj files
// BEGINNING OF RHINO OBJ FILES HACK
// Statements can be broken in multiple lines using '\' at the
// end of a line.
// In regular expressions, the backslash is also an escape
// character.
// The regular expression \\ matches a single backslash. This
// regular expression as a Java string, becomes "\\\\".
// That's right: 4 backslashes to match a single one.
while (line.contains("\\")) {
line = line.split("\\\\")[0];
final String s = reader.readLine();
if (s != null)
line += s;
}
// END OF RHINO OBJ FILES HACK
String[] elements = line.split("\\s+");
// if not a blank line, process the line.
if (elements.length > 0) {
if (elements[0].equals("v")) {
// vertex
PVector tempv = new PVector(Float.valueOf(elements[1]).floatValue(),
Float.valueOf(elements[2]).floatValue(),
Float.valueOf(elements[3]).floatValue());
vertices.add(tempv);
readv = true;
} else if (elements[0].equals("vn")) {
// normal
PVector tempn = new PVector(Float.valueOf(elements[1]).floatValue(),
Float.valueOf(elements[2]).floatValue(),
Float.valueOf(elements[3]).floatValue());
normals.add(tempn);
readvn = true;
} else if (elements[0].equals("vt")) {
// uv, inverting v to take into account Processing's invertex Y axis with
// respect to OpenGL.
PVector tempv = new PVector(Float.valueOf(elements[1]).floatValue(),
1 - Float.valueOf(elements[2]).floatValue());
textures.add(tempv);
readvt = true;
} else if (elements[0].equals("o")) {
// Object name is ignored, for now.
} else if (elements[0].equals("mtllib")) {
if (elements[1] != null) {
BufferedReader mreader = parent.createReader(elements[1]);
if (mreader != null) {
parseMTL(parent, mreader, materials, mtlTable);
}
}
} else if (elements[0].equals("g")) {
gname = 1 < elements.length ? elements[1] : "";
} else if (elements[0].equals("usemtl")) {
// Getting index of current active material (will be applied on all subsequent faces).
if (elements[1] != null) {
String mtlname = elements[1];
if (mtlTable.containsKey(mtlname)) {
Integer tempInt = mtlTable.get(mtlname);
mtlIdxCur = tempInt.intValue();
} else {
mtlIdxCur = -1;
}
}
} else if (elements[0].equals("f")) {
// Face setting
OBJFace face = new OBJFace();
face.matIdx = mtlIdxCur;
face.name = gname;
for (int i = 1; i < elements.length; i++) {
String seg = elements[i];
if (seg.indexOf("/") > 0) {
String[] forder = seg.split("/");
if (forder.length > 2) {
// Getting vertex and texture and normal indexes.
if (forder[0].length() > 0 && readv) {
face.vertIdx.add(Integer.valueOf(forder[0]));
}
if (forder[1].length() > 0 && readvt) {
face.texIdx.add(Integer.valueOf(forder[1]));
}
if (forder[2].length() > 0 && readvn) {
face.normIdx.add(Integer.valueOf(forder[2]));
}
} else if (forder.length > 1) {
// Getting vertex and texture/normal indexes.
if (forder[0].length() > 0 && readv) {
face.vertIdx.add(Integer.valueOf(forder[0]));
}
if (forder[1].length() > 0) {
if (readvt) {
face.texIdx.add(Integer.valueOf(forder[1]));
} else if (readvn) {
face.normIdx.add(Integer.valueOf(forder[1]));
}
}
} else if (forder.length > 0) {
// Getting vertex index only.
if (forder[0].length() > 0 && readv) {
face.vertIdx.add(Integer.valueOf(forder[0]));
}
}
} else {
// Getting vertex index only.
if (seg.length() > 0 && readv) {
face.vertIdx.add(Integer.valueOf(seg));
}
}
}
faces.add(face);
}
}
}
if (materials.size() == 0) {
// No materials definition so far. Adding one default material.
OBJMaterial defMtl = new OBJMaterial();
materials.add(defMtl);
}
} catch (Exception e) {
e.printStackTrace();
}
}
static protected void parseMTL(PApplet parent,
BufferedReader reader, ArrayList<OBJMaterial> materials,
Hashtable<String, Integer> materialsHash) {
try {
String line;
OBJMaterial currentMtl = null;
while ((line = reader.readLine()) != null) {
// Parse the line
line = line.trim();
String elements[] = line.split("\\s+");
if (elements.length > 0) {
// Extract the material data.
if (elements[0].equals("newmtl")) {
// Starting new material.
String mtlname = elements[1];
currentMtl = new OBJMaterial(mtlname);
materialsHash.put(mtlname, new Integer(materials.size()));
materials.add(currentMtl);
} else if (elements[0].equals("map_Kd") && elements.length > 1) {
// Loading texture map.
String texname = elements[1];
currentMtl.kdMap = parent.loadImage(texname);
} else if (elements[0].equals("Ka") && elements.length > 3) {
// The ambient color of the material
currentMtl.ka.x = Float.valueOf(elements[1]).floatValue();
currentMtl.ka.y = Float.valueOf(elements[2]).floatValue();
currentMtl.ka.z = Float.valueOf(elements[3]).floatValue();
} else if (elements[0].equals("Kd") && elements.length > 3) {
// The diffuse color of the material
currentMtl.kd.x = Float.valueOf(elements[1]).floatValue();
currentMtl.kd.y = Float.valueOf(elements[2]).floatValue();
currentMtl.kd.z = Float.valueOf(elements[3]).floatValue();
} else if (elements[0].equals("Ks") && elements.length > 3) {
// The specular color weighted by the specular coefficient
currentMtl.ks.x = Float.valueOf(elements[1]).floatValue();
currentMtl.ks.y = Float.valueOf(elements[2]).floatValue();
currentMtl.ks.z = Float.valueOf(elements[3]).floatValue();
} else if ((elements[0].equals("d") || elements[0].equals("Tr")) && elements.length > 1) {
// Reading the alpha transparency.
currentMtl.d = Float.valueOf(elements[1]).floatValue();
} else if (elements[0].equals("Ns") && elements.length > 1) {
// The specular component of the Phong shading model
currentMtl.ns = Float.valueOf(elements[1]).floatValue();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Stores a face from an OBJ file
static protected class OBJFace {
ArrayList<Integer> vertIdx;
ArrayList<Integer> texIdx;
ArrayList<Integer> normIdx;
int matIdx;
String name;
OBJFace() {
vertIdx = new ArrayList<Integer>();
texIdx = new ArrayList<Integer>();
normIdx = new ArrayList<Integer>();
matIdx = -1;
name = "";
}
}
// Stores a material defined in an MTL file.
static protected class OBJMaterial {
String name;
PVector ka;
PVector kd;
PVector ks;
float d;
float ns;
PImage kdMap;
OBJMaterial() {
this("default");
}
OBJMaterial(String name) {
this.name = name;
ka = new PVector(0.5f, 0.5f, 0.5f);
kd = new PVector(0.5f, 0.5f, 0.5f);
ks = new PVector(0.5f, 0.5f, 0.5f);
d = 1.0f;
ns = 0.0f;
kdMap = null;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,796 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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 as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
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.opengl;
import processing.core.*;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
/**
* This class encapsulates a GLSL shader program, including a vertex
* and a fragment shader. Originally based in the code by JohnG
* (http://www.hardcorepawn.com/)
*/
public class PShader {
// shaders constants
static public final int FILTER = 0;
static public final int FLAT = 1;
static public final int LIT = 2;
static public final int TEXTURED = 3;
static public final int FULL = 4;
static public final int LINE = 5;
static public final int POINT = 6;
protected PApplet parent;
// The main renderer associated to the parent PApplet.
protected PGraphicsOpenGL pgMain;
// We need a reference to the renderer since a shader might
// be called by different renderers within a single application
// (the one corresponding to the main surface, or other offscreen
// renderers).
protected PGraphicsOpenGL pgCurrent;
protected PGL pgl;
protected PGL.Context context; // The context that created this shader.
public int glProgram;
public int glVertex;
public int glFragment;
protected URL vertexURL;
protected URL fragmentURL;
protected String vertexFilename;
protected String fragmentFilename;
protected String vertexShaderSource;
protected String fragmentShaderSource;
protected boolean bound;
protected HashMap<Integer, UniformValue> uniformValues = null;
public PShader() {
parent = null;
pgMain = null;
pgl = null;
context = null;
this.vertexURL = null;
this.fragmentURL = null;
this.vertexFilename = null;
this.fragmentFilename = null;
glProgram = 0;
glVertex = 0;
glFragment = 0;
bound = false;
}
public PShader(PApplet parent) {
this();
this.parent = parent;
pgMain = (PGraphicsOpenGL) parent.g;
pgl = pgMain.pgl;
context = pgl.createEmptyContext();
}
/**
* Creates a shader program using the specified vertex and fragment
* shaders.
*
* @param parent PApplet
* @param vertexFN String
* @param fragmentFN String
*/
public PShader(PApplet parent, String vertFilename, String fragFilename) {
this.parent = parent;
pgMain = (PGraphicsOpenGL) parent.g;
pgl = pgMain.pgl;
this.vertexURL = null;
this.fragmentURL = null;
this.vertexFilename = vertFilename;
this.fragmentFilename = fragFilename;
glProgram = 0;
glVertex = 0;
glFragment = 0;
}
public PShader(PApplet parent, URL vertURL, URL fragURL) {
this.parent = parent;
pgMain = (PGraphicsOpenGL) parent.g;
pgl = pgMain.pgl;
this.vertexURL = vertURL;
this.fragmentURL = fragURL;
this.vertexFilename = null;
this.fragmentFilename = null;
glProgram = 0;
glVertex = 0;
glFragment = 0;
}
protected void finalize() throws Throwable {
try {
if (glVertex != 0) {
pgMain.finalizeGLSLVertShaderObject(glVertex, context.code());
}
if (glFragment != 0) {
pgMain.finalizeGLSLFragShaderObject(glFragment, context.code());
}
if (glProgram != 0) {
pgMain.finalizeGLSLProgramObject(glProgram, context.code());
}
} finally {
super.finalize();
}
}
public void setVertexShader(String vertFilename) {
this.vertexFilename = vertFilename;
}
public void setVertexShader(URL vertURL) {
this.vertexURL = vertURL;
}
public void setFragmentShader(String fragFilename) {
this.fragmentFilename = fragFilename;
}
public void setFragmentShader(URL fragURL) {
this.fragmentURL = fragURL;
}
/**
* Initializes (if needed) and binds the shader program.
*/
public void bind() {
init();
pgl.glUseProgram(glProgram);
bound = true;
consumeUniforms();
}
/**
* Unbinds the shader program.
*/
public void unbind() {
pgl.glUseProgram(0);
bound = false;
}
/**
* Returns true if the shader is bound, false otherwise.
*/
public boolean bound() {
return bound;
}
public void set(String name, int x) {
setUniformImpl(name, UniformValue.INT1, new int[] { x });
}
public void set(String name, int x, int y) {
setUniformImpl(name, UniformValue.INT2, new int[] { x, y });
}
public void set(String name, int x, int y, int z) {
setUniformImpl(name, UniformValue.INT3, new int[] { x, y, z });
}
public void set(String name, int x, int y, int z, int w) {
setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z });
}
public void set(String name, float x) {
setUniformImpl(name, UniformValue.FLOAT1, new float[] { x });
}
public void set(String name, float x, float y) {
setUniformImpl(name, UniformValue.FLOAT2, new float[] { x, y });
}
public void set(String name, float x, float y, float z) {
setUniformImpl(name, UniformValue.FLOAT3, new float[] { x, y, z });
}
public void set(String name, float x, float y, float z, float w) {
setUniformImpl(name, UniformValue.FLOAT4, new float[] { x, y, z, w });
}
public void set(String name, PVector vec) {
setUniformImpl(name, UniformValue.FLOAT3, new float[] { vec.x, vec.y, vec.z });
}
public void set(String name, int[] vec) {
set(name, vec, 1);
}
public void set(String name, int[] vec, int ncoords) {
if (ncoords == 1) {
setUniformImpl(name, UniformValue.INT1VEC, vec);
} else if (ncoords == 2) {
setUniformImpl(name, UniformValue.INT2VEC, vec);
} else if (ncoords == 3) {
setUniformImpl(name, UniformValue.INT3VEC, vec);
} else if (ncoords == 4) {
setUniformImpl(name, UniformValue.INT4VEC, vec);
} else if (4 < ncoords) {
PGraphics.showWarning("Only up to 4 coordinates per element are supported.");
} else {
PGraphics.showWarning("Wrong number of coordinates: it is negative!");
}
}
public void set(String name, float[] vec) {
set(name, vec, 1);
}
public void set(String name, float[] vec, int ncoords) {
if (ncoords == 1) {
setUniformImpl(name, UniformValue.FLOAT1VEC, vec);
} else if (ncoords == 2) {
setUniformImpl(name, UniformValue.FLOAT2VEC, vec);
} else if (ncoords == 3) {
setUniformImpl(name, UniformValue.FLOAT3VEC, vec);
} else if (ncoords == 4) {
setUniformImpl(name, UniformValue.FLOAT4VEC, vec);
} else if (4 < ncoords) {
PGraphics.showWarning("Only up to 4 coordinates per element are supported.");
} else {
PGraphics.showWarning("Wrong number of coordinates: it is negative!");
}
}
public void set(String name, PMatrix2D mat) {
float[] matv = { mat.m00, mat.m01,
mat.m10, mat.m11 };
setUniformImpl(name, UniformValue.MAT2, matv);
}
public void set(String name, PMatrix3D mat) {
set(name, mat, false);
}
public void set(String name, PMatrix3D mat, boolean use3x3) {
if (use3x3) {
float[] matv = { mat.m00, mat.m01, mat.m02,
mat.m10, mat.m11, mat.m12,
mat.m20, mat.m21, mat.m22 };
setUniformImpl(name, UniformValue.MAT3, matv);
} else {
float[] matv = { mat.m00, mat.m01, mat.m02, mat.m03,
mat.m10, mat.m11, mat.m12, mat.m13,
mat.m20, mat.m21, mat.m22, mat.m23,
mat.m30, mat.m31, mat.m32, mat.m33 };
setUniformImpl(name, UniformValue.MAT4, matv);
}
}
/**
* Returns the ID location of the attribute parameter given its name.
*
* @param name String
* @return int
*/
protected int getAttributeLoc(String name) {
init();
return pgl.glGetAttribLocation(glProgram, name);
}
/**
* Returns the ID location of the uniform parameter given its name.
*
* @param name String
* @return int
*/
protected int getUniformLoc(String name) {
init();
return pgl.glGetUniformLocation(glProgram, name);
}
protected void setAttributeVBO(int loc, int vboId, int size, int type, boolean normalized, int stride, int offset) {
if (-1 < loc) {
pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, vboId);
pgl.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
}
}
protected void setUniformValue(int loc, int x) {
if (-1 < loc) {
pgl.glUniform1i(loc, x);
}
}
protected void setUniformValue(int loc, int x, int y) {
if (-1 < loc) {
pgl.glUniform2i(loc, x, y);
}
}
protected void setUniformValue(int loc, int x, int y, int z) {
if (-1 < loc) {
pgl.glUniform3i(loc, x, y, z);
}
}
protected void setUniformValue(int loc, int x, int y, int z, int w) {
if (-1 < loc) {
pgl.glUniform4i(loc, x, y, z, w);
}
}
protected void setUniformValue(int loc, float x) {
if (-1 < loc) {
pgl.glUniform1f(loc, x);
}
}
protected void setUniformValue(int loc, float x, float y) {
if (-1 < loc) {
pgl.glUniform2f(loc, x, y);
}
}
protected void setUniformValue(int loc, float x, float y, float z) {
if (-1 < loc) {
pgl.glUniform3f(loc, x, y, z);
}
}
protected void setUniformValue(int loc, float x, float y, float z, float w) {
if (-1 < loc) {
pgl.glUniform4f(loc, x, y, z, w);
}
}
protected void setUniformVector(int loc, int[] vec, int ncoords) {
if (-1 < loc) {
if (ncoords == 1) {
pgl.glUniform1iv(loc, vec.length, vec, 0);
} else if (ncoords == 2) {
pgl.glUniform2iv(loc, vec.length / 2, vec, 0);
} else if (ncoords == 3) {
pgl.glUniform3iv(loc, vec.length / 3, vec, 0);
} else if (ncoords == 4) {
pgl.glUniform3iv(loc, vec.length / 4, vec, 0);
}
}
}
protected void setUniformVector(int loc, float[] vec, int ncoords) {
if (-1 < loc) {
if (ncoords == 1) {
pgl.glUniform1fv(loc, vec.length, vec, 0);
} else if (ncoords == 2) {
pgl.glUniform2fv(loc, vec.length / 2, vec, 0);
} else if (ncoords == 3) {
pgl.glUniform3fv(loc, vec.length / 3, vec, 0);
} else if (ncoords == 4) {
pgl.glUniform4fv(loc, vec.length / 4, vec, 0);
}
}
}
protected void setUniformMatrix(int loc, float[] mat) {
if (-1 < loc) {
if (mat.length == 4) {
pgl.glUniformMatrix2fv(loc, 1, false, mat, 0);
} else if (mat.length == 9) {
pgl.glUniformMatrix3fv(loc, 1, false, mat, 0);
} else if (mat.length == 16) {
pgl.glUniformMatrix4fv(loc, 1, false, mat, 0);
}
}
}
/*
// The individual attribute setters are not really needed, read this:
// http://stackoverflow.com/questions/7718976/what-is-glvertexattrib-versus-glvertexattribpointer-used-for
// except for setting a constant vertex attribute value.
public void set1FloatAttribute(int loc, float x) {
if (-1 < loc) {
pgl.glVertexAttrib1f(loc, x);
}
}
public void set2FloatAttribute(int loc, float x, float y) {
if (-1 < loc) {
pgl.glVertexAttrib2f(loc, x, y);
}
}
public void set3FloatAttribute(int loc, float x, float y, float z) {
if (-1 < loc) {
pgl.glVertexAttrib3f(loc, x, y, z);
}
}
public void set4FloatAttribute(int loc, float x, float y, float z, float w) {
if (-1 < loc) {
pgl.glVertexAttrib4f(loc, x, y, z, w);
}
}
*/
protected void setUniformImpl(String name, int type, Object value) {
int loc = getUniformLoc(name);
if (-1 < loc) {
if (uniformValues == null) {
uniformValues = new HashMap<Integer, UniformValue>();
}
uniformValues.put(loc, new UniformValue(type, value));
} else {
PGraphics.showWarning("The shader doesn't have the uniform " + name);
}
}
protected void consumeUniforms() {
if (uniformValues != null && 0 < uniformValues.size()) {
for (Integer loc: uniformValues.keySet()) {
UniformValue val = uniformValues.get(loc);
if (val.type == UniformValue.INT1) {
int[] v = ((int[])val.value);
pgl.glUniform1i(loc, v[0]);
} else if (val.type == UniformValue.INT2) {
int[] v = ((int[])val.value);
pgl.glUniform2i(loc, v[0], v[1]);
} else if (val.type == UniformValue.INT3) {
int[] v = ((int[])val.value);
pgl.glUniform3i(loc, v[0], v[1], v[2]);
} else if (val.type == UniformValue.INT4) {
int[] v = ((int[])val.value);
pgl.glUniform4i(loc, v[0], v[1], v[2], v[4]);
} else if (val.type == UniformValue.FLOAT1) {
float[] v = ((float[])val.value);
pgl.glUniform1f(loc, v[0]);
} else if (val.type == UniformValue.FLOAT2) {
float[] v = ((float[])val.value);
pgl.glUniform2f(loc, v[0], v[1]);
} else if (val.type == UniformValue.FLOAT3) {
float[] v = ((float[])val.value);
pgl.glUniform3f(loc, v[0], v[1], v[2]);
} else if (val.type == UniformValue.FLOAT4) {
float[] v = ((float[])val.value);
pgl.glUniform4f(loc, v[0], v[1], v[2], v[3]);
} else if (val.type == UniformValue.INT1VEC) {
int[] v = ((int[])val.value);
pgl.glUniform1iv(loc, v.length, v, 0);
} else if (val.type == UniformValue.INT2VEC) {
int[] v = ((int[])val.value);
pgl.glUniform2iv(loc, v.length / 2, v, 0);
} else if (val.type == UniformValue.INT3VEC) {
int[] v = ((int[])val.value);
pgl.glUniform3iv(loc, v.length / 3, v, 0);
} else if (val.type == UniformValue.INT4VEC) {
int[] v = ((int[])val.value);
pgl.glUniform4iv(loc, v.length / 4, v, 0);
} else if (val.type == UniformValue.FLOAT1VEC) {
float[] v = ((float[])val.value);
pgl.glUniform1fv(loc, v.length, v, 0);
} else if (val.type == UniformValue.FLOAT2VEC) {
float[] v = ((float[])val.value);
pgl.glUniform2fv(loc, v.length / 2, v, 0);
} else if (val.type == UniformValue.FLOAT3VEC) {
float[] v = ((float[])val.value);
pgl.glUniform3fv(loc, v.length / 3, v, 0);
} else if (val.type == UniformValue.FLOAT4VEC) {
float[] v = ((float[])val.value);
pgl.glUniform4fv(loc, v.length / 4, v, 0);
} else if (val.type == UniformValue.MAT2) {
float[] v = ((float[])val.value);
pgl.glUniformMatrix2fv(loc, 1, false, v, 0);
} else if (val.type == UniformValue.MAT3) {
float[] v = ((float[])val.value);
pgl.glUniformMatrix3fv(loc, 1, false, v, 0);
} else if (val.type == UniformValue.MAT4) {
float[] v = ((float[])val.value);
pgl.glUniformMatrix4fv(loc, 1, false, v, 0);
}
}
uniformValues.clear();
}
}
protected void init() {
if (glProgram == 0 || contextIsOutdated()) {
context = pgl.getCurrentContext();
glProgram = pgMain.createGLSLProgramObject(context.code());
boolean hasVert = false;
if (vertexFilename != null) {
hasVert = loadVertexShader(vertexFilename);
} else if (vertexURL != null) {
hasVert = loadVertexShader(vertexURL);
} else {
PGraphics.showException("Vertex shader filenames and URLs are both null!");
}
boolean hasFrag = false;
if (fragmentFilename != null) {
hasFrag = loadFragmentShader(fragmentFilename);
} else if (fragmentURL != null) {
hasFrag = loadFragmentShader(fragmentURL);
} else {
PGraphics.showException("Fragment shader filenames and URLs are both null!");
}
boolean vertRes = true;
if (hasVert) {
vertRes = compileVertexShader();
}
boolean fragRes = true;
if (hasFrag) {
fragRes = compileFragmentShader();
}
if (vertRes && fragRes) {
if (hasVert) {
pgl.glAttachShader(glProgram, glVertex);
}
if (hasFrag) {
pgl.glAttachShader(glProgram, glFragment);
}
pgl.glLinkProgram(glProgram);
int[] linked = new int[1];
pgl.glGetProgramiv(glProgram, PGL.GL_LINK_STATUS, linked, 0);
if (linked[0] == PGL.GL_FALSE) {
PGraphics.showException("Cannot link shader program:\n" + pgl.glGetProgramInfoLog(glProgram));
}
pgl.glValidateProgram(glProgram);
int[] validated = new int[1];
pgl.glGetProgramiv(glProgram, PGL.GL_VALIDATE_STATUS, validated, 0);
if (validated[0] == PGL.GL_FALSE) {
PGraphics.showException("Cannot validate shader program:\n" + pgl.glGetProgramInfoLog(glProgram));
}
}
}
}
protected boolean contextIsOutdated() {
boolean outdated = !pgl.contextIsCurrent(context);
if (outdated) {
pgMain.removeGLSLProgramObject(glProgram, context.code());
pgMain.removeGLSLVertShaderObject(glVertex, context.code());
pgMain.removeGLSLFragShaderObject(glFragment, context.code());
glProgram = 0;
glVertex = 0;
glFragment = 0;
}
return outdated;
}
/**
* Loads and compiles the vertex shader contained in file.
*
* @param file String
*/
protected boolean loadVertexShader(String filename) {
vertexShaderSource = PApplet.join(parent.loadStrings(filename), "\n");
return vertexShaderSource != null;
}
/**
* Loads and compiles the vertex shader contained in the URL.
*
* @param file String
*/
protected boolean loadVertexShader(URL url) {
try {
vertexShaderSource = PApplet.join(PApplet.loadStrings(url.openStream()), "\n");
return vertexShaderSource != null;
} catch (IOException e) {
PGraphics.showException("Cannot load vertex shader " + url.getFile());
return false;
}
}
/**
* Loads and compiles the fragment shader contained in file.
*
* @param file String
*/
protected boolean loadFragmentShader(String filename) {
fragmentShaderSource = PApplet.join(parent.loadStrings(filename), "\n");
return fragmentShaderSource != null;
}
/**
* Loads and compiles the fragment shader contained in the URL.
*
* @param url URL
*/
protected boolean loadFragmentShader(URL url) {
try {
fragmentShaderSource = PApplet.join(PApplet.loadStrings(url.openStream()), "\n");
return fragmentShaderSource != null;
} catch (IOException e) {
PGraphics.showException("Cannot load fragment shader " + url.getFile());
return false;
}
}
/**
* @param shaderSource a string containing the shader's code
*/
protected boolean compileVertexShader() {
glVertex = pgMain.createGLSLVertShaderObject(context.code());
pgl.glShaderSource(glVertex, vertexShaderSource);
pgl.glCompileShader(glVertex);
int[] compiled = new int[1];
pgl.glGetShaderiv(glVertex, PGL.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == PGL.GL_FALSE) {
PGraphics.showException("Cannot compile vertex shader:\n" + pgl.glGetShaderInfoLog(glVertex));
return false;
} else {
return true;
}
}
/**
* @param shaderSource a string containing the shader's code
*/
protected boolean compileFragmentShader() {
glFragment = pgMain.createGLSLFragShaderObject(context.code());
pgl.glShaderSource(glFragment, fragmentShaderSource);
pgl.glCompileShader(glFragment);
int[] compiled = new int[1];
pgl.glGetShaderiv(glFragment, PGL.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == PGL.GL_FALSE) {
PGraphics.showException("Cannot compile fragment shader:\n" + pgl.glGetShaderInfoLog(glFragment));
return false;
} else {
return true;
}
}
protected void setRenderer(PGraphicsOpenGL pg) {
pgCurrent = pg;
}
protected void loadAttributes() { }
protected void loadUniforms() { }
protected void release() {
if (glVertex != 0) {
pgMain.deleteGLSLVertShaderObject(glVertex, context.code());
glVertex = 0;
}
if (glFragment != 0) {
pgMain.deleteGLSLFragShaderObject(glFragment, context.code());
glFragment = 0;
}
if (glProgram != 0) {
pgMain.deleteGLSLProgramObject(glProgram, context.code());
glProgram = 0;
}
}
// Class to store a user-specified value for a uniform parameter
// in the shader
protected class UniformValue {
static final int INT1 = 0;
static final int INT2 = 1;
static final int INT3 = 2;
static final int INT4 = 3;
static final int FLOAT1 = 4;
static final int FLOAT2 = 5;
static final int FLOAT3 = 6;
static final int FLOAT4 = 7;
static final int INT1VEC = 8;
static final int INT2VEC = 9;
static final int INT3VEC = 10;
static final int INT4VEC = 11;
static final int FLOAT1VEC = 12;
static final int FLOAT2VEC = 13;
static final int FLOAT3VEC = 14;
static final int FLOAT4VEC = 15;
static final int MAT2 = 16;
static final int MAT3 = 17;
static final int MAT4 = 18;
int type;
Object value;
UniformValue(int type, Object value) {
this.type = type;
this.value = value;
}
}
}
@@ -1,171 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012 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 as published by the Free Software Foundation, version 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., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.opengl;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PShape;
public class PShape2D extends PShapeOpenGL {
public PShape2D(PApplet parent, int family) {
super(parent, family);
}
public boolean is2D() {
return true;
}
public boolean is3D() {
return false;
}
////////////////////////////////////////////////////////////////////////
//
// Shape copy
static public PShape2D createShape(PApplet parent, PShape src) {
PShape2D dest = null;
if (src.getFamily() == GROUP) {
dest = PGraphics2D.createShapeImpl(parent, GROUP);
PShape2D.copyGroup(parent, src, dest);
} else if (src.getFamily() == PRIMITIVE) {
dest = PGraphics2D.createShapeImpl(parent, src.getKind(), src.getParams());
PShape.copyPrimitive(src, dest);
} else if (src.getFamily() == GEOMETRY) {
dest = PGraphics2D.createShapeImpl(parent, src.getKind());
PShape.copyGeometry(src, dest);
} else if (src.getFamily() == PATH) {
dest = PGraphics2D.createShapeImpl(parent, PATH);
PShape.copyPath(src, dest);
}
dest.setName(src.getName());
return dest;
}
static public void copyGroup(PApplet parent, PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
for (int i = 0; i < src.getChildCount(); i++) {
PShape c = PShape2D.createShape(parent, src.getChild(i));
dest.addChild(c);
}
}
///////////////////////////////////////////////////////////
//
// Drawing methods
public void vertex(float x, float y, float z) {
PGraphics.showDepthWarningXYZ("vertex");
}
public void vertex(float x, float y, float z, float u, float v) {
PGraphics.showDepthWarningXYZ("vertex");
}
///////////////////////////////////////////////////////////
//
// Bezier curves
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
PGraphics.showDepthWarningXYZ("bezierVertex");
}
public void quadraticVertex(float x2, float y2, float z2,
float x4, float y4, float z4) {
PGraphics.showDepthWarningXYZ("quadVertex");
}
public void curveVertex(float x, float y, float z) {
PGraphics.showDepthWarningXYZ("curveVertex");
}
///////////////////////////////////////////////////////////
//
// Geometric transformations
public void translate(float tx, float ty, float tz) {
PGraphics.showVariationWarning("translate");
}
public void rotateX(float angle) {
PGraphics.showDepthWarning("rotateX");
}
public void rotateY(float angle) {
PGraphics.showDepthWarning("rotateY");
}
public void rotateZ(float angle) {
PGraphics.showDepthWarning("rotateZ");
}
public void rotate(float angle, float vx, float vy, float vz) {
PGraphics.showVariationWarning("rotate");
}
public void applyMatrix(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
PGraphics.showVariationWarning("applyMatrix");
}
public void scale(float sx, float sy, float sz) {
PGraphics.showDepthWarningXYZ("scale");
}
///////////////////////////////////////////////////////////
//
// Setters/getters of individual vertices
public float getVertexZ(int index) {
PGraphics.showDepthWarningXYZ("getVertexZ");
return 0;
}
public void setVertex(int index, float x, float y) {
super.setVertex(index, x, y, 0);
}
public void setVertex(int index, float x, float y, float z) {
PGraphics.showDepthWarningXYZ("setVertex");
}
}
@@ -1,79 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012 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 as published by the Free Software Foundation, version 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., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.opengl;
import processing.core.PApplet;
import processing.core.PShape;
public class PShape3D extends PShapeOpenGL {
public PShape3D(PApplet parent, int family) {
super(parent, family);
}
public boolean is2D() {
return false;
}
public boolean is3D() {
return true;
}
////////////////////////////////////////////////////////////////////////
//
// Shape copy
static public PShape3D createShape(PApplet parent, PShape src) {
PShape3D dest = null;
if (src.getFamily() == GROUP) {
dest = PGraphics3D.createShapeImpl(parent, GROUP);
PShape3D.copyGroup(parent, src, dest);
} else if (src.getFamily() == PRIMITIVE) {
dest = PGraphics3D.createShapeImpl(parent, src.getKind(), src.getParams());
PShape.copyPrimitive(src, dest);
} else if (src.getFamily() == GEOMETRY) {
dest = PGraphics3D.createShapeImpl(parent, src.getKind());
PShape.copyGeometry(src, dest);
} else if (src.getFamily() == PATH) {
dest = PGraphics3D.createShapeImpl(parent, PATH);
PShape.copyPath(src, dest);
}
dest.setName(src.getName());
return dest;
}
static public void copyGroup(PApplet parent, PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
for (int i = 0; i < src.getChildCount(); i++) {
PShape c = PShape3D.createShape(parent, src.getChild(i));
dest.addChild(c);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,30 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor;
void main() {
gl_FragColor = vertColor;
}
@@ -1,36 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
uniform mat4 projectionMatrix;
uniform mat4 modelviewMatrix;
attribute vec4 inVertex;
attribute vec4 inColor;
attribute vec2 inPoint;
varying vec4 vertColor;
void main() {
vec4 pos = modelviewMatrix * inVertex;
pos.xy += inPoint.xy;
gl_Position = projectionMatrix * pos;
vertColor = inColor;
}
@@ -1,32 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
uniform mat4 projmodelviewMatrix;
attribute vec4 inVertex;
attribute vec4 inColor;
varying vec4 vertColor;
void main() {
gl_Position = projmodelviewMatrix * inVertex;
vertColor = inColor;
}
@@ -1,142 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
uniform mat4 modelviewMatrix;
uniform mat4 projmodelviewMatrix;
uniform mat3 normalMatrix;
uniform mat4 texcoordMatrix;
uniform int lightCount;
uniform vec4 lightPosition[8];
uniform vec3 lightNormal[8];
uniform vec3 lightAmbient[8];
uniform vec3 lightDiffuse[8];
uniform vec3 lightSpecular[8];
uniform vec3 lightFalloffCoefficients[8];
uniform vec2 lightSpotParameters[8];
attribute vec4 inVertex;
attribute vec4 inColor;
attribute vec3 inNormal;
attribute vec2 inTexcoord;
attribute vec4 inAmbient;
attribute vec4 inSpecular;
attribute vec4 inEmissive;
attribute float inShine;
varying vec4 vertColor;
varying vec4 vertTexcoord;
const float zero_float = 0.0;
const float one_float = 1.0;
const vec3 zero_vec3 = vec3(0);
float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) {
vec3 lpv = lightPos - vertPos;
vec3 dist = vec3(one_float);
dist.z = dot(lpv, lpv);
dist.y = sqrt(dist.z);
return one_float / dot(dist, coeff);
}
float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) {
vec3 lpv = normalize(lightPos - vertPos);
float spotCos = dot(-lightNorm, lpv);
return spotCos <= minCos ? zero_float : pow(spotCos, spotExp);
}
float lambertFactor(vec3 lightDir, vec3 vecNormal) {
return max(zero_float, dot(lightDir, vecNormal));
}
float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) {
vec3 np = normalize(vertPos);
vec3 ldp = normalize(lightDir - np);
return pow(max(zero_float, dot(ldp, vecNormal)), shine);
}
void main() {
// Vertex in clip coordinates
gl_Position = projmodelviewMatrix * inVertex;
// Vertex in eye coordinates
vec3 ecVertex = vec3(modelviewMatrix * inVertex);
// Normal vector in eye coordinates
vec3 ecNormal = normalize(normalMatrix * inNormal);
if (dot(-ecVertex, ecNormal) < zero_float) {
// If normal is away from camera, choose its opposite.
// If we add backface culling, this will be backfacing
ecNormal *= -one_float;
}
// Light calculations
vec3 totalAmbient = vec3(0, 0, 0);
vec3 totalDiffuse = vec3(0, 0, 0);
vec3 totalSpecular = vec3(0, 0, 0);
for (int i = 0; i < lightCount; i++) {
vec3 lightPos = lightPosition[i].xyz;
bool isDir = zero_float < lightPosition[i].w;
float spotCos = lightSpotParameters[i].x;
float spotExp = lightSpotParameters[i].y;
vec3 lightDir;
float falloff;
float spotf;
if (isDir) {
falloff = one_float;
lightDir = -lightNormal[i];
} else {
falloff = falloffFactor(lightPos, ecVertex, lightFalloffCoefficients[i]);
lightDir = normalize(lightPos - ecVertex);
}
spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i],
spotCos, spotExp)
: one_float;
if (any(greaterThan(lightAmbient[i], zero_vec3))) {
totalAmbient += lightAmbient[i] * falloff;
}
if (any(greaterThan(lightDiffuse[i], zero_vec3))) {
totalDiffuse += lightDiffuse[i] * falloff * spotf *
lambertFactor(lightDir, ecNormal);
}
if (any(greaterThan(lightSpecular[i], zero_vec3))) {
totalSpecular += lightSpecular[i] * falloff * spotf *
blinnPhongFactor(lightDir, ecVertex, ecNormal, inShine);
}
}
// Calculating final color as result of all lights (plus emissive term).
// Transparency is determined exclusively by the diffuse component.
vertColor = vec4(totalAmbient, 0) * inAmbient +
vec4(totalDiffuse, 1) * inColor +
vec4(totalSpecular, 0) * inSpecular +
vec4(inEmissive.rgb, 0);
// Calculating texture coordinates, with r and q set both to one
vertTexcoord = texcoordMatrix * vec4(inTexcoord, 1.0, 1.0);
}
@@ -1,136 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
uniform mat4 modelviewMatrix;
uniform mat4 projmodelviewMatrix;
uniform mat3 normalMatrix;
uniform int lightCount;
uniform vec4 lightPosition[8];
uniform vec3 lightNormal[8];
uniform vec3 lightAmbient[8];
uniform vec3 lightDiffuse[8];
uniform vec3 lightSpecular[8];
uniform vec3 lightFalloffCoefficients[8];
uniform vec2 lightSpotParameters[8];
attribute vec4 inVertex;
attribute vec4 inColor;
attribute vec3 inNormal;
attribute vec4 inAmbient;
attribute vec4 inSpecular;
attribute vec4 inEmissive;
attribute float inShine;
varying vec4 vertColor;
const float zero_float = 0.0;
const float one_float = 1.0;
const vec3 zero_vec3 = vec3(0);
float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) {
vec3 lpv = lightPos - vertPos;
vec3 dist = vec3(one_float);
dist.z = dot(lpv, lpv);
dist.y = sqrt(dist.z);
return one_float / dot(dist, coeff);
}
float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) {
vec3 lpv = normalize(lightPos - vertPos);
float spotCos = dot(-lightNorm, lpv);
return spotCos <= minCos ? zero_float : pow(spotCos, spotExp);
}
float lambertFactor(vec3 lightDir, vec3 vecNormal) {
return max(zero_float, dot(lightDir, vecNormal));
}
float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) {
vec3 np = normalize(vertPos);
vec3 ldp = normalize(lightDir - np);
return pow(max(zero_float, dot(ldp, vecNormal)), shine);
}
void main() {
// Vertex in clip coordinates
gl_Position = projmodelviewMatrix * inVertex;
// Vertex in eye coordinates
vec3 ecVertex = vec3(modelviewMatrix * inVertex);
// Normal vector in eye coordinates
vec3 ecNormal = normalize(normalMatrix * inNormal);
if (dot(-ecVertex, ecNormal) < zero_float) {
// If normal is away from camera, choose its opposite.
// If we add backface culling, this will be backfacing
ecNormal *= -one_float;
}
// Light calculations
vec3 totalAmbient = vec3(0, 0, 0);
vec3 totalDiffuse = vec3(0, 0, 0);
vec3 totalSpecular = vec3(0, 0, 0);
for (int i = 0; i < lightCount; i++) {
vec3 lightPos = lightPosition[i].xyz;
bool isDir = zero_float < lightPosition[i].w;
float spotCos = lightSpotParameters[i].x;
float spotExp = lightSpotParameters[i].y;
vec3 lightDir;
float falloff;
float spotf;
if (isDir) {
falloff = one_float;
lightDir = -lightNormal[i];
} else {
falloff = falloffFactor(lightPos, ecVertex, lightFalloffCoefficients[i]);
lightDir = normalize(lightPos - ecVertex);
}
spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i],
spotCos, spotExp)
: one_float;
if (any(greaterThan(lightAmbient[i], zero_vec3))) {
totalAmbient += lightAmbient[i] * falloff;
}
if (any(greaterThan(lightDiffuse[i], zero_vec3))) {
totalDiffuse += lightDiffuse[i] * falloff * spotf *
lambertFactor(lightDir, ecNormal);
}
if (any(greaterThan(lightSpecular[i], zero_vec3))) {
totalSpecular += lightSpecular[i] * falloff * spotf *
blinnPhongFactor(lightDir, ecVertex, ecNormal, inShine);
}
}
// Calculating final color as result of all lights (plus emissive term).
// Transparency is determined exclusively by the diffuse component.
vertColor = vec4(totalAmbient, 0) * inAmbient +
vec4(totalDiffuse, 1) * inColor +
vec4(totalSpecular, 0) * inSpecular +
vec4(inEmissive.rgb, 0);
}
@@ -1,30 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor;
void main() {
gl_FragColor = vertColor;
}
@@ -1,35 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform sampler2D textureSampler;
uniform vec2 texcoordOffset;
varying vec4 vertColor;
varying vec4 vertTexcoord;
void main() {
gl_FragColor = texture2D(textureSampler, vertTexcoord.st) * vertColor;
}
@@ -1,36 +0,0 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-12 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
*/
uniform mat4 projmodelviewMatrix;
uniform mat4 texcoordMatrix;
attribute vec4 inVertex;
attribute vec4 inColor;
attribute vec2 inTexcoord;
varying vec4 vertColor;
varying vec4 vertTexcoord;
void main() {
gl_Position = projmodelviewMatrix * inVertex;
vertColor = inColor;
vertTexcoord = texcoordMatrix * vec4(inTexcoord, 1.0, 1.0);
}
File diff suppressed because it is too large Load Diff