mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
moving opengl into the core
This commit is contained in:
@@ -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
Reference in New Issue
Block a user