# Launcher for Multi-Renderer PApplets

**URL:** <https://discourse.processing.org/t/launcher-for-multi-renderer-papplets/46764>\
**Category:** Gallery\
**Created:** [July 20, 2025, 7:52pm UTC](https://discourse.processing.org/t/launcher-for-multi-renderer-papplets/46764 "2025-07-20T19:52:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [July 20, 2025, 7:52pm UTC](https://discourse.processing.org/t/launcher-for-multi-renderer-papplets/46764/1 "2025-07-20T19:52:01Z")

</div>

Hello folks!

My exploration of a launcher for PApplets with different renderers.

This was used primarily for testing Windows scaling on my W10 system and how it affects the sketch window.

Code:

```processing
/**
 * Launcher for Multi-Renderer PApplets
 * 
 * Author: glv
 * Date: 2025-07-07
 * 
 * Description:
 * Launches four separate Processing sketches (PApplets) using different renderers:
 * - JAVA2D
 * - P2D
 * - P3D
 * - FX2D
 * 
 * Each renderer runs in its own thread, with readiness flags for communication.
 * Allows visual comparison of renderer behavior and DPI scaling issues on Windows.
 * 
 * Notes:
 * - Uses `volatile` flags to ensure safe thread communication.
 * - Each PApplet has a window title and custom location.
 * - Both lambda and traditional Runnable launch methods shown for `app_0`.
 * - Can be extended for inter-applet communication or benchmarking.
 * 
 * Assisted by: ChatGPT (OpenAI)
 */

// Processing JavaFX library
import processing.javafx.*;

// Renderer Applets:
renderApp_0 app_0; // JAVA2D
renderApp_1 app_1; // P2D
renderApp_2 app_2; // P3D
renderApp_3 app_3; // FX2D

// Shared volatile flags for thread safety
volatile boolean ready_0 = false;
volatile boolean ready_1 = false;
volatile boolean ready_2 = false;
volatile boolean ready_3 = false;

boolean ready_p0 = false;
boolean ready_p1 = false;
boolean ready_p2 = false;
boolean ready_p3 = false;

int ws = 200;
int sp;

boolean db = false; // Debug true or false

boolean pr = false;

void settings() {
  size(ws, ws);
  sp = 300;
}

void setup() {
  surface.setTitle("Launcher");
  surface.setVisible(true);
  surface.setLocation(0 * sp, 10);

  displayDensity(1); // Use if necessary

  // app_0 Lambda Thread (active)
  app_0 = new renderApp_0();
  Thread thread_0 = new Thread(() -> PApplet.runSketch(new String[]{"renderapp_0"}, app_0));
  thread_0.start();

  // app_0 Traditional Runnable (commented out)
  /*
  app_0 = new renderApp_0();
  Runnable runnable_0 = new Runnable() {
    @Override
    public void run() {
      PApplet.runSketch(new String[]{"renderapp_0"}, app_0);
    }
  };
  Thread thread_0 = new Thread(runnable_0);
  thread_0.start();
  */

  // app_1
  app_1 = new renderApp_1();
  Thread thread_1 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_1"}, app_1));
  thread_1.start();

  // app_2
  app_2 = new renderApp_2();
  Thread thread_2 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_2"}, app_2));
  thread_2.start();

  // app_3 This is 1.25x larger on my W10 PC because of windows scaling settings!
  app_3 = new renderApp_3();
  Thread thread_3 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_3"}, app_3));
  thread_3.start();
}

void draw() {
  background(255);
  translate(width/2, height/2);

  fill(0);
  textSize(24);
  textAlign(CENTER, CENTER);
  text("Launcher JAVA2D", 0, 0);

  checkStatus();
}

void checkStatus() {
  if (ready_0 && !ready_p0) {
    println("0:", frameCount, millis(), ready_0);
    ready_p0 = true;
  }

  if (ready_1 && !ready_p1) {
    println("1:", frameCount, millis(), ready_1);
    ready_p1 = true;
  }

  if (ready_2 && !ready_p2) {
    println("2:", frameCount, millis(), ready_2);
    ready_p2 = true;
  }

  if (ready_3 && !ready_p3) {
    println("3:", frameCount, millis(), ready_3);
    ready_p3 = true;
  }
}

// ****************************************************************

// JAVA2D
class renderApp_0 extends PApplet {
  void settings() {
    if (db) delay(1000);
    size(ws, ws, JAVA2D);
  }

  void setup() {
    surface.setVisible(true);
    surface.setTitle("R0 JAVA2D");
    //surface.setLocation(1*sp, 10);
    surface.setLocation(1 * sp * 4/5, 10); // Adjust for scaling of 1.25x (5/4)
    println("R0 JAVA2D");

    ready_0 = true;
  }

  void draw() {
    background(255);
    translate(width/2, 2 * height/3);

    fill(0);
    textSize(24);
    textAlign(CENTER, CENTER);
    text("Renderer 0: \r\n JAVA2D", 0, -height/2);

    strokeWeight(2);
    line(-50, 50, 50, -50);
    line(-50, -50, 50, 50);
  }
}

// ****************************************************************

// P2D
class renderApp_1 extends PApplet {
  void settings() {
    if (db) delay(2000);
    size(ws, ws, P2D);

    //noSmooth();
    smooth(4);
  }

  void setup() {
    surface.setVisible(true);
    surface.setTitle("R1 P2D");
    surface.setLocation(2 * sp, 10);

    println("R1 P2D:");
    println(2 * sp);
    
    //ortho();
  }

  void draw() {
    background(255);
    translate(width/2, 2 * height/3);

    fill(0);
    textSize(24);
    textAlign(CENTER, CENTER);
    text("Renderer 1: \r\n P2D", 0, -height/2);

    strokeWeight(2);
    line(-50, 50, 50, -50);
    line(-50, -50, 50, 50);
    
    ready_1 = true;
  }
}

// ****************************************************************

// P3D
class renderApp_2 extends PApplet {
  void settings() {
    if (db) delay(3000);
    size(ws, ws, P3D);
  }

  void setup() {
    surface.setVisible(true);
    surface.setTitle("R2 P3D");
    surface.setLocation(3 * sp, 10);

    println("R2 P3D");
    println(3 * sp);

    ready_2 = true;
  }

  void draw() {
    background(255);
    translate(width/2, height/2);
    lights();

    push();
    translate(0, height/ 8);
    lights();
    fill(0, 255, 0);
    rotateY((frameCount % 360) * (TAU/360));
    //noStroke();
    stroke(128+64);
    sphere(50);
    pop();
    
    //hint(DISABLE_DEPTH_TEST);
    //ortho();
    noLights();
    fill(0);
    textSize(24);
    textAlign(CENTER, CENTER);
    text("Renderer 2: \r\n P3D", 0, -height/3);
    //hint(ENABLE_DEPTH_TEST);        
  }
}

// ****************************************************************

// FX2D
class renderApp_3 extends PApplet {
  boolean tog;
  
  void settings() {
    if (db) delay(4000);
    size(ws, ws, FX2D);
  }

  void setup() {
    surface.setVisible(true);
    surface.setTitle("R3 FX2D");
    //surface.setLocation(4 * sp, 10);
    surface.setLocation(4*sp*4/5, 10); // // Adjust for scaling of 1.25x (5/4)

    println("R3 FX2D:");
    println(4*sp);

    ready_3 = true;
  }

  void draw() {
    background(255);
    translate(width/2, 2 * height/3);

    fill(0);
    textSize(24);
    textAlign(CENTER, CENTER);
    text("Renderer 3: \r\n FX2D", 0, -height/2);

    strokeWeight(2);
    line(-50, 50, 50, -50);
    line(-50, -50, 50, 50);
  }
}

```

The _displayDensity()_ is 1 for my monitors until I upgrade.

Processing 4.4.4, W10 and Windows scaling of 125%:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/e/b/ebe76fa74125f0272c5305631468535d1cbed08b.png)

