diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index ed29c0ee4..7d950eecc 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -2664,8 +2664,8 @@ public class PGraphics extends PImage implements PConstants { } if (stop - start > TWO_PI) { - start = 0; - stop = TWO_PI; + // don't change start, it is visible in PIE mode + stop = start + TWO_PI; } arcImpl(x, y, w, h, start, stop, mode); } diff --git a/core/src/processing/opengl/LightFrag.glsl b/core/src/processing/opengl/LightFrag.glsl new file mode 100644 index 000000000..b566c8e5b --- /dev/null +++ b/core/src/processing/opengl/LightFrag.glsl @@ -0,0 +1,31 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-13 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; +varying vec4 backVertColor; + +void main() { + gl_FragColor = gl_FrontFacing ? vertColor : backVertColor; +} \ No newline at end of file diff --git a/core/src/processing/opengl/LightVert.glsl b/core/src/processing/opengl/LightVert.glsl index bfbb6a8d3..8d75f970a 100644 --- a/core/src/processing/opengl/LightVert.glsl +++ b/core/src/processing/opengl/LightVert.glsl @@ -43,6 +43,7 @@ attribute vec4 emissive; attribute float shininess; varying vec4 vertColor; +varying vec4 backVertColor; const float zero_float = 0.0; const float one_float = 1.0; @@ -82,17 +83,17 @@ void main() { // Normal vector in eye coordinates vec3 ecNormal = normalize(normalMatrix * normal); - - if (dot(-one_float * 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; - } + vec3 ecNormalInv = ecNormal * -one_float; // Light calculations vec3 totalAmbient = vec3(0, 0, 0); - vec3 totalDiffuse = vec3(0, 0, 0); - vec3 totalSpecular = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + for (int i = 0; i < 8; i++) { if (lightCount == i) break; @@ -118,24 +119,33 @@ void main() { : one_float; if (any(greaterThan(lightAmbient[i], zero_vec3))) { - totalAmbient += lightAmbient[i] * falloff; + totalAmbient += lightAmbient[i] * falloff; } if (any(greaterThan(lightDiffuse[i], zero_vec3))) { - totalDiffuse += lightDiffuse[i] * falloff * spotf * - lambertFactor(lightDir, ecNormal); + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); } if (any(greaterThan(lightSpecular[i], zero_vec3))) { - totalSpecular += lightSpecular[i] * falloff * spotf * - blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); } } // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - vertColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); } \ No newline at end of file diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index f177bfa67..c2bf327e9 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -160,6 +160,11 @@ public class PGraphicsOpenGL extends PGraphics { PGraphicsOpenGL.class.getResource("ColorFrag.glsl"); static protected URL defTextureShaderFragURL = PGraphicsOpenGL.class.getResource("TextureFrag.glsl"); + static protected URL defLightShaderFragURL = + PGraphicsOpenGL.class.getResource("LightFrag.glsl"); + static protected URL defTexlightShaderFragURL = + PGraphicsOpenGL.class.getResource("TexlightFrag.glsl"); + static protected URL defLineShaderVertURL = PGraphicsOpenGL.class.getResource("LineVert.glsl"); static protected URL defLineShaderFragURL = @@ -379,9 +384,9 @@ public class PGraphicsOpenGL extends PGraphics { /** PImage that wraps filterTexture. */ protected PImage filterImage; - /** Flag to indicate if the user is manipulating the - * pixels array through the set()/get() methods */ - protected boolean setgetPixels; + /** Flag to indicate that pixels array is up-to-date and + * ready to be manipulated through the set()/get() methods */ + protected boolean arePixelsUpToDate; // ........................................................ @@ -2151,6 +2156,9 @@ public class PGraphicsOpenGL extends PGraphics { if ((flushMode == FLUSH_CONTINUOUSLY) || (flushMode == FLUSH_WHEN_FULL && tessGeo.isFull())) { flush(); + } else { + // pixels array is not up-to-date anymore + arePixelsUpToDate = false; } } @@ -2166,6 +2174,9 @@ public class PGraphicsOpenGL extends PGraphics { if (flushMode == FLUSH_CONTINUOUSLY || (flushMode == FLUSH_WHEN_FULL && tessGeo.isFull())) { flush(); + } else { + // pixels array is not up-to-date anymore + arePixelsUpToDate = false; } } @@ -2443,7 +2454,7 @@ public class PGraphicsOpenGL extends PGraphics { tessGeo.clear(); texCache.clear(); - setgetPixels = false; + arePixelsUpToDate = false; } @@ -3237,6 +3248,7 @@ public class PGraphicsOpenGL extends PGraphics { normalMode = NORMAL_MODE_SHAPE; inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); + inGeo.setNormal(normalX, normalY, normalZ); inGeo.addArc(x, y, w, h, start, stop, fill, stroke, mode); endShape(); @@ -5435,7 +5447,7 @@ public class PGraphicsOpenGL extends PGraphics { needEndDraw = true; } - if (!setgetPixels) { + if (!arePixelsUpToDate) { // Draws any remaining geometry in case the user is still not // setting/getting new pixels. flush(); @@ -5443,10 +5455,13 @@ public class PGraphicsOpenGL extends PGraphics { allocatePixels(); - if (!setgetPixels) { + if (!arePixelsUpToDate) { readPixels(); } + // Pixels are now up-to-date, set the flag. + arePixelsUpToDate = true; + if (needEndDraw) { endDraw(); } @@ -5566,7 +5581,6 @@ public class PGraphicsOpenGL extends PGraphics { @Override public int get(int x, int y) { loadPixels(); - setgetPixels = true; return super.get(x, y); } @@ -5576,7 +5590,6 @@ public class PGraphicsOpenGL extends PGraphics { int sourceWidth, int sourceHeight, PImage target, int targetX, int targetY) { loadPixels(); - setgetPixels = true; super.getImpl(sourceX, sourceY, sourceWidth, sourceHeight, target, targetX, targetY); } @@ -5585,7 +5598,6 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void set(int x, int y, int argb) { loadPixels(); - setgetPixels = true; super.set(x, y, argb); } @@ -5596,7 +5608,6 @@ public class PGraphicsOpenGL extends PGraphics { int sourceWidth, int sourceHeight, int targetX, int targetY) { loadPixels(); - setgetPixels = true; super.setImpl(sourceImage, sourceX, sourceY, sourceWidth, sourceHeight, targetX, targetY); // do we need this? @@ -6531,8 +6542,12 @@ public class PGraphicsOpenGL extends PGraphics { lightSpecular(0, 0, 0); } - // Because y is flipped, the vertices that should be specified by - // the user in CCW order to define a front-facing facet, end up being CW. + // Vertices should be specified by user in CW order (left-handed) + // That is CCW order (right-handed). Vertex shader inverts + // Y-axis and outputs vertices in CW order (right-handed). + // Culling occurs after the vertex shader, so FRONT FACE + // has to be set to CW (right-handed) for OpenGL to correctly + // recognize FRONT and BACK faces. pgl.frontFace(PGL.CW); pgl.disable(PGL.CULL_FACE); @@ -6540,7 +6555,8 @@ public class PGraphicsOpenGL extends PGraphics { pgl.activeTexture(PGL.TEXTURE0); // The current normal vector is set to be parallel to the Z axis. - normalX = normalY = normalZ = 0; + normalX = normalY = 0; + normalZ = 1; // Clear depth and stencil buffers. pgl.depthMask(true); @@ -6569,7 +6585,7 @@ public class PGraphicsOpenGL extends PGraphics { clearColorBuffer = false; modified = false; - setgetPixels = false; + arePixelsUpToDate = false; } @@ -6740,7 +6756,7 @@ public class PGraphicsOpenGL extends PGraphics { if (useDefault || !polyShader.checkPolyType(PShader.TEXLIGHT)) { if (ppg.defTexlightShader == null) { String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL, 120); - String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL, 120); + String[] fragSource = pgl.loadFragmentShader(defTexlightShaderFragURL, 120); ppg.defTexlightShader = new PShader(parent, vertSource, fragSource); } shader = ppg.defTexlightShader; @@ -6751,7 +6767,7 @@ public class PGraphicsOpenGL extends PGraphics { if (useDefault || !polyShader.checkPolyType(PShader.LIGHT)) { if (ppg.defLightShader == null) { String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL, 120); - String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL, 120); + String[] fragSource = pgl.loadFragmentShader(defLightShaderFragURL, 120); ppg.defLightShader = new PShader(parent, vertSource, fragSource); } shader = ppg.defLightShader; @@ -7798,6 +7814,7 @@ public class PGraphicsOpenGL extends PGraphics { // // Normal calculation + // Expects vertices in CW (left-handed) order. void calcTriangleNormal(int i0, int i1, int i2) { int index; @@ -7825,9 +7842,9 @@ public class PGraphicsOpenGL extends PGraphics { float v10z = z0 - z1; // The automatic normal calculation in Processing assumes - // that vertices as given in CCW order so: + // that vertices as given in CCW order (right-handed) so: // n = v12 x v10 - // so that the normal outwards. + // so that the normal extends from the front face. float nx = v12y * v10z - v10y * v12z; float ny = v12z * v10x - v10z * v12x; float nz = v12x * v10y - v10x * v12y; @@ -7876,14 +7893,18 @@ public class PGraphicsOpenGL extends PGraphics { for (int i = 1; i < vertexCount - 1; i++) { int i1 = i; int i0, i2; - if (i % 2 == 0) { - // The even triangles (0, 2, 4...) should be CW - i0 = i + 1; - i2 = i - 1; - } else { - // The even triangles (1, 3, 5...) should be CCW + // Vertices are specified by user as: + // 1-3 ... + // |\|\ ... + // 0-2-4 ... + if (i % 2 == 1) { + // The odd triangles (1, 3, 5...) should be CW (left-handed) i0 = i - 1; i2 = i + 1; + } else { + // The even triangles (2, 4, 6...) should be CCW (left-handed) + i0 = i + 1; + i2 = i - 1; } calcTriangleNormal(i0, i1, i2); } @@ -7908,8 +7929,14 @@ public class PGraphicsOpenGL extends PGraphics { int i2 = 2 * qd; int i3 = 2 * qd + 1; - calcTriangleNormal(i0, i3, i1); - calcTriangleNormal(i0, i2, i3); + // Vertices are specified by user as: + // 1-3-5 ... + // |\|\| ... + // 0-2-4 ... + // thus (0, 1, 2) and (2, 1, 3) are triangles + // in CW order (left-handed). + calcTriangleNormal(i0, i1, i2); + calcTriangleNormal(i2, i1, i3); } } @@ -8081,56 +8108,108 @@ public class PGraphicsOpenGL extends PGraphics { int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH); int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH); - int idx0 = addVertex(centerX, centerY, VERTEX, true); + // get length before wrapping indexes so (startLUT <= stopLUT); + int length = PApplet.constrain(stopLUT - startLUT, 0, SINCOS_LENGTH); - int increment = 1; // what's a good algorithm? stopLUT - startLUT; - int pidx = 0, idx = 0; - for (int i = startLUT; i < stopLUT; i += increment) { - int ii = i % SINCOS_LENGTH; - // modulo won't make the value positive - if (ii < 0) ii += SINCOS_LENGTH; + boolean fullCircle = length == SINCOS_LENGTH; + + if (fullCircle && arcMode == CHORD) { + // get rid of overlapping vertices, + // solves problem with closing edge in P3D + length -= 1; + stopLUT -= 1; + } + + { // wrap indexes so they are safe to use in LUT + startLUT %= SINCOS_LENGTH; + if (startLUT < 0) startLUT += SINCOS_LENGTH; + + stopLUT %= SINCOS_LENGTH; + if (stopLUT < 0) stopLUT += SINCOS_LENGTH; + } + + int idx0; + if (arcMode == CHORD || arcMode == OPEN) { + // move center to the middle of flat side + // to properly display arcs smaller than PI + float relX = (cosLUT[startLUT] + cosLUT[stopLUT]) * 0.5f * hr; + float relY = (sinLUT[startLUT] + sinLUT[stopLUT]) * 0.5f * vr; + idx0 = addVertex(centerX + relX, centerY + relY, VERTEX, true); + } else { + idx0 = addVertex(centerX, centerY, VERTEX, true); + } + + int inc; + { // initializes inc the same way ellipse does + float sx1 = pg.screenX(x, y); + float sy1 = pg.screenY(x, y); + float sx2 = pg.screenX(x + w, y + h); + float sy2 = pg.screenY(x + w, y + h); + + int accuracy = + PApplet.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY, + (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / + POINT_ACCURACY_FACTOR))); + inc = PApplet.max(1, SINCOS_LENGTH / accuracy); + } + + int idx = idx0; + int pidx; + + int i = -inc; + int ii; + + // i: (0 -> length) inclusive + // ii: (startLUT -> stopLUT) inclusive, going CW (left-handed), + // wrapping around end of LUT + do { + i += inc; + i = PApplet.min(i, length); // clamp so last vertex won't go over + + ii = startLUT + i; // ii from 0 to (2 * SINCOS_LENGTH - 1) + if (ii >= SINCOS_LENGTH) ii -= SINCOS_LENGTH; + + pidx = idx; idx = addVertex(centerX + cosLUT[ii] * hr, centerY + sinLUT[ii] * vr, - VERTEX, i == startLUT && !fill); + VERTEX, i == 0 && !fill); if (stroke) { - if (arcMode == PIE) { - addEdge(pidx, idx, i == startLUT, false); - } else if (startLUT < i) { - addEdge(pidx, idx, i == startLUT + 1, arcMode == 0 && - i == stopLUT - 1); + if (arcMode == CHORD || arcMode == PIE) { + addEdge(pidx, idx, i == 0, false); + } else if (0 < i) { + // when drawing full circle, the edge is closed later + addEdge(pidx, idx, i == inc, i == length && !fullCircle); } } + } while (i < length); + + // keeping last vertex as idx and second last vertex as pidx - pidx = idx; - } - // draw last point explicitly for accuracy - idx = addVertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr, - centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr, - VERTEX, false); if (stroke) { - if (arcMode == PIE) { + if (arcMode == CHORD || arcMode == PIE) { addEdge(idx, idx0, false, false); closeEdge(idx, idx0); - } - } - if (arcMode == CHORD || arcMode == OPEN) { - // Add a last vertex coincident with the first along the perimeter - pidx = idx; - int i = startLUT; - int ii = i % SINCOS_LENGTH; - if (ii < 0) ii += SINCOS_LENGTH; - idx = addVertex(centerX + cosLUT[ii] * hr, - centerY + sinLUT[ii] * vr, - VERTEX, false); - if (stroke && arcMode == CHORD) { - addEdge(pidx, idx, false, true); + } else if (fullCircle) { + closeEdge(pidx, idx); } } } void addBox(float w, float h, float d, boolean fill, boolean stroke) { + + // Correct normals if some dimensions are negative so they always + // extend from front face. We could just take absolute value + // of dimensions, but that would affect texturing. + boolean invertNormX = (h > 0) != (d > 0); + boolean invertNormY = (w > 0) != (d > 0); + boolean invertNormZ = (w > 0) != (h > 0); + + int normX = invertNormX ? -1 : 1; + int normY = invertNormY ? -1 : 1; + int normZ = invertNormZ ? -1 : 1; + float x1 = -w/2f; float x2 = w/2f; float y1 = -h/2f; float y2 = h/2f; float z1 = -d/2f; float z2 = d/2f; @@ -8138,11 +8217,11 @@ public class PGraphicsOpenGL extends PGraphics { int idx1 = 0, idx2 = 0, idx3 = 0, idx4 = 0; if (fill || stroke) { // back face - setNormal(0, 0, -1); + setNormal(0, 0, -normZ); idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true); - idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX, false); + idx2 = addVertex(x1, y2, z1, 0, 1, VERTEX, false); idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX, false); - idx4 = addVertex(x1, y2, z1, 0, 1, VERTEX, false); + idx4 = addVertex(x2, y1, z1, 1, 0, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8152,10 +8231,10 @@ public class PGraphicsOpenGL extends PGraphics { } // front face - setNormal(0, 0, 1); - idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX, false); + setNormal(0, 0, normZ); + idx1 = addVertex(x1, y2, z2, 1, 1, VERTEX, false); idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX, false); - idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX, false); + idx3 = addVertex(x2, y1, z2, 0, 0, VERTEX, false); idx4 = addVertex(x2, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); @@ -8166,11 +8245,11 @@ public class PGraphicsOpenGL extends PGraphics { } // right face - setNormal(1, 0, 0); + setNormal(normX, 0, 0); idx1 = addVertex(x2, y1, z1, 0, 0, VERTEX, false); - idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); + idx2 = addVertex(x2, y2, z1, 0, 1, VERTEX, false); idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); - idx4 = addVertex(x2, y2, z1, 0, 1, VERTEX, false); + idx4 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8180,10 +8259,10 @@ public class PGraphicsOpenGL extends PGraphics { } // left face - setNormal(-1, 0, 0); - idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); + setNormal(-normX, 0, 0); + idx1 = addVertex(x1, y2, z1, 1, 1, VERTEX, false); idx2 = addVertex(x1, y1, z1, 1, 0, VERTEX, false); - idx3 = addVertex(x1, y2, z1, 1, 1, VERTEX, false); + idx3 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); @@ -8193,26 +8272,26 @@ public class PGraphicsOpenGL extends PGraphics { closeEdge(idx4, idx1); } - // bottom face - setNormal(0, -1, 0); - idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); - idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); - idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX, false); - idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX, false); - if (stroke) { - addEdge(idx1, idx2, true, false); - addEdge(idx2, idx3, false, false); - addEdge(idx3, idx4, false, false); - addEdge(idx4, idx1, false, false); - closeEdge(idx4, idx1); - } - // top face - setNormal(0, 1, 0); + setNormal(0, -normY, 0); + idx1 = addVertex(x2, y1, z1, 1, 1, VERTEX, false); + idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); + idx3 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); + idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX, false); + if (stroke) { + addEdge(idx1, idx2, true, false); + addEdge(idx2, idx3, false, false); + addEdge(idx3, idx4, false, false); + addEdge(idx4, idx1, false, false); + closeEdge(idx4, idx1); + } + + // bottom face + setNormal(0, normY, 0); idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX, false); - idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX, false); + idx2 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); - idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); + idx4 = addVertex(x2, y2, z1, 1, 0, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8342,8 +8421,8 @@ public class PGraphicsOpenGL extends PGraphics { int i0 = vert0 + i; int i1 = vert0 + i + detailU + 1; - indices[indCount + 3 * i + 0] = i0; - indices[indCount + 3 * i + 1] = i1; + indices[indCount + 3 * i + 0] = i1; + indices[indCount + 3 * i + 1] = i0; indices[indCount + 3 * i + 2] = i0 + 1; addEdge(i0, i0 + 1, true, true); @@ -9169,6 +9248,7 @@ public class PGraphicsOpenGL extends PGraphics { // // Normal calculation + // Expects vertices in CW (left-handed) order. void calcPolyNormal(int i0, int i1, int i2) { int index; diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 9957204c8..9aa70d2d1 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -167,7 +167,7 @@ public class PJOGL extends PGL { /** This countdown latch is used to maintain the synchronization between * Processing's drawing thread and JOGL's rendering thread */ - protected CountDownLatch drawLatch; + protected CountDownLatch drawLatch = new CountDownLatch(0); /** Flag used to do request final display() call to make sure that the * buffers are properly swapped. diff --git a/core/src/processing/opengl/TexlightFrag.glsl b/core/src/processing/opengl/TexlightFrag.glsl new file mode 100644 index 000000000..f423e49d3 --- /dev/null +++ b/core/src/processing/opengl/TexlightFrag.glsl @@ -0,0 +1,36 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-13 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 texture; + +uniform vec2 texOffset; + +varying vec4 vertColor; +varying vec4 backVertColor; +varying vec4 vertTexCoord; + +void main() { + gl_FragColor = texture2D(texture, vertTexCoord.st) * (gl_FrontFacing ? vertColor : backVertColor); +} \ No newline at end of file diff --git a/core/src/processing/opengl/TexlightVert.glsl b/core/src/processing/opengl/TexlightVert.glsl index 6542bf8fb..d9f2cde3a 100644 --- a/core/src/processing/opengl/TexlightVert.glsl +++ b/core/src/processing/opengl/TexlightVert.glsl @@ -45,6 +45,7 @@ attribute vec4 emissive; attribute float shininess; varying vec4 vertColor; +varying vec4 backVertColor; varying vec4 vertTexCoord; const float zero_float = 0.0; @@ -85,17 +86,17 @@ void main() { // Normal vector in eye coordinates vec3 ecNormal = normalize(normalMatrix * normal); - - if (dot(-one_float * 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; - } + vec3 ecNormalInv = ecNormal * -one_float; // Light calculations vec3 totalAmbient = vec3(0, 0, 0); - vec3 totalDiffuse = vec3(0, 0, 0); - vec3 totalSpecular = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + for (int i = 0; i < 8; i++) { if (lightCount == i) break; @@ -121,27 +122,36 @@ void main() { : one_float; if (any(greaterThan(lightAmbient[i], zero_vec3))) { - totalAmbient += lightAmbient[i] * falloff; + totalAmbient += lightAmbient[i] * falloff; } if (any(greaterThan(lightDiffuse[i], zero_vec3))) { - totalDiffuse += lightDiffuse[i] * falloff * spotf * - lambertFactor(lightDir, ecNormal); + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); } if (any(greaterThan(lightSpecular[i], zero_vec3))) { - totalSpecular += lightSpecular[i] * falloff * spotf * - blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); - } + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); + } } // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - vertColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); + // Calculating texture coordinates, with r and q set both to one vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); }