# Java to Python (PixelFlow library)

**URL:** <https://discourse.processing.org/t/java-to-python-pixelflow-library/4885>\
**Category:** Processing.py\
**Created:** [October 25, 2018, 8:27pm UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885 "2018-10-25T20:27:50Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [October 25, 2018, 8:27pm UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/1 "2018-10-25T20:27:50Z")

</div>

Hi,

I’m having difficulting porting the “[Fluid\_CustomParticles](https://github.com/diwi/PixelFlow/tree/master/examples/Fluid2D/Fluid_CustomParticles)” example sketch from the PixelFlow library to Python.

In Java I have somehting like this:

```auto
static public class MyParticleSystem{
  
  public DwGLSLProgram shader_particleSpawn;
  public DwGLSLProgram shader_particleUpdate;
  public DwGLSLProgram shader_particleRender;

...

    // create shader
    shader_particleSpawn = context.createShader("data/particleSpawn.frag");
    shader_particleUpdate = context.createShader("data/particleUpdate.frag");
    shader_particleRender = context.createShader("data/particleRender.glsl", "data/particleRender.glsl");
    shader_particleRender.vert.setDefine("SHADER_VERT", 1);
    shader_particleRender.frag.setDefine("SHADER_FRAG", 1);

```

But when running the following in Python mode:

```auto
def setup():
    size(1000, 800, P2D)

    
    shader_particleSpawn = context.createShader("data/particleSpawn.frag")
    shader_particleUpdate = context.createShader("data/particleUpdate.frag")
    shader_particleRender = context.createShader("data/particleRender.glsl", "data/particleRender.glsl")
    shader_particleRender.vert.setDefine("SHADER_VERT", 1)
    shader_particleRender.frag.setDefine("SHADER_FRAG", 1)

```

I have this error

> DwUtils ERROR: could not create inputstream for data/particleSpawn.frag

Am i missing something ?

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [October 25, 2018, 10:21pm UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/2 "2018-10-25T22:21:31Z")

</div>

That program is written in actual pure Java syntax, not Processing! No “.pde” file there! 😵

Before converting it to Python Mode, you should 1st convert “Fluid\_CustomParticles.java” to “Fluid\_CustomParticles.pde”, so it runs under Java Mode.

The other “MyParticleSystem.java” file doesn’t need to be converted to a “.java” though. Just the 1 w/ **setup()** & **draw()** in it. 😌

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [October 25, 2018, 10:38pm UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/3 "2018-10-25T22:38:27Z")

</div>

Hi @GoToLoop, thanks for the reply.

I just realized the link I posted isn’t correct. Here’s the original `Fluid_CustomParticles.pde` file:

```auto
/**
 * 
 * PixelFlow | Copyright (C) 2016 Thomas Diewald - http://thomasdiewald.com
 * 
 * A Processing/Java library for high performance GPU-Computing (GLSL).
 * MIT License: https://opensource.org/licenses/MIT
 * 
 */

import com.thomasdiewald.pixelflow.java.DwPixelFlow;
import com.thomasdiewald.pixelflow.java.fluid.DwFluid2D;

import controlP5.Accordion;
import controlP5.ControlP5;
import controlP5.Group;
import controlP5.RadioButton;
import controlP5.Toggle;
import processing.core.*;
import processing.opengl.PGraphics2D;
import processing.opengl.PJOGL;

  // Fluid_CustomParticles show how to setup a completely customized particle
  // system that is interacting with the fluid simulation.
  // The particle data (positions) is stored in an OpenGL texture (GL_RGBA32F) 
  // and gets updated each frame using GLSL shaders.
  // No Data transfer (application <-> device), is required.
  //
  //
  // controls:
  //
  // LMB: add Particles + Velocity
  // MMB: add Particles
  // RMB: add Particles
  
  
  
  private class MyFluidData implements DwFluid2D.FluidData{
    
    // update() is called during the fluid-simulation update step.
    @Override
    public void update(DwFluid2D fluid) {
    
      float px, py, vx, vy, radius, vscale, temperature;
 
      radius = 15;
      vscale = 10;
      px = width/2;
      py = 50;
      vx = 1 * +vscale;
      vy = 1 * vscale;
      radius = 40;
      temperature = 1f;
      fluid.addDensity(px, py, radius, 0.2f, 0.3f, 0.5f, 1.0f);
      fluid.addTemperature(px, py, radius, temperature);
      particles.spawn(fluid, px, py, radius, 100);
      

      boolean mouse_input = !cp5.isMouseOver() && mousePressed;
      
      // add impulse: density + velocity, particles
      if(mouse_input && mouseButton == LEFT){
        radius = 15;
        vscale = 15;
        px = mouseX;
        py = height-mouseY;
        vx = (mouseX - pmouseX) * +vscale;
        vy = (mouseY - pmouseY) * -vscale;
        fluid.addDensity (px, py, radius, 0.25f, 0.0f, 0.1f, 1.0f);
        fluid.addVelocity(px, py, radius, vx, vy);
        particles.spawn(fluid, px, py, radius*2, 300);
      }
      
      // add impulse: density + temperature, particles
      if(mouse_input && mouseButton == CENTER){
        radius = 15;
        vscale = 15;
        px = mouseX;
        py = height-mouseY;
        temperature = 2f;
        fluid.addDensity(px, py, radius, 0.25f, 0.0f, 0.1f, 1.0f);
        fluid.addTemperature(px, py, radius, temperature);
        particles.spawn(fluid, px, py, radius, 100);
      }
      
      // particles
      if(mouse_input && mouseButton == RIGHT){
        px = mouseX;
        py = height - 1 - mouseY; // invert
        radius = 50;
        particles.spawn(fluid, px, py, radius, 300);
      }
       
    }
  }
  
  
  int viewport_w = 1280;
  int viewport_h = 720;
  int viewport_x = 230;
  int viewport_y = 0;
  
  int gui_w = 200;
  int gui_x = 20;
  int gui_y = 20;
  
  int fluidgrid_scale = 3;
  
  DwFluid2D fluid;

  // render targets
  PGraphics2D pg_fluid;
  //texture-buffer, for adding obstacles
  PGraphics2D pg_obstacles;
  
  // custom particle system
  MyParticleSystem particles;
  
  // some state variables for the GUI/display
  int BACKGROUND_COLOR = 0;
  boolean UPDATE_FLUID = true;
  boolean DISPLAY_FLUID_TEXTURES = false;
  boolean DISPLAY_FLUID_VECTORS = false;
  int DISPLAY_fluid_texture_mode = 0;
  boolean DISPLAY_PARTICLES = true;
  
  
  public void settings() {
    size(viewport_w, viewport_h, P2D);
    smooth(4);
    PJOGL.profile = 3;
  }
  

  
  public void setup() {
    surface.setLocation(viewport_x, viewport_y);
    
    // main library context
    DwPixelFlow context = new DwPixelFlow(this);
    context.print();
    context.printGL();

    // fluid simulation
    fluid = new DwFluid2D(context, viewport_w, viewport_h, fluidgrid_scale);
  
    // set some simulation parameters
    fluid.param.dissipation_density = 0.999f;
    fluid.param.dissipation_velocity = 0.99f;
    fluid.param.dissipation_temperature = 0.80f;
    fluid.param.vorticity = 0.10f;
    
    // interface for adding data to the fluid simulation
    MyFluidData cb_fluid_data = new MyFluidData();
    fluid.addCallback_FluiData(cb_fluid_data);
   
    // pgraphics for fluid
    pg_fluid = (PGraphics2D) createGraphics(viewport_w, viewport_h, P2D);
    pg_fluid.smooth(4);
    pg_fluid.beginDraw();
    pg_fluid.background(BACKGROUND_COLOR);
    pg_fluid.endDraw();
    
        // pgraphics for obstacles
    pg_obstacles = (PGraphics2D) createGraphics(viewport_w, viewport_h, P2D);
    pg_obstacles.smooth(4);
    pg_obstacles.beginDraw();
    pg_obstacles.clear();
    float radius;
    radius = 200;
    pg_obstacles.stroke(64);
    pg_obstacles.strokeWeight(10);
    pg_obstacles.noFill();
    pg_obstacles.rect(1*width/2f, 1*height/4f, radius, radius, 20);
    // border-obstacle
    pg_obstacles.strokeWeight(20);
    pg_obstacles.stroke(64);
    pg_obstacles.noFill();
    pg_obstacles.rect(0, 0, pg_obstacles.width, pg_obstacles.height);
    pg_obstacles.endDraw();
    
    fluid.addObstacles(pg_obstacles);
    
    // custom particle object
    particles = new MyParticleSystem(context, 1000 * 1000);

    createGUI();
    
    background(0);
    frameRate(60);
  }
  

  public void draw() {    
    
 
    // update simulation
    if(UPDATE_FLUID){
      fluid.addObstacles(pg_obstacles);
      fluid.update();
      particles.update(fluid);
    }
    
    // clear render target
    pg_fluid.beginDraw();
    pg_fluid.background(BACKGROUND_COLOR);
    pg_fluid.endDraw();
    
    
    // render fluid stuff
    if(DISPLAY_FLUID_TEXTURES){
      // render: density (0), temperature (1), pressure (2), velocity (3)
      fluid.renderFluidTextures(pg_fluid, DISPLAY_fluid_texture_mode);
    }
    
    if(DISPLAY_FLUID_VECTORS){
      // render: velocity vector field
      fluid.renderFluidVectors(pg_fluid, 10);
    }
    
    if( DISPLAY_PARTICLES){
      // render: particles; 0 ... points, 1 ...sprite texture, 2 ... dynamic points
      particles.render(pg_fluid, BACKGROUND_COLOR);
    }
    

    // display
    image(pg_fluid , 0, 0);
    image(pg_obstacles, 0, 0);

    
    // display number of particles as text
    String txt_num_particles = String.format("Particles %,d", particles.ALIVE_PARTICLES);
    fill(0, 0, 0, 220);
    noStroke();
    rect(10, height-10, 160, -30);
    fill(255,128,0);
    text(txt_num_particles, 20, height-20);
 
    // info
    String txt_fps = String.format(getClass().getName()+ " [size %d/%d] [frame %d] [fps %6.2f]", fluid.fluid_w, fluid.fluid_h, fluid.simulation_step, frameRate);
    surface.setTitle(txt_fps);
  }
  

  
  public void fluid_resizeUp(){
    fluid.resize(width, height, fluidgrid_scale = max(1, --fluidgrid_scale));
  }
  public void fluid_resizeDown(){
    fluid.resize(width, height, ++fluidgrid_scale);
  }
  public void fluid_reset(){
    fluid.reset();
  }
  public void fluid_togglePause(){
    UPDATE_FLUID = !UPDATE_FLUID;
  }
  public void fluid_displayMode(int val){
    DISPLAY_fluid_texture_mode = val;
    DISPLAY_FLUID_TEXTURES = DISPLAY_fluid_texture_mode != -1;
  }
  public void fluid_displayVelocityVectors(int val){
    DISPLAY_FLUID_VECTORS = val != -1;
  }

  public void fluid_displayParticles(int val){
    DISPLAY_PARTICLES = val != -1;
  }

  public void keyReleased(){
    if(key == 'p') fluid_togglePause(); // pause / unpause simulation
    if(key == '+') fluid_resizeUp(); // increase fluid-grid resolution
    if(key == '-') fluid_resizeDown(); // decrease fluid-grid resolution
    if(key == 'r') fluid_reset(); // restart simulation
    
    if(key == '1') DISPLAY_fluid_texture_mode = 0; // density
    if(key == '2') DISPLAY_fluid_texture_mode = 1; // temperature
    if(key == '3') DISPLAY_fluid_texture_mode = 2; // pressure
    if(key == '4') DISPLAY_fluid_texture_mode = 3; // velocity
    
    if(key == 'q') DISPLAY_FLUID_TEXTURES = !DISPLAY_FLUID_TEXTURES;
    if(key == 'w') DISPLAY_FLUID_VECTORS = !DISPLAY_FLUID_VECTORS;
  }
 
  
  
  ControlP5 cp5;
  
  public void createGUI(){
    cp5 = new ControlP5(this);
    
    int sx, sy, px, py, oy;
    
    sx = 100; sy = 14; oy = (int)(sy*1.5f);
    

    ////////////////////////////////////////////////////////////////////////////
    // GUI - FLUID
    ////////////////////////////////////////////////////////////////////////////
    Group group_fluid = cp5.addGroup("fluid");
    {
      group_fluid.setHeight(20).setSize(gui_w, 300)
      .setBackgroundColor(color(16, 180)).setColorBackground(color(16, 180));
      group_fluid.getCaptionLabel().align(CENTER, CENTER);
      
      px = 10; py = 15;
      
      cp5.addButton("reset").setGroup(group_fluid).plugTo(this, "fluid_reset" ).setSize(80, 18).setPosition(px , py);
      cp5.addButton("+" ).setGroup(group_fluid).plugTo(this, "fluid_resizeUp" ).setSize(39, 18).setPosition(px+=82, py);
      cp5.addButton("-" ).setGroup(group_fluid).plugTo(this, "fluid_resizeDown").setSize(39, 18).setPosition(px+=41, py);
      
      px = 10;
     
      cp5.addSlider("velocity").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=(int)(oy*1.5f))
          .setRange(0, 1).setValue(fluid.param.dissipation_velocity).plugTo(fluid.param, "dissipation_velocity");
      
      cp5.addSlider("density").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=oy)
          .setRange(0, 1).setValue(fluid.param.dissipation_density).plugTo(fluid.param, "dissipation_density");
      
      cp5.addSlider("temperature").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=oy)
          .setRange(0, 1).setValue(fluid.param.dissipation_temperature).plugTo(fluid.param, "dissipation_temperature");
      
      cp5.addSlider("vorticity").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=oy)
          .setRange(0, 1).setValue(fluid.param.vorticity).plugTo(fluid.param, "vorticity");
          
      cp5.addSlider("iterations").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=oy)
          .setRange(0, 80).setValue(fluid.param.num_jacobi_projection).plugTo(fluid.param, "num_jacobi_projection");
            
      cp5.addSlider("timestep").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=oy)
          .setRange(0, 1).setValue(fluid.param.timestep).plugTo(fluid.param, "timestep");
          
      cp5.addSlider("gridscale").setGroup(group_fluid).setSize(sx, sy).setPosition(px, py+=oy)
          .setRange(0, 50).setValue(fluid.param.gridscale).plugTo(fluid.param, "gridscale");
      
      RadioButton rb_setFluid_DisplayMode = cp5.addRadio("fluid_displayMode").setGroup(group_fluid).setSize(80,18).setPosition(px, py+=(int)(oy*1.5f))
          .setSpacingColumn(2).setSpacingRow(2).setItemsPerRow(2)
          .addItem("Density" ,0)
          .addItem("Temperature",1)
          .addItem("Pressure" ,2)
          .addItem("Velocity" ,3)
          .activate(DISPLAY_fluid_texture_mode);
      for(Toggle toggle : rb_setFluid_DisplayMode.getItems()) toggle.getCaptionLabel().alignX(CENTER);
      
      cp5.addRadio("fluid_displayVelocityVectors").setGroup(group_fluid).setSize(18,18).setPosition(px, py+=(int)(oy*2.5f))
          .setSpacingColumn(2).setSpacingRow(2).setItemsPerRow(1)
          .addItem("Velocity Vectors", 0)
          .activate(DISPLAY_FLUID_VECTORS ? 0 : 2);
    }
    
    
    ////////////////////////////////////////////////////////////////////////////
    // GUI - DISPLAY
    ////////////////////////////////////////////////////////////////////////////
    Group group_display = cp5.addGroup("display");
    {
      group_display.setHeight(20).setSize(gui_w, 50)
      .setBackgroundColor(color(16, 180)).setColorBackground(color(16, 180));
      group_display.getCaptionLabel().align(CENTER, CENTER);
      
      px = 10; py = 15;
      
      cp5.addSlider("BACKGROUND").setGroup(group_display).setSize(sx,sy).setPosition(px, py)
          .setRange(0, 255).setValue(BACKGROUND_COLOR).plugTo(this, "BACKGROUND_COLOR");
      
      cp5.addRadio("fluid_displayParticles").setGroup(group_display).setSize(18,18).setPosition(px, py+=(int)(oy*1.5f))
          .setSpacingColumn(2).setSpacingRow(2).setItemsPerRow(1)
          .addItem("display particles", 0)
          .activate(DISPLAY_PARTICLES ? 0 : 2);
    }
    
    
    ////////////////////////////////////////////////////////////////////////////
    // GUI - ACCORDION
    ////////////////////////////////////////////////////////////////////////////
    cp5.addAccordion("acc").setPosition(gui_x, gui_y).setWidth(gui_w).setSize(gui_w, height)
      .setCollapseMode(Accordion.MULTI)
      .addItem(group_fluid)
      .addItem(group_display)
      .open(4);
  }

```

But I don’t see how it is related to my question on shader creation…

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [October 26, 2018, 12:24am UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/4 "2018-10-26T00:24:21Z")

</div>

> [@solub](#):
>
> But I don’t see how it is related to my question on shader creation…

It isn’t. But at least now I could run it to check whether it works under Java Mode or not. 🤪

It’d be better if you posted your full attempt under Python Mode, so I can compare it w/ Java’s. 🐍

---

<div class="post-metadata">

**Author:** ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)\
**Post date:** [October 26, 2018, 6:44am UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/5 "2018-10-26T06:44:09Z")

</div>

You may be heartened to know or otherwise that I have successfully got several sketches working with [JRubyArt](https://github.com/ruby-processing/JRubyArt-examples/tree/master/external_library/java/PixelFlow).

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [October 26, 2018, 11:01am UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/6 "2018-10-26T11:01:33Z")

</div>

@monkstone – Thank you for your concern. Unfortunately I don’t know Ruby and it seems the problem I’m facing has to do with the `DwGLSLProgram` variable declaration. A variable that doesn’t seem to be used in your example sketches. Great contribution anyway.

@GoToLoop – I see. I deliberately reduced the Python code to the problematic snippet for clarity (that snippet should be working) but here’s my attempt to implement the `MyParticleSystem` class in full sketch:

```auto
add_library('PixelFlow')
from com.jogamp.opengl import GL2ES2

def setup():
    global fluid, pg_fluid, context, particles, tex_particles
    size(1000, 800, P2D)
    frameRate(1000)
    smooth(8)

    context = DwPixelFlow(this)
    fluid = DwFluid2D(context, width, height, 0)
    tex_particles = DwGLTexture.TexturePingPong()
    pg_fluid = createGraphics(width, height, P2D)
    particles = Particles(context, 1000 * 1000)
    
    fluid.param.dissipation_velocity = 0.99
    fluid.param.dissipation_density = 0.99
    fluid.param.dissipation_temperature = 0.1
    fluid.param.vorticity = 0.00
    fluid.param.timestep = 0.1
    fluid.addCallback_FluiData(MyFluidData())
    
    
def draw():
    image(pg_fluid, 0, 0)
    
    pg_fluid.beginDraw()
    pg_fluid.background(0)
    pg_fluid.endDraw()
    
    fluid.update()
    fluid.renderFluidTextures(pg_fluid, 0)

    #particles.update(fluid)
    #particles.render(pg_fluid, 0)

    
class MyFluidData(DwFluid2D.FluidData):
    def update(_, fluid):
        if mousePressed:
            radius = 15
            px = mouseX
            py = height-mouseY
            vx = (mouseX-pmouseX) * 15
            vy = (mouseY-pmouseY) * -15
            fluid.addVelocity(px, py, 20, vx, vy)
            fluid.addDensity(px, py, 20, 0.0, 0.4, .7, .5)
            #particles.spawn(fluid, px, py, radius, 100)
            
            
class Particles(object):
    def __init__ (self, context, n_particles):
        self.context = context
        self.npart = n_particles
        self.ALIVE_LO = 0
        self.ALIVE_HI = 0
        self.ALIVE_PARTICLES = 0
        self.dissipation = 0.90
        self.intertia = 0.20
        self.particles_x = 0
        self.particles_y = 0
        self.resiz(self.context, self.npart)
        
    def dispose(self):
        release()
        
    def release(self):
        tex_particles.release()
        
    def resiz(self, context, n_particles):
        self.particles_x = ceil(sqrt(n_particles))
        self.particles_y = self.particles_x

        context.begin()
        self.release()
        mxpart = self.particles_x * self.particles_y
        
        shader_particleSpawn = context.createShader("data/particleSpawn.frag")
        shader_particleUpdate = context.createShader("data/particleUpdate.frag")
        shader_particleRender = context.createShader("data/particleRender.glsl", "data/particleRender.glsl")
        shader_particleRender.vert.setDefine("SHADER_VERT", 1)
        shader_particleRender.frag.setDefine("SHADER_FRAG", 1)
    
        tex_particles.resize(context, GL2ES2.GL_RGBA32F, self.particles_x, self.particles_y, GL2ES2.GL_RGBA, GL2ES2.GL_FLOAT, GL2ES2.GL_NEAREST, 4, 4);
    
        context.end("ParticleSystem.resize");
    
        reset();
        
    def spawn(self, fluid, px, py, radius, count):
        count = round(count * 1.0)
        
        spawn_lo = self.ALIVE_HI
        spawn_hi = min(self.spawn.lo + count, n_particles)
        no = float(random()) * PI
        
        context.begin()
        context.beginDraw(self.tex_articles.dst)
        shader_particleSpawn.begin()
        shader_particleSpawn.uniform1i("spawn_lo", self.spawn_lo)
        shader_particleSpawn.uniform1i("spawn_hi", self.spawn_hi)
        shader_particleSpawn.uniform2f("spawn_origin", px, py)
        shader_particleSpawn.uniform1f("spawn_radius", radius)
        shader_particleSpawn.uniform1f("noise", no)
        shader_particleSpawn.uniform2f("wh_particles" , self.particles_x, self.particles_y)
        shader_particleSpawn.uniformTexture("tex_particles" , tex_particles.src)
        shader_particleSpawn.drawFullScreenQuad()
        shader_particleSpawn.end()
        context.endDraw()
        context.end("ParticleSystem.spawn")
        self.tex_particles.swap()
        
        self.ALIVE_HI = spawn_hi;
        self.ALIVE_PARTICLES = max(self.ALIVE_PARTICLES, self.ALIVE_HI - self.ALIVE_LO)
    
    def update(self, fluid):
        self.context.begin();
        self.context.beginDraw(tex_particles.dst);
        shader_particleUpdate.begin();
        shader_particleUpdate.uniform2f("wh_fluid", fluid.fluid_w, fluid.fluid_h);
        shader_particleUpdate.uniform2f("wh_particles", self.particles_x, self.particles_y);
        shader_particleUpdate.uniform1f("timestep", fluid.param.timestep);
        shader_particleUpdate.uniform1f("rdx", 1.0 / fluid.param.gridscale);
        shader_particleUpdate.uniform1f("dissipation", self.dissipation);
        shader_particleUpdate.uniform1f("inertia", self.inertia);
        shader_particleUpdate.uniformTexture("tex_particles", tex_particles.src);
        shader_particleUpdate.uniformTexture("tex_velocity" , fluid.tex_velocity.src);
        shader_particleUpdate.uniformTexture("tex_obstacles", fluid.tex_obstacleC.src);
        shader_particleUpdate.drawFullScreenQuad();
        shader_particleUpdate.end();
        self.context.endDraw();
        self.context.end("ParticleSystem.update");
        tex_particles.swap()
        
        
    def render(self, dst, bg):
        num_points_to_render = self.ALIVE_PARTICLES
        w = dst.width
        h = dst.height
    
        dst.beginDraw();
        dst.blendMode(PConstants.BLEND)
        if bg == 0: dst.bendMode(PConstants.ADD)
        context.begin();
        shader_particleRender.begin()
        shader_particleRender.uniform2f("wh_viewport", w, h)
        shader_particleRender.uniform2i("num_particles", self.particles_x, self.particles_y)
        shader_particleRender.uniform1f("point_size", 1.5)
        shader_particleRender.uniformTexture("tex_particles", tex_particles.src)
        shader_particleRender.drawFullScreenPoints(num_points_to_render)
        shader_particleRender.end();
        context.end("ParticleSystem.render");
    
        dst.endDraw();

```

---

<div class="post-metadata">

**Author:** ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)\
**Post date:** [October 26, 2018, 1:17pm UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/7 "2018-10-26T13:17:19Z")

</div>

The reaction\_diffusion.rb is an example where I create instances of DwGLSLProgram, but ruby is not strongly typed so it isn’t obvious

```ruby
@shader_grayscott = context.create_shader(data_path('grayscott.frag'))
  @shader_render = context.create_shader(data_path('render.frag'))

```

Just a thought but have you tried using the absolute data path for `particleRender.glsl` etc., instead of `data/particleRender.glsl`. That is what my `data_path` wrapper above returns…

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [October 26, 2018, 3:48pm UTC](https://discourse.processing.org/t/java-to-python-pixelflow-library/4885/8 "2018-10-26T15:48:38Z")

</div>

Following @monkstone suggestion I put all 3 shaders’ files in the main sketch file and it worked.  
Also I apologize as I realize my first draft was full of typos. Please find below a fully working and cleaned-up version.

> **Script**
>
> ```auto
> add_library('PixelFlow')
> from com.jogamp.opengl import GL2ES2
> 
> def setup():
> global fluid, pg_fluid, context, particles, tex_particles, shader_particleSpawn, shader_particleUpdate, shader_particleRender
> size(1000, 800, P2D)
> frameRate(1000)
> smooth(8)
> 
> context = DwPixelFlow(this)
> fluid = DwFluid2D(context, width, height, 0)
> tex_particles = DwGLTexture.TexturePingPong()
> 
> particles = Particles(context, 1000 * 1000)
> pg_fluid = createGraphics(width, height, P2D)
> 
> shader_particleSpawn = context.createShader("particleSpawn.frag")
> shader_particleUpdate = context.createShader("particleUpdate.frag")
> shader_particleRender = context.createShader("particleRender.glsl", "particleRender.glsl")
> shader_particleRender.vert.setDefine("SHADER_VERT", 1)
> shader_particleRender.frag.setDefine("SHADER_FRAG", 1)
>     
> fluid.param.dissipation_velocity = 0.99
> fluid.param.dissipation_density = 0.99
> fluid.param.dissipation_temperature = 0.1
> fluid.param.vorticity = 0.00
> fluid.param.timestep = 0.1
> fluid.addCallback_FluiData(MyFluidData())
> 
>     
> def draw():
> image(pg_fluid, 0, 0)
>     
> pg_fluid.beginDraw()
> pg_fluid.background(0)
> pg_fluid.endDraw()
>     
> fluid.update()
> #fluid.renderFluidTextures(pg_fluid, 0)
> 
> particles.update(fluid)
> particles.render(pg_fluid, 0)
> 
>     
> class MyFluidData(DwFluid2D.FluidData):
> def update(_, fluid):
> if mousePressed:
> radius = 15
> px = mouseX
> py = height-mouseY
> vx = (mouseX-pmouseX) * radius
> vy = (mouseY-pmouseY) * - radius
> fluid.addVelocity(px, py, 20, vx, vy)
> fluid.addDensity(px, py, 20, 0.0, 0.4, .7, .5)
> particles.spawn(fluid, px, py, radius, 100)
>             
>             
> class Particles(object):
> def __init__ (self, context, n_particles):
> self.context = context
> self.npart = n_particles
> self.ALIVE_LO = 0
> self.ALIVE_HI = 0
> self.ALIVE_PARTICLES = 0
> self.dissipation = 0.90
> self.inertia = 0.20
> self.particles_x = 0
> self.particles_y = 0
> self.resize(context, n_particles)
> 
>         
> def resize(self, context, n_particles):
> self.particles_x = ceil(sqrt(n_particles))
> self.particles_y = self.particles_x
> 
> context.begin()
> tex_particles.release()
> tex_particles.resize(context, GL2ES2.GL_RGBA32F, self.particles_x, self.particles_y, GL2ES2.GL_RGBA, GL2ES2.GL_FLOAT, GL2ES2.GL_NEAREST, 4, 4)
> context.end("ParticleSystem.resize")
>         
> def spawn(self, fluid, px, py, radius, count):
> count = round(count * 1.0)
> spawn_lo = int(self.ALIVE_HI)
> spawn_hi = int(min(spawn_lo + count, self.npart))
> n = float(random(1)) * PI
>         
> context.begin()
> context.beginDraw(tex_particles.dst)
> shader_particleSpawn.begin()
> if fluid is not None: shader_particleSpawn.uniform2f("wh_viewport", fluid.viewp_w, fluid.viewp_h)
> shader_particleSpawn.uniform1i("spawn_lo", spawn_lo)
> shader_particleSpawn.uniform1i("spawn_hi", spawn_hi)
> shader_particleSpawn.uniform2f("spawn_origin", px, py)
> shader_particleSpawn.uniform1f("spawn_radius", radius)
> shader_particleSpawn.uniform1f("noise", n)
> shader_particleSpawn.uniform2f("wh_particles" , self.particles_x, self.particles_y)
> shader_particleSpawn.uniformTexture("tex_particles" , tex_particles.src)
> shader_particleSpawn.drawFullScreenQuad()
> shader_particleSpawn.end()
> context.endDraw()
> context.end("ParticleSystem.spawn")
> tex_particles.swap()
>         
> self.ALIVE_HI = spawn_hi
> self.ALIVE_PARTICLES = max(self.ALIVE_PARTICLES, self.ALIVE_HI - self.ALIVE_LO)
>     
> def update(self, fluid):
> self.context.begin()
> self.context.beginDraw(tex_particles.dst)
> shader_particleUpdate.begin()
> shader_particleUpdate.uniform2f("wh_fluid", fluid.fluid_w, fluid.fluid_h)
> shader_particleUpdate.uniform2f("wh_particles", self.particles_x, self.particles_y)
> shader_particleUpdate.uniform1f("timestep", fluid.param.timestep)
> shader_particleUpdate.uniform1f("rdx", 1.0 / fluid.param.gridscale)
> shader_particleUpdate.uniform1f("dissipation", self.dissipation)
> shader_particleUpdate.uniform1f("inertia", self.inertia)
> shader_particleUpdate.uniformTexture("tex_particles", tex_particles.src)
> shader_particleUpdate.uniformTexture("tex_velocity" , fluid.tex_velocity.src)
> shader_particleUpdate.uniformTexture("tex_obstacles", fluid.tex_obstacleC.src)
> shader_particleUpdate.drawFullScreenQuad()
> shader_particleUpdate.end()
> self.context.endDraw()
> self.context.end("ParticleSystem.update")
> tex_particles.swap()
>         
>         
> def render(self, dst, bg):
> num_points_to_render = self.ALIVE_PARTICLES
> w = dst.width
> h = dst.height
>     
> dst.beginDraw();
> dst.blendMode(PConstants.BLEND)
> if bg == 0: dst.blendMode(PConstants.ADD)
> context.begin();
> shader_particleRender.begin()
> shader_particleRender.uniform2f("wh_viewport", w, h)
> shader_particleRender.uniform2i("num_particles", self.particles_x, self.particles_y)
> shader_particleRender.uniform1f("point_size", 1.5)
> shader_particleRender.uniformTexture("tex_particles", tex_particles.src)
> shader_particleRender.drawFullScreenPoints(num_points_to_render)
> shader_particleRender.end()
> context.end("ParticleSystem.render")
> dst.endDraw()
> 
> ```

Thank you
