Package advanced.fluidSimulator

Source Code of advanced.fluidSimulator.FluidSimulationScene

/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*   This program is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   This program 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 General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package advanced.fluidSimulator;

import java.awt.event.KeyEvent;
import java.nio.FloatBuffer;

import javax.media.opengl.GL;

import msafluid.MSAFluidSolver2D;

import org.mt4j.MTApplication;
import org.mt4j.components.MTComponent;
import org.mt4j.input.IMTInputEventListener;
import org.mt4j.input.inputData.AbstractCursorInputEvt;
import org.mt4j.input.inputData.InputCursor;
import org.mt4j.input.inputData.MTInputEvent;
import org.mt4j.sceneManagement.AbstractScene;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.math.Vector3D;

import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PImage;
import processing.opengl.PGraphicsOpenGL;

import com.sun.opengl.util.BufferUtil;

/**
* The Class FluidSimulationScene.
*
* The original fluid simulation code was taken from
* memo akten (www.memo.tv)
*
*/
public class FluidSimulationScene extends AbstractScene{
 
  private final float FLUID_WIDTH = 120;
  private float invWidth, invHeight;    // inverse of screen dimensions
  private float aspectRatio, aspectRatio2;
  private MSAFluidSolver2D fluidSolver;
  private PImage imgFluid;
  private boolean drawFluid = true;
 
  private ParticleSystem particleSystem;
  /////////
 
  private MTApplication app;

  public FluidSimulationScene(MTApplication mtApplication, String name) {
    super(mtApplication, name);
    this.app = mtApplication;
   
    if (!MT4jSettings.getInstance().isOpenGlMode()){
      System.err.println("Scene only usable when using the OpenGL renderer! - See settings.txt");
          return;
        }
   
        //pa.hint( PApplet.ENABLE_OPENGL_4X_SMOOTH );    // Turn on 4X antialiasing
        invWidth = 1.0f/mtApplication.width;
        invHeight = 1.0f/mtApplication.height;
        aspectRatio = mtApplication.width * invHeight;
        aspectRatio2 = aspectRatio * aspectRatio;
    
        // Create fluid and set options
        fluidSolver = new MSAFluidSolver2D((int)(FLUID_WIDTH), (int)(FLUID_WIDTH * mtApplication.height/mtApplication.width));
//        fluidSolver.enableRGB(true).setFadeSpeed(0.003f).setDeltaT(0.5f).setVisc(0.00005f);
        fluidSolver.enableRGB(true).setFadeSpeed(0.003f).setDeltaT(0.8f).setVisc(0.00004f);
    
        // Create image to hold fluid picture
        imgFluid = mtApplication.createImage(fluidSolver.getWidth(), fluidSolver.getHeight(), PApplet.RGB);
       
        // Create particle system
        particleSystem = new ParticleSystem(mtApplication, fluidSolver);
       
        this.getCanvas().addInputListener(new IMTInputEventListener() {
          //@Override
          public boolean processInputEvent(MTInputEvent inEvt){
            if(inEvt instanceof AbstractCursorInputEvt){
              AbstractCursorInputEvt posEvt = (AbstractCursorInputEvt)inEvt;
              if (posEvt.hasTarget() && posEvt.getTargetComponent().equals(getCanvas())){
                InputCursor m = posEvt.getCursor();
                AbstractCursorInputEvt prev = m.getPreviousEventOf(posEvt);
                if (prev == null)
                  prev = posEvt;

                Vector3D pos = new Vector3D(posEvt.getPosX(), posEvt.getPosY(), 0);
                Vector3D prevPos = new Vector3D(prev.getPosX(), prev.getPosY(), 0);

                //System.out.println("Pos: " + pos);
                float mouseNormX = pos.x * invWidth;
                float mouseNormY = pos.y * invHeight;
                //System.out.println("MouseNormPosX: " + mouseNormX + "," + mouseNormY);
                float mouseVelX = (pos.x - prevPos.x) * invWidth;
                float mouseVelY = (pos.y - prevPos.y) * invHeight;
                /*
                System.out.println("Mouse vel X: " + mouseVelX + " mouseNormX:" + mouseNormX);
                System.out.println("Mouse vel Y: " + mouseVelY + " mouseNormY:" + mouseNormY);
                 */
                addForce(mouseNormX, mouseNormY, mouseVelX, mouseVelY);
              }
            }
            return false;
          }
    });
        //FIXME make componentInputProcessor?
       
        this.getCanvas().addChild(new FluidImage(mtApplication));
       
       
        this.getCanvas().setDepthBufferDisabled(true);
  }
 
 
  /**
   * The Class FluidImage.
   */
  private class FluidImage extends MTComponent{
    public FluidImage(PApplet applet) {
      super(applet);
    }
    //@Override
    public void drawComponent(PGraphics g) {
      super.drawComponent(g);
      drawFluidImage();
     
      g.noSmooth();
      g.fill(255,255,255,255);
      g.tint(255,255,255,255);
     
      //FIXME TEST
      PGraphicsOpenGL pgl = (PGraphicsOpenGL)g;
      GL gl = pgl.gl;
      gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
      gl.glDisableClientState(GL.GL_COLOR_ARRAY);
      gl.glDisable(GL.GL_LINE_SMOOTH);
      gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    }
  }
 
 
  //@Override
  public void drawAndUpdate(PGraphics graphics, long timeDelta) {
//    this.drawFluidImage();
    super.drawAndUpdate(graphics, timeDelta);
   
//    app.noSmooth();
//    app.fill(255,255,255,255);
//    app.tint(255,255,255,255);
//   
//    //FIXME TEST
//    PGraphicsOpenGL pgl = (PGraphicsOpenGL)app.g;
//    GL gl = pgl.gl;
//    gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
//    gl.glDisableClientState(GL.GL_COLOR_ARRAY);
//    gl.glDisable(GL.GL_LINE_SMOOTH);
//    gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
//    mtApp.colorMode(PApplet.RGB, 255); 
  }
 
 
 
