From a9bf6751742f906b32cca60b82c5aed76f27c870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Fri, 25 Sep 2026 09:23:13 -0700 Subject: [PATCH 1/6] Rename PShader to PShaderOpenGL and extract PShader interface. (#1556) --- core/src/processing/core/PGraphics.java | 1 - core/src/processing/core/PShader.java | 113 +++++++++++++++++ .../processing/opengl/PGraphicsOpenGL.java | 117 +++++++++--------- .../{PShader.java => PShaderOpenGL.java} | 60 +++++---- core/src/processing/opengl/PShapeOpenGL.java | 6 +- java/src/processing/mode/java/JavaMode.java | 2 +- 6 files changed, 205 insertions(+), 94 deletions(-) create mode 100644 core/src/processing/core/PShader.java rename core/src/processing/opengl/{PShader.java => PShaderOpenGL.java} (97%) diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 8d411abef2..da0c526a5b 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -47,7 +47,6 @@ import java.util.concurrent.TimeUnit; import processing.opengl.PGL; -import processing.opengl.PShader; /** * diff --git a/core/src/processing/core/PShader.java b/core/src/processing/core/PShader.java new file mode 100644 index 0000000000..4882a0952c --- /dev/null +++ b/core/src/processing/core/PShader.java @@ -0,0 +1,113 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2012-21 The Processing Foundation + Copyright (c) 2004-12 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + 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.core; + +/** + * This class encapsulates a shader program, including a vertex and a fragment + * shader. It is the renderer-agnostic type that sketches declare and pass to + * shader() and filter(); each renderer supplies its own + * implementation (for example a GLSL-backed shader under P2D/P3D, or a WGSL + * one under the WebGPU renderer). + * + * Use the loadShader() function to load your shader code, rather than + * constructing a renderer-specific implementation directly. + * + * @webref rendering:shaders + * @webBrief This class encapsulates a shader program, including a vertex and a + * fragment shader + */ +public interface PShader { + + /** + * Sets the uniform variables inside the shader to modify the effect while the + * program is running. + * + * @webref rendering:shaders + * @webBrief Sets a variable within the shader + * @param name the name of the uniform variable to modify + * @param x first component of the variable to modify + */ + void set(String name, int x); + + /** + * @param y second component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[2], vec2) + */ + void set(String name, int x, int y); + + /** + * @param z third component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[3], vec3) + */ + void set(String name, int x, int y, int z); + + /** + * @param w fourth component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[4], vec4) + */ + void set(String name, int x, int y, int z, int w); + + void set(String name, float x); + void set(String name, float x, float y); + void set(String name, float x, float y, float z); + void set(String name, float x, float y, float z, float w); + + /** + * @param vec modifies all the components of an array/vector uniform variable. PVector can only be used if the type of the variable is vec3. + */ + void set(String name, PVector vec); + + void set(String name, boolean x); + void set(String name, boolean x, boolean y); + void set(String name, boolean x, boolean y, boolean z); + void set(String name, boolean x, boolean y, boolean z, boolean w); + + void set(String name, int[] vec); + + /** + * @param ncoords number of coordinates per element, max 4 + */ + void set(String name, int[] vec, int ncoords); + + void set(String name, float[] vec); + void set(String name, float[] vec, int ncoords); + + void set(String name, boolean[] vec); + void set(String name, boolean[] boolvec, int ncoords); + + /** + * @param mat matrix of values + */ + void set(String name, PMatrix2D mat); + + void set(String name, PMatrix3D mat); + + /** + * @param use3x3 enforces the matrix is 3 x 3 + */ + void set(String name, PMatrix3D mat, boolean use3x3); + + /** + * @param tex sets the sampler uniform variable to read from this image texture + */ + void set(String name, PImage tex); +} diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index b00fa43f92..3dabb2c12c 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -204,17 +204,17 @@ public void dispose() { static protected URL maskShaderFragURL = PGraphicsOpenGL.class.getResource("/processing/opengl/shaders/MaskFrag.glsl"); - protected PShader defColorShader; - protected PShader defTextureShader; - protected PShader defLightShader; - protected PShader defTexlightShader; - protected PShader defLineShader; - protected PShader defPointShader; - protected PShader maskShader; - - protected PShader polyShader; - protected PShader lineShader; - protected PShader pointShader; + protected PShaderOpenGL defColorShader; + protected PShaderOpenGL defTextureShader; + protected PShaderOpenGL defLightShader; + protected PShaderOpenGL defTexlightShader; + protected PShaderOpenGL defLineShader; + protected PShaderOpenGL defPointShader; + protected PShaderOpenGL maskShader; + + protected PShaderOpenGL polyShader; + protected PShaderOpenGL lineShader; + protected PShaderOpenGL pointShader; // ........................................................ @@ -984,7 +984,7 @@ public int hashCode() { } - protected static class GLResourceShader extends Disposable { + protected static class GLResourceShader extends Disposable { int glProgram; int glVertex; int glFragment; @@ -992,7 +992,7 @@ protected static class GLResourceShader extends Disposable { private PGL pgl; final private int context; - public GLResourceShader(PShader sh) { + public GLResourceShader(PShaderOpenGL sh) { super(sh); this.pgl = sh.pgl.graphics.getPrimaryPGL(); @@ -2341,7 +2341,7 @@ protected void flushPolys() { // If the renderer is 2D, then lights should always be false, // so no need to worry about that. - PShader shader = getPolyShader(lights, tex != null); + PShaderOpenGL shader = getPolyShader(lights, tex != null); shader.bind(); int first = texCache.firstCache[i]; @@ -2442,7 +2442,7 @@ protected void flushSortedPolys() { // If the renderer is 2D, then lights should always be false, // so no need to worry about that. - PShader shader = getPolyShader(lights, tex != null); + PShaderOpenGL shader = getPolyShader(lights, tex != null); shader.bind(); shader.setVertexAttribute(bufPolyVertex.glId, 4, PGL.FLOAT, 0, @@ -2704,7 +2704,7 @@ void rawSortedPolys() { protected void flushLines() { updateLineBuffers(); - PShader shader = getLineShader(); + PShaderOpenGL shader = getLineShader(); shader.bind(); IndexCache cache = tessGeo.lineIndexCache; @@ -2804,7 +2804,7 @@ void rawLines() { protected void flushPoints() { updatePointBuffers(); - PShader shader = getPointShader(); + PShaderOpenGL shader = getPointShader(); shader.bind(); IndexCache cache = tessGeo.pointIndexCache; @@ -6005,7 +6005,7 @@ public void mask(PImage alpha) { PGraphicsOpenGL ppg = getPrimaryPG(); if (ppg.maskShader == null) { - ppg.maskShader = new PShader(parent, defTextureShaderVertURL, + ppg.maskShader = new PShaderOpenGL(parent, defTextureShaderVertURL, maskShaderFragURL); } ppg.maskShader.set("mask", alpha); @@ -6047,7 +6047,8 @@ public void filter(int kind, float param) { @Override public void filter(PShader shader) { - if (!shader.isPolyShader()) { + PShaderOpenGL glShader = (PShaderOpenGL) shader; + if (!glShader.isPolyShader()) { PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR); return; } @@ -6090,8 +6091,8 @@ public void filter(PShader shader) { stroke = false; int prevBlendMode = blendMode; blendMode(REPLACE); - PShader prevShader = polyShader; - polyShader = shader; + PShaderOpenGL prevShader = polyShader; + polyShader = glShader; beginShape(QUADS); texture(filterImage); @@ -6913,27 +6914,27 @@ public PShader loadShader(String fragFilename) { return null; } - int type = PShader.getShaderType(parent.loadStrings(fragFilename), - PShader.POLY); - PShader shader = new PShader(parent); + int type = PShaderOpenGL.getShaderType(parent.loadStrings(fragFilename), + PShaderOpenGL.POLY); + PShaderOpenGL shader = new PShaderOpenGL(parent); shader.setType(type); shader.setFragmentShader(fragFilename); - if (type == PShader.POINT) { + if (type == PShaderOpenGL.POINT) { String[] vertSource = pgl.loadVertexShader(defPointShaderVertURL); shader.setVertexShader(vertSource); - } else if (type == PShader.LINE) { + } else if (type == PShaderOpenGL.LINE) { String[] vertSource = pgl.loadVertexShader(defLineShaderVertURL); shader.setVertexShader(vertSource); - } else if (type == PShader.TEXLIGHT) { + } else if (type == PShaderOpenGL.TEXLIGHT) { String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL); shader.setVertexShader(vertSource); - } else if (type == PShader.LIGHT) { + } else if (type == PShaderOpenGL.LIGHT) { String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL); shader.setVertexShader(vertSource); - } else if (type == PShader.TEXTURE) { + } else if (type == PShaderOpenGL.TEXTURE) { String[] vertSource = pgl.loadVertexShader(defTextureShaderVertURL); shader.setVertexShader(vertSource); - } else if (type == PShader.COLOR) { + } else if (type == PShaderOpenGL.COLOR) { String[] vertSource = pgl.loadVertexShader(defColorShaderVertURL); shader.setVertexShader(vertSource); } else { @@ -6946,13 +6947,13 @@ public PShader loadShader(String fragFilename) { @Override public PShader loadShader(String fragFilename, String vertFilename) { - PShader shader = null; + PShaderOpenGL shader = null; if (fragFilename == null || fragFilename.equals("")) { PGraphics.showWarning(MISSING_FRAGMENT_SHADER); } else if (vertFilename == null || vertFilename.equals("")) { PGraphics.showWarning(MISSING_VERTEX_SHADER); } else { - shader = new PShader(parent, vertFilename, fragFilename); + shader = new PShaderOpenGL(parent, vertFilename, fragFilename); } return shader; } @@ -6960,24 +6961,26 @@ public PShader loadShader(String fragFilename, String vertFilename) { @Override public void shader(PShader shader) { + PShaderOpenGL glShader = (PShaderOpenGL) shader; flush(); // Flushing geometry drawn with a different shader. - if (shader != null) shader.init(); - if (shader.isPolyShader()) polyShader = shader; - else if (shader.isLineShader()) lineShader = shader; - else if (shader.isPointShader()) pointShader = shader; + if (glShader != null) glShader.init(); + if (glShader.isPolyShader()) polyShader = glShader; + else if (glShader.isLineShader()) lineShader = glShader; + else if (glShader.isPointShader()) pointShader = glShader; else PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR); } @Override public void shader(PShader shader, int kind) { + PShaderOpenGL glShader = (PShaderOpenGL) shader; flush(); // Flushing geometry drawn with a different shader. - if (shader != null) shader.init(); - if (kind == TRIANGLES) polyShader = shader; - else if (kind == LINES) lineShader = shader; - else if (kind == POINTS) pointShader = shader; + if (glShader != null) glShader.init(); + if (kind == TRIANGLES) polyShader = glShader; + else if (kind == LINES) lineShader = glShader; + else if (kind == POINTS) pointShader = glShader; else PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR); } @@ -7004,8 +7007,8 @@ public void resetShader(int kind) { } - protected PShader getPolyShader(boolean lit, boolean tex) { - PShader shader; + protected PShaderOpenGL getPolyShader(boolean lit, boolean tex) { + PShaderOpenGL shader; PGraphicsOpenGL ppg = getPrimaryPG(); boolean useDefault = polyShader == null; if (polyShader != null) { @@ -7015,22 +7018,22 @@ protected PShader getPolyShader(boolean lit, boolean tex) { } if (lit) { if (tex) { - if (useDefault || !polyShader.checkPolyType(PShader.TEXLIGHT)) { + if (useDefault || !polyShader.checkPolyType(PShaderOpenGL.TEXLIGHT)) { if (ppg.defTexlightShader == null) { String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL); String[] fragSource = pgl.loadFragmentShader(defTexlightShaderFragURL); - ppg.defTexlightShader = new PShader(parent, vertSource, fragSource); + ppg.defTexlightShader = new PShaderOpenGL(parent, vertSource, fragSource); } shader = ppg.defTexlightShader; } else { shader = polyShader; } } else { - if (useDefault || !polyShader.checkPolyType(PShader.LIGHT)) { + if (useDefault || !polyShader.checkPolyType(PShaderOpenGL.LIGHT)) { if (ppg.defLightShader == null) { String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL); String[] fragSource = pgl.loadFragmentShader(defLightShaderFragURL); - ppg.defLightShader = new PShader(parent, vertSource, fragSource); + ppg.defLightShader = new PShaderOpenGL(parent, vertSource, fragSource); } shader = ppg.defLightShader; } else { @@ -7044,22 +7047,22 @@ protected PShader getPolyShader(boolean lit, boolean tex) { } if (tex) { - if (useDefault || !polyShader.checkPolyType(PShader.TEXTURE)) { + if (useDefault || !polyShader.checkPolyType(PShaderOpenGL.TEXTURE)) { if (ppg.defTextureShader == null) { String[] vertSource = pgl.loadVertexShader(defTextureShaderVertURL); String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL); - ppg.defTextureShader = new PShader(parent, vertSource, fragSource); + ppg.defTextureShader = new PShaderOpenGL(parent, vertSource, fragSource); } shader = ppg.defTextureShader; } else { shader = polyShader; } } else { - if (useDefault || !polyShader.checkPolyType(PShader.COLOR)) { + if (useDefault || !polyShader.checkPolyType(PShaderOpenGL.COLOR)) { if (ppg.defColorShader == null) { String[] vertSource = pgl.loadVertexShader(defColorShaderVertURL); String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL); - ppg.defColorShader = new PShader(parent, vertSource, fragSource); + ppg.defColorShader = new PShaderOpenGL(parent, vertSource, fragSource); } shader = ppg.defColorShader; } else { @@ -7076,14 +7079,14 @@ protected PShader getPolyShader(boolean lit, boolean tex) { } - protected PShader getLineShader() { - PShader shader; + protected PShaderOpenGL getLineShader() { + PShaderOpenGL shader; PGraphicsOpenGL ppg = getPrimaryPG(); if (lineShader == null) { if (ppg.defLineShader == null) { String[] vertSource = pgl.loadVertexShader(defLineShaderVertURL); String[] fragSource = pgl.loadFragmentShader(defLineShaderFragURL); - ppg.defLineShader = new PShader(parent, vertSource, fragSource); + ppg.defLineShader = new PShaderOpenGL(parent, vertSource, fragSource); } shader = ppg.defLineShader; } else { @@ -7096,14 +7099,14 @@ protected PShader getLineShader() { } - protected PShader getPointShader() { - PShader shader; + protected PShaderOpenGL getPointShader() { + PShaderOpenGL shader; PGraphicsOpenGL ppg = getPrimaryPG(); if (pointShader == null) { if (ppg.defPointShader == null) { String[] vertSource = pgl.loadVertexShader(defPointShaderVertURL); String[] fragSource = pgl.loadFragmentShader(defPointShaderFragURL); - ppg.defPointShader = new PShader(parent, vertSource, fragSource); + ppg.defPointShader = new PShaderOpenGL(parent, vertSource, fragSource); } shader = ppg.defPointShader; } else { @@ -7279,7 +7282,7 @@ void unbind(PGL pgl) { pgl.disableVertexAttribArray(glLoc); } - boolean active(PShader shader) { + boolean active(PShaderOpenGL shader) { if (active) { if (glLoc == -1) { glLoc = shader.getAttributeLoc(name); diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShaderOpenGL.java similarity index 97% rename from core/src/processing/opengl/PShader.java rename to core/src/processing/opengl/PShaderOpenGL.java index f3c25e2169..f89874b61c 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShaderOpenGL.java @@ -33,20 +33,16 @@ import java.util.HashMap; /** - * This class encapsulates a GLSL shader program, including a vertex - * and a fragment shader. It is compatible with P2D and P3D, but not - * with the default renderer. + * The OpenGL (GLSL) implementation of {@link processing.core.PShader}. It + * encapsulates a GLSL shader program, including a vertex and a fragment + * shader. It is compatible with P2D and P3D, but not with the default + * renderer. * * Use the loadShader() function to load your shader code. * Note: It's strongly encouraged to use loadShader() to create - * a PShader object, rather than calling the PShader - * constructor manually. - * - * @webref rendering:shaders - * @webBrief This class encapsulates a GLSL shader program, - * including a vertex and a fragment shader + * a PShader object, rather than calling this constructor manually. */ -public class PShader implements PConstants { +public class PShaderOpenGL implements PShader, PConstants { static protected final int POINT = 0; static protected final int LINE = 1; static protected final int POLY = 2; @@ -169,7 +165,7 @@ public class PShader implements PConstants { protected int emissiveLoc; protected int shininessLoc; - public PShader() { + public PShaderOpenGL() { parent = null; pgl = null; context = -1; @@ -192,7 +188,7 @@ public PShader() { } - public PShader(PApplet parent) { + public PShaderOpenGL(PApplet parent) { this(); this.parent = parent; primaryPG = (PGraphicsOpenGL)parent.g; @@ -209,7 +205,7 @@ public PShader(PApplet parent) { * @param vertFilename name of the vertex shader * @param fragFilename name of the fragment shader */ - public PShader(PApplet parent, String vertFilename, String fragFilename) { + public PShaderOpenGL(PApplet parent, String vertFilename, String fragFilename) { this.parent = parent; primaryPG = (PGraphicsOpenGL)parent.g; pgl = primaryPG.pgl; @@ -231,7 +227,7 @@ public PShader(PApplet parent, String vertFilename, String fragFilename) { int vertType = getShaderType(vertexShaderSource, -1); int fragType = getShaderType(fragmentShaderSource, -1); if (vertType == -1 && fragType == -1) { - type = PShader.POLY; + type = PShaderOpenGL.POLY; } else if (vertType == -1) { type = fragType; } else if (fragType == -1) { @@ -248,7 +244,7 @@ public PShader(PApplet parent, String vertFilename, String fragFilename) { * @param vertURL network location of the vertex shader * @param fragURL network location of the fragment shader */ - public PShader(PApplet parent, URL vertURL, URL fragURL) { + public PShaderOpenGL(PApplet parent, URL vertURL, URL fragURL) { this.parent = parent; primaryPG = (PGraphicsOpenGL)parent.g; pgl = primaryPG.pgl; @@ -270,7 +266,7 @@ public PShader(PApplet parent, URL vertURL, URL fragURL) { int vertType = getShaderType(vertexShaderSource, -1); int fragType = getShaderType(fragmentShaderSource, -1); if (vertType == -1 && fragType == -1) { - type = PShader.POLY; + type = PShaderOpenGL.POLY; } else if (vertType == -1) { type = fragType; } else if (fragType == -1) { @@ -282,7 +278,7 @@ public PShader(PApplet parent, URL vertURL, URL fragURL) { } } - public PShader(PApplet parent, String[] vertSource, String[] fragSource) { + public PShaderOpenGL(PApplet parent, String[] vertSource, String[] fragSource) { this.parent = parent; primaryPG = (PGraphicsOpenGL)parent.g; pgl = primaryPG.pgl; @@ -304,7 +300,7 @@ public PShader(PApplet parent, String[] vertSource, String[] fragSource) { int vertType = getShaderType(vertexShaderSource, -1); int fragType = getShaderType(fragmentShaderSource, -1); if (vertType == -1 && fragType == -1) { - type = PShader.POLY; + type = PShaderOpenGL.POLY; } else if (vertType == -1) { type = fragType; } else if (fragType == -1) { @@ -1025,31 +1021,31 @@ static protected int getShaderType(String[] source, int defaultType) { String line = s.trim(); if (PApplet.match(line, colorShaderDefRegexp) != null) - return PShader.COLOR; + return PShaderOpenGL.COLOR; else if (PApplet.match(line, lightShaderDefRegexp) != null) - return PShader.LIGHT; + return PShaderOpenGL.LIGHT; else if (PApplet.match(line, texShaderDefRegexp) != null) - return PShader.TEXTURE; + return PShaderOpenGL.TEXTURE; else if (PApplet.match(line, texlightShaderDefRegexp) != null) - return PShader.TEXLIGHT; + return PShaderOpenGL.TEXLIGHT; else if (PApplet.match(line, polyShaderDefRegexp) != null) - return PShader.POLY; + return PShaderOpenGL.POLY; else if (PApplet.match(line, triShaderAttrRegexp) != null) - return PShader.POLY; + return PShaderOpenGL.POLY; else if (PApplet.match(line, quadShaderAttrRegexp) != null) - return PShader.POLY; + return PShaderOpenGL.POLY; else if (PApplet.match(line, pointShaderDefRegexp) != null) - return PShader.POINT; + return PShaderOpenGL.POINT; else if (PApplet.match(line, lineShaderDefRegexp) != null) - return PShader.LINE; + return PShaderOpenGL.LINE; else if (PApplet.match(line, pointShaderAttrRegexp) != null) - return PShader.POINT; + return PShaderOpenGL.POINT; else if (PApplet.match(line, pointShaderInRegexp) != null) - return PShader.POINT; + return PShaderOpenGL.POINT; else if (PApplet.match(line, lineShaderAttrRegexp) != null) - return PShader.LINE; + return PShaderOpenGL.LINE; else if (PApplet.match(line, lineShaderInRegexp) != null) - return PShader.LINE; + return PShaderOpenGL.LINE; } return defaultType; } @@ -1091,7 +1087,7 @@ protected boolean isPolyShader() { protected boolean checkPolyType(int type) { - if (getType() == PShader.POLY) return true; + if (getType() == PShaderOpenGL.POLY) return true; if (getType() != type) { if (type == TEXLIGHT) { diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index f34031f1ac..b97550f13c 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -5475,7 +5475,7 @@ protected void renderPolys(PGraphicsOpenGL g, PImage textureImage) { Texture tex = textureImage != null ? g.getTexture(textureImage) : null; boolean renderingFill = false, renderingStroke = false; - PShader shader = null; + PShaderOpenGL shader = null; IndexCache cache = tessGeo.polyIndexCache; for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) { if (is3D() || (tex != null && (firstLineIndexCache == -1 || @@ -5658,7 +5658,7 @@ protected void rawPolys(PGraphicsOpenGL g, PImage textureImage) { protected void renderLines(PGraphicsOpenGL g) { - PShader shader = g.getLineShader(); + PShaderOpenGL shader = g.getLineShader(); shader.bind(); IndexCache cache = tessGeo.lineIndexCache; @@ -5755,7 +5755,7 @@ protected void rawLines(PGraphicsOpenGL g) { protected void renderPoints(PGraphicsOpenGL g) { - PShader shader = g.getPointShader(); + PShaderOpenGL shader = g.getPointShader(); shader.bind(); IndexCache cache = tessGeo.pointIndexCache; diff --git a/java/src/processing/mode/java/JavaMode.java b/java/src/processing/mode/java/JavaMode.java index 31d189ff52..26c1963d42 100644 --- a/java/src/processing/mode/java/JavaMode.java +++ b/java/src/processing/mode/java/JavaMode.java @@ -328,7 +328,7 @@ protected String[] getSuggestionIncludeList() { "processing.event.KeyEvent", "processing.event.MouseEvent", "processing.event.TouchEvent", - "processing.opengl.PShader", + "processing.core.PShader", "processing.opengl.PGL", "java.util.ArrayList", From be0ee8266e07857f65937ec0a033707b9f6a286b Mon Sep 17 00:00:00 2001 From: Moon Date: Fri, 25 Sep 2026 15:05:11 -0400 Subject: [PATCH 2/6] Added blurb about 5.0 dev and 4.x (#1576) --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 6c19b6923e..aaebdb18ab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ +> [!NOTE] +> **Processing 5.0 development is underway on `main`.** +> +> - **New features and 5.0 work:** Open pull requests against `main`. +> - **Bug fixes for Processing 4:** Open pull requests against the [`4.x`](https://github.com/processing/processing4/tree/4.x) branch. +> +> Not sure which branch to use? Ask in the issue thread or on [Discord](https://discord.processing.org) in #devs-chat. + Processing Logo Processing is a flexible software sketchbook and a programming language designed for learning how to code. From da0b93217520b52c82672905b4613d661d35ea98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moon=20dav=C3=A9?= Date: Mon, 19 Oct 2026 17:54:38 -0400 Subject: [PATCH 3/6] Handle the edge case of Preprocessor passing back a string that says WEBGPU --- java/src/processing/mode/java/runner/Runner.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/java/src/processing/mode/java/runner/Runner.java b/java/src/processing/mode/java/runner/Runner.java index 3813928ea4..f241fe95c2 100644 --- a/java/src/processing/mode/java/runner/Runner.java +++ b/java/src/processing/mode/java/runner/Runner.java @@ -294,6 +294,18 @@ public boolean launchVirtualMachine(boolean present, String[] args) { } + // the results of `build.sketchRunner()` returns a string without being checked so this is actually a code-smell. + // This function should not exist. + // In a better world as I understand it now, we should be making some fixes in the PreProcessor + // There are two things to consider at this moment: + // When we use the constant P2D or P3D there is actually no check for converting this into the PConstant.* value. + // So it doesn't actually do anything. WEBGPU actually does do something which led to this function. + // TODO: Lets try to remove this function, or create something that considers P2D and P3D + // This will lead to cleaning up the PreProcessor and help us learn its architecture so we can move towards a healthy refactor. + static private boolean isWebGPU(String renderer) { + return "WEBGPU".equals(renderer) || PConstants.WEBGPU.equals(renderer); + } + protected StringList getMachineParams() { StringList params = new StringList(); @@ -343,7 +355,7 @@ protected StringList getMachineParams() { //params.append("-Dcom.apple.mrj.application.apple.menu.about.name=" + // build.getSketchClassName()); - if (PConstants.WEBGPU.equals(build.getSketchRenderer())) { + if (isWebGPU(build.getSketchRenderer())) { params.append("-XstartOnFirstThread"); } } @@ -518,7 +530,7 @@ protected StringList getSketchParams(boolean present, String[] args) { // Only disable AWT for the WebGPU renderer, which uses GLFW and // cannot coexist with AWT. All other renderers still depend on AWT // for display detection, displayWidth/displayHeight, pixelDensity(), etc. - if (PConstants.WEBGPU.equals(build.getSketchRenderer())) { + if (isWebGPU(build.getSketchRenderer())) { params.append(PApplet.ARGS_DISABLE_AWT); } From c9408ac157fd0e5d6c0cf3b28b0894bf4a1a0f10 Mon Sep 17 00:00:00 2001 From: Moon Date: Fri, 23 Oct 2026 07:43:13 -0400 Subject: [PATCH 4/6] Update libprocessing submodule (#1586) --- core/src/processing/webgpu/PWebGPU.java | 6 +++--- libprocessing | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/processing/webgpu/PWebGPU.java b/core/src/processing/webgpu/PWebGPU.java index fd3b5c751c..a17b27054b 100644 --- a/core/src/processing/webgpu/PWebGPU.java +++ b/core/src/processing/webgpu/PWebGPU.java @@ -204,17 +204,17 @@ public static void resetMatrix(long graphicsId) { } public static void translate(long graphicsId, float x, float y) { - processing_translate(graphicsId, x, y); + processing_translate(graphicsId, x, y, 0); checkError(); } public static void rotate(long graphicsId, float angle) { - processing_rotate(graphicsId, angle); + processing_rotate(graphicsId, angle, 0, 0, 1); checkError(); } public static void scale(long graphicsId, float x, float y) { - processing_scale(graphicsId, x, y); + processing_scale(graphicsId, x, y, 1); checkError(); } diff --git a/libprocessing b/libprocessing index 77f105be73..aaa0215fab 160000 --- a/libprocessing +++ b/libprocessing @@ -1 +1 @@ -Subproject commit 77f105be7307bc0b3552aba3cb9f24d1736aeda1 +Subproject commit aaa0215fabda64ce072ec3da3d524e884bf10e20 From c2e7cb6ffcb6691d5b533217c8a2bd22f100e0b0 Mon Sep 17 00:00:00 2001 From: Moon Date: Sun, 25 Oct 2026 03:32:25 -0400 Subject: [PATCH 5/6] Build updates for v5 (#1587) * update github actions to use JVM25, and to get submodules * Update documentation * Specify JVM 25 for gradle daemon * remove conditionals around enableWebGPU * Update github actions to install required linux packages --- .github/actions/setup/action.yml | 31 ++- .github/workflows/build.yml | 4 + .github/workflows/release.yml | 10 + BUILD.md | 97 +++---- app/build.gradle.kts | 5 +- build.gradle.kts | 9 +- core/build.gradle.kts | 261 ++++++++---------- gradle.properties | 2 +- gradle/gradle-daemon-jvm.properties | 1 + gradle/libs.versions.toml | 2 +- .../main/kotlin/ProcessingLibraryPlugin.kt | 3 +- .../src/main/kotlin/ProcessingPlugin.kt | 3 +- 12 files changed, 208 insertions(+), 220 deletions(-) create mode 100644 gradle/gradle-daemon-jvm.properties diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index cc65b83095..ae3da9a445 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -7,12 +7,41 @@ inputs: runs: using: "composite" steps: + # Mirrors libprocessing/.github/actions/setup, needed to build the Rust core on Linux + - name: Install Linux system dependencies + if: runner.os == 'Linux' + shell: bash + run: | + if ! command -v apt-get >/dev/null; then + echo "apt-get not available, skipping system dependencies" + exit 0 + fi + sudo apt-get update + sudo apt-get install -y g++ cmake pkg-config libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libasound2-dev libudev-dev libxkbcommon-x11-0 libwayland-dev libwayland-bin libxkbcommon-dev wayland-protocols libdecor-0-dev libegl1-mesa-dev libwayland-egl1-mesa libfontconfig1-dev + + - name: Build and install GLFW 3.4 + if: runner.os == 'Linux' + shell: bash + run: | + if ! command -v apt-get >/dev/null; then + exit 0 + fi + git clone --depth 1 --branch 3.4 https://github.com/glfw/glfw.git /tmp/glfw + cd /tmp/glfw + cmake -B build -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_DOCS=OFF -DGLFW_BUILD_WAYLAND=ON -DGLFW_BUILD_X11=ON + cmake --build build + sudo cmake --install build + sudo ldconfig + - name: Install Java uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '25' distribution: 'temurin' architecture: ${{ inputs.arch }} + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbca994d60..7f46dba606 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,6 +18,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup @@ -70,6 +72,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 04a4985699..a3f65ccfea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,6 +109,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup @@ -137,6 +139,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup @@ -183,6 +187,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup @@ -249,6 +255,8 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup @@ -304,6 +312,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Processing uses: ./.github/actions/setup diff --git a/BUILD.md b/BUILD.md index 2cc31446a4..d50b6b871d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -7,30 +7,24 @@ Great to see you are interested in contributing to Processing. To get started yo _**Note:** A paid subscription is **not** required. Everything needed to build and work on Processing is available for free in IntelliJ IDEA._ 1. [Download IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and install it. -1. Clone the `Processing4` repository locally. +1. Install [Rust](https://rustup.rs/). It is needed to build `libprocessing`, the native library behind the WebGPU renderer. +1. Clone the `processing4` repository locally, including its submodules (`git clone --recursive`, or `git submodule update --init --recursive` in an existing clone). 1. Open the cloned repository in **IntelliJ IDEA**. 1. When prompted, select **Trust Project**. (You can preview the project in Safe Mode, but you will not be able to build Processing.) 1. If IntelliJ asks whether to import the Gradle project, select **Load Gradle Project**. -1. Make sure IntelliJ and Gradle are both using **JDK 17**: +1. Make sure IntelliJ and Gradle are both using **JDK 25**: * Go to **`File > Project Structure > Project`** - * Set **Project SDK** to **JDK 17** (we recommend **Eclipse Temurin**) - * If needed, choose **Download JDK…** and install **Version 17** + * Set **Project SDK** to **JDK 25** (we recommend **Eclipse Temurin**) + * If needed, choose **Download JDK…** and install **Version 25** * Then go to **`Settings > Build, Execution, Deployment > Build Tools > Gradle`** - * Set **Gradle JVM** to the same **JDK 17** + * Set **Gradle JVM** to the same **JDK 25** (the project requests 25 in `gradle/gradle-daemon-jvm.properties`, so this is usually picked automatically) 1. Wait for Gradle sync to finish. 1. Click the green **Run** button in the top right to build and launch Processing. You can also use this menu to start a debug session. > [!TIP] > If you encounter any issues with this process, Read the [Troubleshooting and Setup Tips for IntelliJ IDEA](#troubleshooting-and-setup-tips-intellij-idea) -1. Clone the Processing4 repository to your machine locally -1. Open the cloned repository in IntelliJ IDEA CE -1. When prompted, select **Trust Project**. You can preview the project in Safe Mode but you won't be able to build Processing. -1. IntelliJ may ask if you want to load Gradle project. If you allow this, make sure you are using JDK version 17. -1. In the main menu, go to File > Project Structure > Project Settings > Project. -1. In the SDK Dropdown option, select a JDK version 17 or Download the jdk -1. Click the green Run Icon in the top right of the window. This is also where you can find the option to debug Processing. -1. Logs can be found in the `Build` or `Debug` pane on the bottom left of the window +Logs can be found in the `Build` or `Debug` pane on the bottom left of the window. ## VSCode @@ -52,7 +46,7 @@ If you prefer not to use an IDE, you can also build Processing directly from the ### Set Up the Environment -If you don't have them installed, you will need to install [Git](https://git-scm.com/downloads) and [Gradle](https://gradle.org/install/) first. Then follow these steps: +If you don't have them installed, you will need to install [Git](https://git-scm.com/downloads), [Gradle](https://gradle.org/install/) and [Rust](https://rustup.rs/) first. Then follow these steps: 1. **Clone the repository:** ```bash @@ -60,61 +54,29 @@ If you don't have them installed, you will need to install [Git](https://git-scm cd processing4 ``` -2. **Install Temurin JDK 17:** +2. **Install Temurin JDK 25:** - Download and install the appropriate version for your platform: - - - [Linux (x86)](https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz) - - [macOS (Apple Silicon)](https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.15_6.pkg) - - [Other platforms](https://adoptium.net/temurin/releases/?package=jdk&version=17&os=any&arch=any) - -### macOS: -```bash -brew install --cask temurin@17 -```` - -### Windows (using winget): -```bash -winget install --id=EclipseAdoptium.Temurin.17.JDK -e -``` - -### SDKMAN! - -[SDKMAN!](https://sdkman.io/) is a useful tool for developers working on multiple versions of the JVM. - -## WebGPU Support (Optional) - -To build Processing with the experimental WebGPU renderer, you need JDK 25, Rust, and jextract. - -### Install Temurin JDK 25 - -```bash -brew install --cask temurin@25 # macOS -``` - -### Install `jextract` + Download and install the appropriate version for your platform from [Adoptium](https://adoptium.net/temurin/releases/?package=jdk&version=25&os=any&arch=any), or use a package manager: -`jextract` generates Java bindings from C header files. -You can download it [here](https://jdk.java.net/jextract/) or install it using SDKMAN!: - -```bash -sdk install jextract -```` - -### Build with WebGPU + ```bash + brew install --cask temurin@25 # macOS + winget install --id=EclipseAdoptium.Temurin.25.JDK -e # Windows + ``` -```bash -./gradlew build -PenableWebGPU=true -``` + [SDKMAN!](https://sdkman.io/) is also a useful tool for developers working on multiple versions of the JVM. 3. **Set the `JAVA_HOME` environment variable:** -It may be necessary to set the `JAVA_HOME` environment variable to point to your Temurin JDK installation. + It may be necessary to set the `JAVA_HOME` environment variable to point to your Temurin JDK installation. ```bash - export JAVA_HOME=/path/to/temurin/jdk-17.0.15+6/ + export JAVA_HOME=/path/to/temurin/jdk-25/ ``` +4. **(Optional) Install `jextract`:** + + `jextract` generates the Java bindings for `libprocessing`. The build downloads it automatically, but if you already have it installed (for example with `sdk install jextract`), that copy will be used instead. + ### Build, Run, and Package Processing #### Build the Project (Required First Step) @@ -191,18 +153,18 @@ If you are specifically trying to run the `Processing CLI`, you can test command If you’re building Processing using IntelliJ IDEA and something’s not working, here are a few things that might help: -### Use the Correct JDK (temurin-17) +### Use the Correct JDK (temurin-25) -Make sure IntelliJ is using **temurin-17**, not another version. If building with WebGPU (`-PenableWebGPU=true`), use **temurin-25** instead. +Make sure IntelliJ is using **temurin-25**, not another version. 1. Go to **File > Project Structure > Project** -2. Set the **Project SDK** to: `temurin-17 java version "17.0.15"` +2. Set the **Project SDK** to: `temurin-25 java version "25"` ![JDK Selection](.github/media/troubleshooting-Intellij-setting-djk-version-manually.png) If it is not already installed, you can download it by: 1. Clicking the SDK input field and then selecting the `Download JDK...` option from the menu -2. Select Version: `17`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)` +2. Select Version: `25`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)` JDK Download @@ -212,6 +174,15 @@ Now go back to your main window and 1. Click the green Run Icon in the top right of the window. +### “libprocessing submodule directory not found” + +The `libprocessing` submodule hasn't been checked out. Run: + +```bash +git submodule update --init --recursive +``` + + ### “Duplicate content roots detected” You may see this warning in IntelliJ: diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ebbc09c8a1..7c6dd48b19 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -142,6 +142,7 @@ dependencies { @OptIn(ExperimentalComposeLibrary::class) testImplementation(compose.uiTest) testImplementation(kotlin("test")) + testImplementation(libs.mockito) testImplementation(libs.mockitoKotlin) testImplementation(libs.junitJupiter) testImplementation(libs.junitJupiterParams) @@ -442,10 +443,8 @@ tasks.register("includeJavaMode") { into(composeResources("modes/java/mode")) duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: false - tasks.register("includeJdk") { - val jdkVersion = if (enableWebGPU) 25 else 17 + val jdkVersion = 25 val jdkHome = project.the().launcherFor { languageVersion.set(JavaLanguageVersion.of(jdkVersion)) }.map { it.metadata.installationPath.asFile } diff --git a/build.gradle.kts b/build.gradle.kts index ca163e476c..95bed60f07 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,13 +12,8 @@ plugins { // Can be deleted after the migration to Gradle is complete layout.buildDirectory = file(".build") -val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: false -val javaVersion = if (enableWebGPU) "25" else "17" -val kotlinJvmTarget = if (enableWebGPU) { - org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_25 -} else { - org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 -} +val javaVersion = "25" +val kotlinJvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_25 allprojects { tasks.withType().configureEach { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 19b42773a8..857c1f98a4 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -12,17 +12,11 @@ repositories { maven { url = uri("https://jogamp.org/deployment/maven") } } -val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: false - sourceSets{ main{ java{ srcDirs("src") exclude("**/*.jnilib") - if (!enableWebGPU) { - exclude("processing/webgpu/**") - exclude("processing/ffi/**") - } } resources{ srcDirs("src") @@ -32,9 +26,6 @@ sourceSets{ test{ java{ srcDirs("test") - if (!enableWebGPU) { - exclude("processing/webgpu/**") - } } } } @@ -43,170 +34,160 @@ dependencies { implementation(libs.jogl) implementation(libs.gluegen) - if (enableWebGPU) { - val lwjglVersion = "3.3.6" - val lwjglNatives = when { - System.getProperty("os.name").lowercase().contains("mac") -> { - if (System.getProperty("os.arch").contains("aarch64")) { - "natives-macos-arm64" - } else { - "natives-macos" - } + val lwjglVersion = "3.3.6" + val lwjglNatives = when { + System.getProperty("os.name").lowercase().contains("mac") -> { + if (System.getProperty("os.arch").contains("aarch64")) { + "natives-macos-arm64" + } else { + "natives-macos" } - System.getProperty("os.name").lowercase().contains("win") -> "natives-windows" - System.getProperty("os.name").lowercase().contains("linux") -> "natives-linux" - else -> "natives-linux" } - - implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion")) - implementation("org.lwjgl", "lwjgl") - implementation("org.lwjgl", "lwjgl-glfw") - runtimeOnly("org.lwjgl", "lwjgl", classifier = lwjglNatives) - runtimeOnly("org.lwjgl", "lwjgl-glfw", classifier = lwjglNatives) + System.getProperty("os.name").lowercase().contains("win") -> "natives-windows" + System.getProperty("os.name").lowercase().contains("linux") -> "natives-linux" + else -> "natives-linux" } + implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion")) + implementation("org.lwjgl", "lwjgl") + implementation("org.lwjgl", "lwjgl-glfw") + runtimeOnly("org.lwjgl", "lwjgl", classifier = lwjglNatives) + runtimeOnly("org.lwjgl", "lwjgl-glfw", classifier = lwjglNatives) + testImplementation(libs.junit) } -if (enableWebGPU) { - val currentPlatform = PlatformUtils.detect() - val libprocessingDir = file("${project.rootDir}/libprocessing") +val currentPlatform = PlatformUtils.detect() +val libprocessingDir = file("${project.rootDir}/libprocessing") - if (!libprocessingDir.exists()) { - throw GradleException( - "libprocessing submodule directory not found at: ${libprocessingDir.absolutePath}\n" + - "Please initialize the submodule with: git submodule update --init --recursive" - ) - } - - val rustTargetDir = file("$libprocessingDir/target") - val nativeOutputDir = file("${layout.buildDirectory.get()}/native/${currentPlatform.target}") - - val ffiManifestPath = fileTree(libprocessingDir) { - include("**/processing_ffi/Cargo.toml") - }.files.firstOrNull()?.let { it.relativeTo(libprocessingDir).path } - ?: throw GradleException( - "Could not find processing_ffi Cargo.toml in libprocessing.\n" + - "Searched in: ${libprocessingDir.absolutePath}\n" + - "The libprocessing structure may have changed." - ) - - val buildRustRelease by tasks.registering(CargoBuildTask::class) { - cargoWorkspaceDir.set(libprocessingDir) - manifestPath.set(ffiManifestPath) - release.set(true) - cargoPath.set(PlatformUtils.getCargoPath()) - if (currentPlatform.os == "linux") { - features.set(listOf("x11", "wayland")) - } - outputLibrary.set(file("$rustTargetDir/release/${currentPlatform.libName}")) - - inputs.files(fileTree("$libprocessingDir/crates") { - include("**/src/**/*.rs") - include("**/Cargo.toml") - include("**/build.rs") - include("**/cbindgen.toml") - }) - inputs.file("$libprocessingDir/Cargo.toml") - inputs.file("$libprocessingDir/Cargo.lock") - - val headerDir = file("$libprocessingDir/${ffiManifestPath}").parentFile.resolve("include") - outputs.file("$headerDir/processing.h") - } +if (!libprocessingDir.exists()) { + throw GradleException( + "libprocessing submodule directory not found at: ${libprocessingDir.absolutePath}\n" + + "Please initialize the submodule with: git submodule update --init --recursive" + ) +} - val copyNativeLibs by tasks.registering(Copy::class) { - group = "rust" - description = "Copy processing library to build directory" +val rustTargetDir = file("$libprocessingDir/target") +val nativeOutputDir = file("${layout.buildDirectory.get()}/native/${currentPlatform.target}") + +val ffiManifestPath = fileTree(libprocessingDir) { + include("**/processing_ffi/Cargo.toml") +}.files.firstOrNull()?.let { it.relativeTo(libprocessingDir).path } + ?: throw GradleException( + "Could not find processing_ffi Cargo.toml in libprocessing.\n" + + "Searched in: ${libprocessingDir.absolutePath}\n" + + "The libprocessing structure may have changed." + ) + +val buildRustRelease by tasks.registering(CargoBuildTask::class) { + cargoWorkspaceDir.set(libprocessingDir) + manifestPath.set(ffiManifestPath) + release.set(true) + cargoPath.set(PlatformUtils.getCargoPath()) + if (currentPlatform.os == "linux") { + features.set(listOf("x11", "wayland")) + } + outputLibrary.set(file("$rustTargetDir/release/${currentPlatform.libName}")) + + inputs.files(fileTree("$libprocessingDir/crates") { + include("**/src/**/*.rs") + include("**/Cargo.toml") + include("**/build.rs") + include("**/cbindgen.toml") + }) + inputs.file("$libprocessingDir/Cargo.toml") + inputs.file("$libprocessingDir/Cargo.lock") + + val headerDir = file("$libprocessingDir/${ffiManifestPath}").parentFile.resolve("include") + outputs.file("$headerDir/processing.h") +} - dependsOn(buildRustRelease) +val copyNativeLibs by tasks.registering(Copy::class) { + group = "rust" + description = "Copy processing library to build directory" - from("$rustTargetDir/release") { - include(currentPlatform.libName) - } + dependsOn(buildRustRelease) - into(nativeOutputDir) + from("$rustTargetDir/release") { + include(currentPlatform.libName) } - val bundleNativeLibs by tasks.registering(Copy::class) { - group = "rust" - description = "Bundle native library into resources" - - dependsOn(copyNativeLibs) - - from(nativeOutputDir) - into("${sourceSets.main.get().output.resourcesDir}/native/${currentPlatform.target}") - } + into(nativeOutputDir) +} - val cleanRust by tasks.registering(CargoCleanTask::class) { - cargoWorkspaceDir.set(libprocessingDir) - manifestPath.set(ffiManifestPath) - cargoPath.set(PlatformUtils.getCargoPath()) +val bundleNativeLibs by tasks.registering(Copy::class) { + group = "rust" + description = "Bundle native library into resources" - mustRunAfter(buildRustRelease) - } + dependsOn(copyNativeLibs) - tasks.named("clean") { - dependsOn(cleanRust) - } + from(nativeOutputDir) + into("${sourceSets.main.get().output.resourcesDir}/native/${currentPlatform.target}") +} - val generatedJavaDir = file("${layout.buildDirectory.get()}/generated/sources/jextract/java") +val cleanRust by tasks.registering(CargoCleanTask::class) { + cargoWorkspaceDir.set(libprocessingDir) + manifestPath.set(ffiManifestPath) + cargoPath.set(PlatformUtils.getCargoPath()) - sourceSets.main { - java.srcDirs(generatedJavaDir) - } + mustRunAfter(buildRustRelease) +} - val jextractVersionString = "22-jextract+6-47" - val jextractDirectory = file("${gradle.gradleUserHomeDir}/jextract-22") - val jextractTarballFile = file("${gradle.gradleUserHomeDir}/jextract-$jextractVersionString.tar.gz") +tasks.named("clean") { + dependsOn(cleanRust) +} - val downloadJextract by tasks.registering(DownloadJextractTask::class) { - jextractVersion.set(jextractVersionString) - platform.set(currentPlatform.jextractPlatform) - jextractDir.set(jextractDirectory) - downloadTarball.set(jextractTarballFile) +val generatedJavaDir = file("${layout.buildDirectory.get()}/generated/sources/jextract/java") - onlyIf { !jextractDirectory.exists() } - } +val jextractVersionString = "22-jextract+6-47" +val jextractDirectory = file("${gradle.gradleUserHomeDir}/jextract-22") +val jextractTarballFile = file("${gradle.gradleUserHomeDir}/jextract-$jextractVersionString.tar.gz") - val makeJextractExecutable by tasks.registering(Exec::class) { - group = "rust" - description = "Make jextract binary executable on Unix systems" +val downloadJextract by tasks.registering(DownloadJextractTask::class) { + jextractVersion.set(jextractVersionString) + platform.set(currentPlatform.jextractPlatform) + jextractDir.set(jextractDirectory) + downloadTarball.set(jextractTarballFile) - dependsOn(downloadJextract) - onlyIf { !System.getProperty("os.name").lowercase().contains("windows") } + onlyIf { !jextractDirectory.exists() } +} - val jextractBin = file("$jextractDirectory/bin/jextract") - commandLine("chmod", "+x", jextractBin.absolutePath) - } +val makeJextractExecutable by tasks.registering(Exec::class) { + group = "rust" + description = "Make jextract binary executable on Unix systems" - val generateJavaBindings by tasks.registering(GenerateJextractBindingsTask::class) { - dependsOn(buildRustRelease) + dependsOn(downloadJextract) + onlyIf { !System.getProperty("os.name").lowercase().contains("windows") } - val userJextract = JextractUtils.findUserJextract() - if (userJextract == null) { - dependsOn(downloadJextract, makeJextractExecutable) - } + val jextractBin = file("$jextractDirectory/bin/jextract") + commandLine("chmod", "+x", jextractBin.absolutePath) +} - // Find header file dynamically based on FFI manifest location - val headerDir = file("$libprocessingDir/${ffiManifestPath}").parentFile.resolve("include") - headerFile.set(file("$headerDir/processing.h")) - outputDirectory.set(generatedJavaDir) - targetPackage.set("processing.ffi") +val generateJavaBindings by tasks.registering(GenerateJextractBindingsTask::class) { + dependsOn(buildRustRelease) - jextractPath.set(userJextract ?: "$jextractDirectory/bin/${JextractUtils.getExecutableName()}") + val userJextract = JextractUtils.findUserJextract() + if (userJextract == null) { + dependsOn(downloadJextract, makeJextractExecutable) } - tasks.named("compileJava") { - dependsOn(generateJavaBindings) - } + // Find header file dynamically based on FFI manifest location + val headerDir = file("$libprocessingDir/${ffiManifestPath}").parentFile.resolve("include") + headerFile.set(file("$headerDir/processing.h")) + outputDirectory.set(generatedJavaDir) + targetPackage.set("processing.ffi") - tasks.named("compileKotlin") { - dependsOn(generateJavaBindings) - } + jextractPath.set(userJextract ?: "$jextractDirectory/bin/${JextractUtils.getExecutableName()}") +} - tasks.named("processResources") { - dependsOn(bundleNativeLibs) - } +// Registering the task output (rather than the bare directory) makes every task that +// reads the main sources (compileJava, compileKotlin, sourcesJar, javadoc) depend on it +sourceSets.main { + java.srcDir(generateJavaBindings.flatMap { it.outputDirectory }) +} + +tasks.named("processResources") { + dependsOn(bundleNativeLibs) } mavenPublishing{ diff --git a/gradle.properties b/gradle.properties index f2f02a91ed..8ea07c4e94 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=org.processing -version=4.5.6 +version=5.0.0 diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties new file mode 100644 index 0000000000..d35f707fd9 --- /dev/null +++ b/gradle/gradle-daemon-jvm.properties @@ -0,0 +1 @@ +toolchainVersion=25 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4455f92044..c72067574a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ kaml = { module = "com.charleskorn.kaml:kaml", version = "0.65.0" } junit = { module = "junit:junit", version = "4.13.2" } junitJupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "jupiter" } junitJupiterParams = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "jupiter" } -mockito = { module = "org.mockito:mockito-core", version = "4.11.0" } +mockito = { module = "org.mockito:mockito-core", version = "5.20.0" } mockitoKotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "5.4.0" } antlr = { module = "org.antlr:antlr4", version = "4.7.2" } eclipseJDT = { module = "org.eclipse.jdt:org.eclipse.jdt.core", version = "3.16.0" } diff --git a/gradle/plugins/library/src/main/kotlin/ProcessingLibraryPlugin.kt b/gradle/plugins/library/src/main/kotlin/ProcessingLibraryPlugin.kt index 9cac968141..d491d9b641 100644 --- a/gradle/plugins/library/src/main/kotlin/ProcessingLibraryPlugin.kt +++ b/gradle/plugins/library/src/main/kotlin/ProcessingLibraryPlugin.kt @@ -36,9 +36,8 @@ class ProcessingLibraryPlugin : Plugin { target.dependencies.add("compileOnly", "org.processing:core:$processingVersion") } } - val javaVersionOverride = target.findProperty("enableWebGPU")?.toString()?.toBoolean()?.let { if (it) 25 else 17 } ?: 17 target.extensions.configure(JavaPluginExtension::class.java) { extension -> - extension.toolchain.languageVersion.set(JavaLanguageVersion.of(javaVersionOverride)) + extension.toolchain.languageVersion.set(JavaLanguageVersion.of(25)) } target.plugins.withType(JavaPlugin::class.java) { diff --git a/java/gradle/src/main/kotlin/ProcessingPlugin.kt b/java/gradle/src/main/kotlin/ProcessingPlugin.kt index 6e1d7d96f6..358669f3d0 100644 --- a/java/gradle/src/main/kotlin/ProcessingPlugin.kt +++ b/java/gradle/src/main/kotlin/ProcessingPlugin.kt @@ -38,8 +38,7 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact val settings = project.findProperty("processing.settings") as String? val root = project.findProperty("processing.root") as String? - val webgpu = (project.findProperty("processing.webgpu") as String?)?.toBoolean() ?: false - val javaVersion = if (webgpu) 25 else 17 + val javaVersion = 25 // Apply the Java plugin to the Project, equivalent of // plugins { From cd50e02e5a8cdf41f8bb165b6ebd85feeeeac543 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 25 Oct 2026 03:33:01 -0400 Subject: [PATCH 6/6] docs: add pepc84 as a contributor for code (#1575) * docs: update CONTRIBUTORS.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 11 ++++++++++- CONTRIBUTORS.md | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9beea4235e..52069c4ab2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1742,6 +1742,15 @@ "contributions": [ "bug" ] + }, + { + "login": "pepc84", + "name": "Pep", + "avatar_url": "https://avatars.githubusercontent.com/u/57294729?v=4", + "profile": "http://pepc84.com", + "contributions": [ + "code" + ] } ], "repoType": "github", @@ -1749,4 +1758,4 @@ "skipCi": true, "commitConvention": "angular", "commitType": "docs" -} \ No newline at end of file +} diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ad532703d8..0c28cc9405 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -257,6 +257,8 @@ _Note: due to GitHub's limitations, this repository's [Contributors](https://git Salmane Khalili
Salmane Khalili

🐛 Nick McIntyre
Nick McIntyre

⚠️ Elijah Baron
Elijah Baron

🐛 + Kate Hollenbach
Kate Hollenbach

🐛 + Pep
Pep

💻