Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6801baf
*:ꔫ:*Renderer Project*:ꔫ:*
catilac Oct 11, 2025
ebd4df6
Create workspaces for ffi and the renderer (#1275)
catilac Oct 14, 2025
32c31b5
Inital scaffold for libprocessing ffi.
tychedelia Oct 15, 2025
a596ad2
Remove EAP.
tychedelia Oct 15, 2025
9ae1d01
Update docs.
tychedelia Oct 15, 2025
8f2542b
Factor out gradle utils. Add flag for disabling webgpu and enforcing …
tychedelia Oct 16, 2025
0078714
Remove processing.h
tychedelia Oct 16, 2025
5662716
Set java version for all projects.
tychedelia Oct 16, 2025
7152360
Merge pull request #1287 from tychedelia/1270-ffi-scaffold
tychedelia Oct 16, 2025
33b8b52
libprocessing ffi error handling (#1293)
tychedelia Oct 17, 2025
bc5a524
Basic app lifecycle / surface creation.
tychedelia Oct 22, 2025
fa83874
Throw when not on macos.
tychedelia Oct 22, 2025
2232a0d
Merge pull request #1302 from tychedelia/1271-surface-creation
tychedelia Oct 27, 2025
89f8a65
Implement `background` method (#1308)
tychedelia Nov 10, 2025
1ee012e
Support for windows surfaces. (#1310)
tychedelia Nov 10, 2025
351737c
Implement basic rendering flow (#1322)
tychedelia Nov 20, 2025
f6eaf88
libprocessing submodule
catilac Nov 21, 2025
6eddaf4
--recursive when cloning repo
catilac Nov 21, 2025
dc359d1
Enable submodule checkout in Gradle workflow
Stefterv Nov 24, 2025
39cca3d
Enable submodules in checkout steps
Stefterv Nov 24, 2025
8400db5
Wayland support with new WebGPU renderer
catilac Nov 24, 2025
b40adac
Merge pull request #1340 from catilac/libprocessing-submodule
tychedelia Nov 24, 2025
01f8923
Merge branch 'the-wgpu-moment' into 1305-wayland
catilac Nov 24, 2025
2b9f115
Merge pull request #1343 from catilac/1305-wayland
tychedelia Nov 25, 2025
eee55b5
Gradle fixes from libprocessing refactor. (#1346)
tychedelia Nov 26, 2025
408d542
Updates from libprocessing. (#1392)
tychedelia Jan 28, 2026
4127dc0
Updates from libprocessing.
tychedelia May 2, 2026
fef550b
Merge remote-tracking branch 'origin/main' into the-wgpu-moment
tychedelia May 2, 2026
67ac864
Fixes for compat with main 17.
tychedelia May 3, 2026
079b879
Fixup docs.
tychedelia May 3, 2026
601af33
Upgrade to jdk-25.
tychedelia May 3, 2026
4b3a06a
Upgrade to jdk-25.
tychedelia May 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ generated/
/java/gradle/build
/core/examples/build
/java/gradle/example/.processing

libprocessing/ffi/include/*
/app/windows/obj
/java/android/example/build
/java/android/example/.processing
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "libprocessing"]
path = libprocessing
url = https://github.com/processing/libprocessing
59 changes: 49 additions & 10 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,62 @@ If you don't have them installed, you will need to install [Git](https://git-scm

1. **Clone the repository:**
```bash
git clone https://github.com/processing/processing4.git
git clone --recursive https://github.com/processing/processing4.git
cd processing4
```

2. **Install Temurin JDK 17:**
Download and install the appropriate version for your platform:

Processing requires the Temurin distribution of OpenJDK.

- [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)
You can download it from [Adoptium](https://adoptium.net/), from [GitHub releases](https://github.com/adoptium/temurin17-binaries/releases),
or find it in the package manager for your platform.

### 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`

`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
./gradlew build -PenableWebGPU=true
```

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.

```bash
export JAVA_HOME=/path/to/temurin/jdk-17.0.15+6/
export JAVA_HOME=/path/to/temurin/jdk-17/
```

### Build, Run, and Package Processing
Expand Down Expand Up @@ -138,10 +178,10 @@ If you’re building Processing using IntelliJ IDEA and something’s not workin

### Use the Correct JDK (temurin-17)

Make sure IntelliJ is using **temurin-17**, not another version. Some users have reported issues with ms-17.
Make sure IntelliJ is using **temurin-17**, not another version. If building with WebGPU (`-PenableWebGPU=true`), use **temurin-25** instead.

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-17`

![JDK Selection](.github/media/troubleshooting-Intellij-setting-djk-version-manually.png)

Expand All @@ -155,7 +195,6 @@ If it is not already installed, you can download it by:
Now go back to your main window and
1. Click the green Run Icon in the top right of the window.


### “Duplicate content roots detected”

You may see this warning in IntelliJ:
Expand Down
39 changes: 25 additions & 14 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,17 @@ compose.desktop {
application {
mainClass = "processing.app.ProcessingKt"

jvmArgs(*listOf(
Pair("processing.version", rootProject.version),
Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE),
Pair("processing.contributions.source", "https://contributions.processing.org/contribs"),
Pair("processing.download.page", "https://processing.org/download/"),
Pair("processing.download.latest", "https://processing.org/download/latest.txt"),
Pair("processing.tutorials", "https://processing.org/tutorials/"),
).map { "-D${it.first}=${it.second}" }.toTypedArray())
jvmArgs(
"--enable-native-access=ALL-UNNAMED", // Required for Java 25 native library access
*listOf(
Pair("processing.version", rootProject.version),
Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE),
Pair("processing.contributions.source", "https://contributions.processing.org/contribs"),
Pair("processing.download.page", "https://processing.org/download/"),
Pair("processing.download.latest", "https://processing.org/download/latest.txt"),
Pair("processing.tutorials", "https://processing.org/tutorials/"),
).map { "-D${it.first}=${it.second}" }.toTypedArray()
)

nativeDistributions{
modules("jdk.jdi", "java.compiler", "jdk.accessibility", "jdk.zipfs", "java.management.rmi", "java.scripting", "jdk.httpserver")
Expand Down Expand Up @@ -432,8 +435,15 @@ tasks.register<Copy>("includeJavaMode") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dirPermissions { unix("rwx------") }
}
val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: false

tasks.register<Copy>("includeJdk") {
from(Jvm.current().javaHome.absolutePath)
val jdkVersion = if (enableWebGPU) 25 else 17
val jdkHome = project.the<JavaToolchainService>().launcherFor {
languageVersion.set(JavaLanguageVersion.of(jdkVersion))
}.map { it.metadata.installationPath.asFile }

from(jdkHome)
destinationDir = composeResources("jdk").get().asFile

fileTree(destinationDir).files.forEach { file ->
Expand Down Expand Up @@ -516,7 +526,7 @@ tasks.register("includeProcessingResources"){
finalizedBy("signResources")
}

tasks.register("signResources"){
tasks.register("signResources") {
onlyIf {
OperatingSystem.current().isMacOsX
&&
Expand Down Expand Up @@ -561,10 +571,11 @@ tasks.register("signResources"){
exclude("*.jar")
exclude("*.so")
exclude("*.dll")
}.forEach{ file ->
exec {
commandLine("codesign", "--timestamp", "--force", "--deep","--options=runtime", "--sign", "Developer ID Application", file)
}
}.forEach{ f ->
ProcessBuilder("codesign", "--timestamp", "--force", "--deep", "--options=runtime", "--sign", "Developer ID Application", f.absolutePath)
.inheritIO()
.start()
.waitFor()
}
jars.forEach { file ->
FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos ->
Expand Down
29 changes: 29 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,35 @@ 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
}

allprojects {
tasks.withType<JavaCompile>().configureEach {
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
compilerOptions {
jvmTarget.set(kotlinJvmTarget)
}
}

plugins.withType<JavaPlugin> {
extensions.configure<JavaPluginExtension> {
toolchain {
languageVersion.set(JavaLanguageVersion.of(javaVersion.toInt()))
}
}
}
}

// Configure the dependencyUpdates task
tasks {
dependencyUpdates {
Expand Down
7 changes: 7 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
}
56 changes: 56 additions & 0 deletions buildSrc/src/main/kotlin/processing/gradle/CargoBuildTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package processing.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.process.ExecOperations
import javax.inject.Inject

abstract class CargoBuildTask : DefaultTask() {

@get:Inject
abstract val execOperations: ExecOperations

@get:InputDirectory
abstract val cargoWorkspaceDir: DirectoryProperty

@get:Input
abstract val manifestPath: Property<String>

@get:Input
abstract val release: Property<Boolean>

@get:Input
abstract val cargoPath: Property<String>

@get:OutputFile
abstract val outputLibrary: RegularFileProperty

init {
group = "rust"
description = "Builds Rust library using cargo"

// release by default
release.convention(true)
}

@TaskAction
fun build() {
val buildType = if (release.get()) "release" else "debug"
logger.lifecycle("Building Rust library ($buildType mode)...")

val args = mutableListOf("build")
if (release.get()) {
args.add("--release")
}
args.add("--manifest-path")
args.add(manifestPath.get())

execOperations.exec {
workingDir = cargoWorkspaceDir.get().asFile
commandLine = listOf(cargoPath.get()) + args
}
}
}
38 changes: 38 additions & 0 deletions buildSrc/src/main/kotlin/processing/gradle/CargoCleanTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package processing.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.process.ExecOperations
import javax.inject.Inject

abstract class CargoCleanTask : DefaultTask() {

@get:Inject
abstract val execOperations: ExecOperations

@get:InputDirectory
abstract val cargoWorkspaceDir: DirectoryProperty

@get:Input
abstract val manifestPath: Property<String>

@get:Input
abstract val cargoPath: Property<String>

init {
group = "rust"
description = "Cleans Rust build artifacts"
}

@TaskAction
fun clean() {
logger.lifecycle("Cleaning Rust build artifacts...")

execOperations.exec {
workingDir = cargoWorkspaceDir.get().asFile
commandLine(cargoPath.get(), "clean", "--manifest-path", manifestPath.get())
}
}
}
60 changes: 60 additions & 0 deletions buildSrc/src/main/kotlin/processing/gradle/DownloadJextractTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package processing.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import java.net.URI

abstract class DownloadJextractTask : DefaultTask() {

@get:Input
abstract val jextractVersion: Property<String>

@get:Input
abstract val platform: Property<String>

@get:OutputDirectory
abstract val jextractDir: DirectoryProperty

@get:Internal
abstract val downloadTarball: RegularFileProperty

init {
group = "rust"
description = "Downloads and extracts jextract for the current platform"
}

@TaskAction
fun download() {
val version = jextractVersion.get()
val plat = platform.get()
val fileName = "openjdk-$version" + "_${plat}_bin.tar.gz"
val downloadUrl = "https://download.java.net/java/early_access/jextract/22/6/$fileName"
val tarFile = downloadTarball.get().asFile

if (!tarFile.exists()) {
logger.lifecycle("Downloading jextract from $downloadUrl")
try {
tarFile.outputStream().use { output ->
URI.create(downloadUrl).toURL().openStream().use { input ->
input.copyTo(output)
}
}
} catch (e: Exception) {
throw GradleException("Failed to download jextract: ${e.message}", e)
}
}

val extractDir = jextractDir.get().asFile
logger.lifecycle("Extracting jextract to ${extractDir.parent}")
project.copy {
from(project.tarTree(tarFile))
into(extractDir.parent)
}

logger.lifecycle("jextract extracted to: $extractDir")
}
}
Loading
Loading