Processing 4.3.4, W10 and Windows scaling of 125%:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/f/bf8105af2435dcaff4570b747df16c4dc8ebc49f.png)

`:)`

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [April 20, 2026, 8:35pm UTC](https://discourse.processing.org/t/launcher-for-multi-renderer-papplets/46764/2 "2026-04-20T20:35:47Z")

</div>

Hello folks!

Some updates to the code:

> **Code 2026-04-20 v1.1.0**
>
> ```processing
> /**
> * Launcher for Multi-Renderer PApplets
> * 
> * Author: glv
> * Date: 2026-04-20
> * Version: 1.1.0
> *
> * Description:
> * Launches four separate Processing sketches (PApplets) using different renderers:
> * - JAVA2D
> * - P2D
> * - P3D
> * - FX2D
> * 
> * Each renderer runs in its own thread, with readiness flags for communication.
> * Allows visual comparison of renderer behavior and DPI scaling issues on Windows.
> * 
> * Notes:
> * - Uses `volatile` flags to ensure safe thread communication.
> * - Each PApplet has a window title and custom location.
> * - Both lambda and traditional Runnable launch methods shown for `app_0`.
> * - Can be extended for inter-applet communication or benchmarking.
> * - Insets are read and used to set offsets in surface.setLocation()
> * - Added code to force 1:1 pixel rendering with System.setProperty()
> *
> * Assisted by: ChatGPT (OpenAI) for illustrative code examples, editing, 
> * technical review, and drafting support; overall direction, integration, 
> * and final decisions by the author.
> */
> 
> import processing.awt.PSurfaceAWT;
> import java.awt.Insets;  
> 
> volatile int sx = 0;
> 
> // Processing JavaFX library
> import processing.javafx.*;
> 
> // Renderer Applets:
> renderApp_0 app_0; // JAVA2D
> renderApp_1 app_1; // P2D
> renderApp_2 app_2; // P3D
> renderApp_3 app_3; // FX2D
> 
> // Shared volatile flags for thread safety
> volatile boolean ready_0 = false;
> volatile boolean ready_1 = false;
> volatile boolean ready_2 = false;
> volatile boolean ready_3 = false;
> 
> boolean ready_p0 = false;
> boolean ready_p1 = false;
> boolean ready_p2 = false;
> boolean ready_p3 = false;
> 
> int w = 200;
> int h = 150;
> int sp;
> 
> boolean db = false; // Debug true or false
> 
> //static // Not required with Processing 4.5.3 (not tested on all other versions)
> {
> // JAVA2D: 
> // Forces 1:1 pixel rendering by disabling OS-level DPI scaling
> System.setProperty("sun.java2d.uiScale", "1.0");
> 
> // FX2D: 
> // Forces 1:1 pixel rendering for the JavaFX-based renderer
> System.setProperty("glass.win.uiScale", "1");
> }
> 
> int [] getInsets()
> {
> PSurfaceAWT.SmoothCanvas canvas = (PSurfaceAWT.SmoothCanvas) surface.getNative();
> Insets in = canvas.getFrame().getInsets();
>   
> println(" JAVA2D Insets L/T/R/B = " + in.left + " / " + in.top + " / " + in.right + " / " + in.bottom);    
>   
> return new int [] {in.left, in.top, in.right, in.bottom}; 
> }
> 
> void settings() {
> size(w, h);
> sp = h + 50;
> pixelDensity(1); // Adjust as required. Must be in settings!
> //noSmooth(); // Visual result was less desirable with this.
> }
> 
> void setup() {
> println();
>     
> //getInsets(); // Prints them
> int insetLeft = getInsets()[0];
> sx = -insetLeft; // Adjust surface.setLocation(sx, 0);
> println();
>     
> surface.setTitle("Launcher");
> surface.setVisible(true);
> surface.setLocation(sx, 0);    
>        
> textSize(20);
> println("displayDensity:", displayDensity());
> 
> // app_0 Lambda Thread
> app_0 = new renderApp_0();
> Thread thread_0 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_0"}, app_0));
> thread_0.start();
> 
> // app_0 Traditional Runnable (commented out)
> /*
> app_0 = new renderApp_0();
> Runnable runnable_0 = new Runnable() {
> @Override
> public void run() {
> PApplet.runSketch(new String[]{"renderApp_0"}, app_0);
> }
> };
> Thread thread_0 = new Thread(runnable_0);
> thread_0.start();
> */
> 
> // app_1
> app_1 = new renderApp_1();
> Thread thread_1 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_1"}, app_1));
> thread_1.start();
> 
> // app_2
> app_2 = new renderApp_2();
> Thread thread_2 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_2"}, app_2));
> thread_2.start();
> 
> // app_3  
> app_3 = new renderApp_3();
> Thread thread_3 = new Thread(() -> PApplet.runSketch(new String[]{"renderApp_3"}, app_3));
> thread_3.start();
> }
> 
> void draw() {
> background(255);
> 
> fill(0);
> textSize(20);
> textAlign(CENTER, TOP);
> text("Launcher JAVA2D", width/2, 10);
> 
> checkStatus();
> }
> 
> void checkStatus() {
> if (ready_0 && !ready_p0) {
> println("0:", frameCount, millis(), ready_0);
> println();
> ready_p0 = true;
> }
> 
> if (ready_1 && !ready_p1) {
> println("1:", frameCount, millis(), ready_1);
> println();
> ready_p1 = true;
> }
> 
> if (ready_2 && !ready_p2) {
> println("2:", frameCount, millis(), ready_2);
> println();
> ready_p2 = true;
> }
> 
> if (ready_3 && !ready_p3) {
> println("3:", frameCount, millis(), ready_3);
> println();
> ready_p3 = true;
> }
> }
> 
> // ****************************************************************
> 
> // JAVA2D
> class renderApp_0 extends PApplet {
>   
> void settings() {
> if (db) delay(1000);
> size(w, h, JAVA2D);
> }
> 
> void setup() {
> surface.setVisible(true);
> surface.setTitle("R0 JAVA2D");
> surface.setLocation(sx, 1*sp);
> println("R0 JAVA2D");
> 
> ready_0 = true;
> }
> 
> void draw() {
> background(255);
>     
> fill(0);
> textSize(20);
> textAlign(CENTER, TOP);
> text("R0: JAVA2D", width/2, 10);    
>     
> translate(width/2, height/2+10);
> strokeWeight(2);
> line(-50, 50, 50, -50);
> line(-50, -50, 50, 50);
> }
> }
> 
> // ****************************************************************
> 
> // P2D
> class renderApp_1 extends PApplet {
> void settings() {
> if (db) delay(2000);
> size(w, h, P2D);
> 
> //noSmooth();
> smooth(4);
> }
> 
> void setup() {
> surface.setVisible(true);
> surface.setTitle("R1 P2D");
> surface.setLocation(sx, 2*sp);
> 
> println("R1 P2D:");
> println(2 * sp);
>       
> ready_1 = true;  
> }
> 
> void draw() {
> background(255);
> 
> fill(0);
> textSize(20);
> textAlign(CENTER, TOP);
> text("R1: P2D", width/2, 10);
>     
> translate(width/2, height/2+10);
> strokeWeight(2);
> line(-50, 50, 50, -50);
> line(-50, -50, 50, 50);
> }
> }
> 
> // ****************************************************************
> 
> // P3D
> class renderApp_2 extends PApplet {
> void settings() {
> if (db) delay(3000);
> size(w, h, P3D);
> }
> 
> void setup() {
> surface.setVisible(true);
> surface.setTitle("R2 P3D");
> surface.setLocation(sx, 3*sp);
> 
> println("R2 P3D");
> println(3 * sp);
> 
> ready_2 = true;
> }
> 
> void draw() {
> background(255);
>     
> fill(0);
> textSize(20);
> textAlign(CENTER, TOP);
> text("R2: P3D", width/2, 10);  
>     
> push();
> translate(width/2, height/2 +10);
> 
> lights();
> fill(0, 255, 0);
> float div = 360*2;
> rotateY((frameCount % div) * (TAU/div));
> noFill();
> //noStroke();
> stroke(0);
> strokeWeight(1);
> sphereDetail(6);
> sphere(50);
> pop();       
> }
> }
> 
> // ****************************************************************
> 
> // FX2D
> class renderApp_3 extends PApplet {
>   
> void settings() {
> if (db) delay(4000);
> size(w, h, FX2D);
> }
> 
> void setup() {
> surface.setVisible(true);
> surface.setTitle("R3 FX2D");
> surface.setLocation(sx, 4*sp);
> 
> println("R3 FX2D:");
> println(4*sp);
> 
> ready_3 = true;
> }
> 
> void draw() {
> background(255);
>     
> fill(0);
> textSize(20);
> textAlign(CENTER, TOP);
> text("R3: FX2D", width/2, 10);
>       
> translate(width/2, height/2 +10);
> strokeWeight(2);
> line(-50, 50, 50, -50);
> line(-50, -50, 50, 50);
> }
> }
> 
> ```

`:)`

---

<div class="post-metadata">

**Author:** ![adaptinnovative](https://avatars.discourse-cdn.com/v4/letter/a/2acd7d/32.png) [@adaptinnovative](https://discourse.processing.org/u/adaptinnovative)\
**Post date:** [April 26, 2026, 2:26pm UTC](https://discourse.processing.org/t/launcher-for-multi-renderer-papplets/46764/3 "2026-04-26T14:26:58Z")

</div>

I love this. I can see how this can work with my project as well

however I use a very old version 1.51