  // add force and dye to fluid, and create particles
  private void addForce(float x, float y, float dx, float dy) {
      float speed = dx * dx  + dy * dy * aspectRatio2;    // balance the x and y components of speed with the screen aspect ratio
  
      if(speed > 0) {
          if(x < 0){
            x = 0;
          }else if(x > 1){
            x = 1;
          }if(y < 0){
            y = 0;
          }else if(y > 1){
            y = 1;
          }
         
          float colorMult = 5;
          float velocityMult = 30.0f;
  
          int index = fluidSolver.getIndexForNormalizedPosition(x, y);
  
//          PApplet.color drawColor;
          app.colorMode(PApplet.HSB, 360, 1, 1);
          float hue = ((x + y) * 180 + app.frameCount) % 360;
          int drawColor = app.color(hue, 1, 1);
          app.colorMode(PApplet.RGB, 1)
  
          fluidSolver.rOld[index+= app.red(drawColor)   * colorMult;
          fluidSolver.gOld[index+= app.green(drawColor)   * colorMult;
          fluidSolver.bOld[index+= app.blue(drawColor)   * colorMult;
  
          //Particles
          particleSystem.addParticles(x * app.width, y * app.height, 10);
         
          fluidSolver.uOld[index] += dx * velocityMult;
          fluidSolver.vOld[index] += dy * velocityMult;
         
//          mtApp.noSmooth();
//      mtApp.fill(255,255,255,255);
//      mtApp.tint(255,255,255,255);
     
      //FIXME TEST
      app.colorMode(PApplet.RGB, 255)
      }
  }
 
 
  private void drawFluidImage(){
    app.colorMode(PApplet.RGB, 1)
    
    fluidSolver.update();
      if(drawFluid) {
          for(int i=0; i<fluidSolver.getNumCells(); i++) {
              int d = 2;
              imgFluid.pixels[i] = app.color(fluidSolver.r[i] * d, fluidSolver.g[i] * d, fluidSolver.b[i] * d);
         
          imgFluid.updatePixels();//  fastblur(imgFluid, 2);
         
//          app.image(imgFluid, 0, 0, app.width, app.height); //FIXME this messes up blend transition!
         
          app.textureMode(app.NORMALIZED);
//          app.textureMode(app.IMAGE);
          app.beginShape(app.QUADS);
          app.texture(imgFluid);
          app.vertex(0, 0, 0, 0);
          app.vertex(app.width, 0, 1, 0);
          app.vertex(app.width, app.height, 1, 1);
          app.vertex(0, app.height, 0, 1);
          app.endShape();

      }
      particleSystem.updateAndDraw();
     
      app.colorMode(PApplet.RGB, 255)
  }

 
  //@Override
  public void init() {
    app.registerKeyEvent(this);
  }

  //@Override
  public void shutDown() {
    app.unregisterKeyEvent(this);
    /*
    mtApp.noSmooth();
    mtApp.fill(255,255,255,255);
    mtApp.tint(255,255,255,255);
    PGraphicsOpenGL pgl = (PGraphicsOpenGL)mtApp.g;
    GL gl = pgl.gl;
    gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL.GL_COLOR_ARRAY);
    gl.glDisable(GL.GL_LINE_SMOOTH);
    gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    mtApp.colorMode(PApplet.RGB, 255); 
     */
  }
 
 
  /**
   *
   * @param e
   */
  public void keyEvent(KeyEvent e){
    int evtID = e.getID();
    if (evtID != KeyEvent.KEY_PRESSED)
      return;
    switch (e.getKeyCode()){
    case KeyEvent.VK_BACK_SPACE:
      app.popScene();
      break;
      default:
        break;
    }
  }

 
 
  private class Particle {
    private final static float MOMENTUM = 0.5f;
    private final static float FLUID_FORCE = 0.6f;

    private float x, y;
    private float vx, vy;
    //private float radius;       // particle's size
    protected float alpha;
    private float mass;
    private PApplet p;
    private float invWidth;
    private float invHeight;
    private MSAFluidSolver2D fluidSolver;
   
   
    public Particle(PApplet p, MSAFluidSolver2D fluidSolver, float invWidth, float invHeight){
      this.p = p;
      this.invWidth = invWidth;
      this.invHeight = invHeight;
      this.fluidSolver = fluidSolver;
    }

     public void init(float x, float y) {
         this.x = x;
         this.y = y;
         vx = 0;
         vy = 0;
         //radius = 5;
         alpha = p.random(0.3f, 1);
         mass = p.random(0.1f, 1);
     }


     public void update() {
         // only update if particle is visible
         if(alpha == 0) return;

         // read fluid info and add to velocity
         int fluidIndex = fluidSolver.getIndexForNormalizedPosition(x * invWidth, y * invHeight);
         vx = fluidSolver.u[fluidIndex] * p.width * mass * FLUID_FORCE + vx * MOMENTUM;
         vy = fluidSolver.v[fluidIndex] * p.height * mass * FLUID_FORCE + vy * MOMENTUM;

         // update position
         x += vx;
         y += vy;

         // bounce of edges
         if(x<0) {
             x = 0;
             vx *= -1;
         }else if(x > p.width) {
             x = p.width;
             vx *= -1;
         }

         if(y<0) {
             y = 0;
             vy *= -1;
         }else if(y > p.height) {
             y = p.height;
             vy *= -1;
         }

         // hackish way to make particles glitter when the slow down a lot
         if(vx * vx + vy * vy < 1) {
             vx = p.random(-1, 1);
             vy = p.random(-1, 1);
         }

         // fade out a bit (and kill if alpha == 0);
         alpha *= 0.999;
         if(alpha < 0.01)
           alpha = 0;

     }


     public void updateVertexArrays(int i, FloatBuffer posBuffer, FloatBuffer colBuffer) {
         int vi = i * 4;
         posBuffer.put(vi++, x - vx);
         posBuffer.put(vi++, y - vy);
         posBuffer.put(vi++, x);
         posBuffer.put(vi++, y);

         int ci = i * 6;
         colBuffer.put(ci++, alpha);
         colBuffer.put(ci++, alpha);
         colBuffer.put(ci++, alpha);
         colBuffer.put(ci++, alpha);
         colBuffer.put(ci++, alpha);
         colBuffer.put(ci++, alpha);
     }


     public void drawOldSchool(GL gl) {
         gl.glColor3f(alpha, alpha, alpha);
         gl.glVertex2f(x-vx, y-vy);
         gl.glVertex2f(x, y);
     }

  }//end particle class
 
 
 
 
  public class ParticleSystem{
    private FloatBuffer posArray;
    private FloatBuffer colArray;
    private final static int maxParticles = 5000;
    private int curIndex;
   
    boolean renderUsingVA = true;
   
    private Particle[] particles;
    private PApplet p;
    private MSAFluidSolver2D fluidSolver;
    private float invWidth;
    private float invHeight;
   
    private boolean drawFluid;
   
    public ParticleSystem(PApplet p, MSAFluidSolver2D fluidSolver) {
      this.p = p;
      this.fluidSolver = fluidSolver;
      this.invWidth = 1.0f/p.width;
      this.invHeight = 1.0f/p.height;
     
      this.drawFluid = true;
     
      particles = new Particle[maxParticles];
     
      for(int i=0; i<maxParticles; i++) {
        particles[i] = new Particle(p, this.fluidSolver, invWidth, invHeight);
      }
     
      curIndex = 0;

      posArray = BufferUtil.newFloatBuffer(maxParticles * 2 * 2);// 2 coordinates per point, 2 points per particle (current and previous)
      colArray = BufferUtil.newFloatBuffer(maxParticles * 3 * 2);
    }


    public void updateAndDraw(){
      PGraphicsOpenGL pgl = (PGraphicsOpenGL)p.g;         // processings opengl graphics object
      GL gl = pgl.beginGL();                // JOGL's GL object

      gl.glEnable( GL.GL_BLEND );             // enable blending
     
      if(!drawFluid)
        fadeToColor(p, gl, 0, 0, 0, 0.05f);

      gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE)// additive blending (ignore alpha)
      gl.glEnable(GL.GL_LINE_SMOOTH);        // make points round
      gl.glLineWidth(1);


      if(renderUsingVA) {
        for(int i=0; i<maxParticles; i++) {
          if(particles[i].alpha > 0) {
            particles[i].update();
            particles[i].updateVertexArrays(i, posArray, colArray);
          }
        }   
        gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
        gl.glVertexPointer(2, GL.GL_FLOAT, 0, posArray);

        gl.glEnableClientState(GL.GL_COLOR_ARRAY);
        gl.glColorPointer(3, GL.GL_FLOAT, 0, colArray);

        gl.glDrawArrays(GL.GL_LINES, 0, maxParticles * 2);
      }
      else {
        gl.glBegin(GL.GL_LINES);               // start drawing points
        for(int i=0; i<maxParticles; i++) {
          if(particles[i].alpha > 0) {
            particles[i].update();
            particles[i].drawOldSchool(gl);    // use oldschool renderng
          }
        }
        gl.glEnd();
      }

//      gl.glDisable(GL.GL_BLEND);
      //Reset blendfunction
      gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
      pgl.endGL();
    }

   
    public void fadeToColor(PApplet p, GL gl, float r, float g, float b, float speed) {
//      gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
      gl.glColor4f(r, g, b, speed);
      gl.glBegin(GL.GL_QUADS);
        gl.glVertex2f(0, 0);
        gl.glVertex2f(p.width, 0);
        gl.glVertex2f(p.width, p.height);
        gl.glVertex2f(0, p.height);
      gl.glEnd();
    }
   

    public void addParticles(float x, float y, int count ){
      for(int i=0; i<count; i++) addParticle(x + p.random(-15, 15), y + p.random(-15, 15));
    }


    public void addParticle(float x, float y) {
      particles[curIndex].init(x, y);
      curIndex++;
      if(curIndex >= maxParticles) curIndex = 0;
    }



    public boolean isDrawFluid() {
      return drawFluid;
    }

    public void setDrawFluid(boolean drawFluid) {
      this.drawFluid = drawFluid;
    }

  }//end psystem class

}
TOP

Related Classes of advanced.fluidSimulator.FluidSimulationScene

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.