Toad Particle Draw on Android

This is a bit silly – been playing with Processing, getting into the deep geometric capabilities of toxiclibs and GLGraphics and Android.

It started as a new VJ… er, “pixelist” app for live performance for a jam session celebrating our friend Olivier Ruellet’s life and untimely death last year from what we think was swine flu.

Now, I made an Android version… this technique will come to life a bit later as part of a”Build Your Own Superhero” workshop I’m co-developing with CoDesign.

Processing code (for Android only):

// Draw Particle Toads by pixelpusher
// <info@pixelist.info>
// Based on examples in the public domain by
// Andres Colubri and toxi (Karsten Schmidt)
//
// Uses toxiclibs - http://toxiclibs.org

import toxi.geom.*;
import toxi.geom.mesh.*;
import toxi.math.*;


TriangleMesh triMesh;

Vec3D prev=new Vec3D();
Vec3D p=new Vec3D();
Vec3D q=new Vec3D();

Vec2D rotation=new Vec2D();

boolean mouseWasDown = false;

float MIN_DIST = 7.0f;
float weight=0;


LinkedList<PShape3D> models;
PImage tex;


void setup()
{
size(800, 400, A3D);
orientation(LANDSCAPE);


models = new LinkedList<PShape3D>();

triMesh =new TriangleMesh("mesh1");

// any particle texture... small is better
tex = loadImage( "whitetoady.png");
}



void draw()
{


background(0);

// rotate around center of screen (accounted for in mouseDragged() function)
translate(width/2, height/2, 0);
rotateX(rotation.x);
rotateY(rotation.y);

// draw mesh as polygon (in white)
drawMesh();

// draw mesh unique points only (in green)
drawMeshUniqueVerts();

//hint(DISABLE_DEPTH_MASK);

screenBlend(ADD);

hint(DISABLE_DEPTH_TEST);

// now models
for (PShape3D model : models)
{
shape(model);


model.loadVertices();
for (int n = 0; n < model.vertices.length; n+=3)
{
model.vertices[n]         -= (0.0f- model.vertices[n])*0.03f;
model.vertices[n+1] -= (0.0f - model.vertices[n+1])*0.03f;
model.vertices[n+2] -= (0.0f - model.vertices[n+2])*0.03f;
}
model.updateVertices();
}

//hint(ENABLE_DEPTH_MASK);

// udpate rotation
rotation.addSelf(0.014, 0.0237);
}




PShape3D makeModel(TriangleMesh mesh)
{

PShape3D model = null;

// get unique x,y,z vertices, use with indices
float[] triVerts = mesh.getUniqueVerticesAsArray();

if (triVerts.length > 0)
{

println("Got " + triVerts.length/3 + " verts");

int[] faces = mesh.getFacesAsArray();


model = (PShape3D)createShape(triVerts.length/3, PShape3D.newParameters(POINT_SPRITES, DYNAMIC));
model.setColor(color(255));

// TESTING - MAKE SURE WE HAVE CORRECT VERTS
model.loadVertices();
for (int n = 0; n < triVerts.length; n++)
{
model.vertices[n] = triVerts[n];
}
model.updateVertices();

//model.initIndices(faces.length);
//model.updateIndices(mesh.getFacesAsArray());


//
//  for (int n=0; n<triVerts.length; n += 4)
//  {
//    println("TRIVERT["+n+"]="+ triVerts[n] +","+triVerts[n+1] +","+triVerts[n+2]);
//  }


//
// Handle colors
//
model.loadColors();

for (int i=0; i<triVerts.length/3; ++i)
{
float f = max( float(i) / (triVerts.length/3), 0.15 );
model.colors[4 * i + 0] = (1 - f) * 0.98 + f;
model.colors[4 * i + 1] = (1 - f) * 0.75 + f;
model.colors[4 * i + 2] = (1 - f) * 0.26 + f;
model.colors[4 * i + 3] = 0.8f;
}

model.updateColors();



//  float pmax = model.getMaxPointSize();
//println("Maximum sprite size supported by the video card: " + pmax + " pixels.");

model.setTexture(tex);

// Setting the maximum sprite to the 90% of the maximum point size.
//model.setMaxSpriteSize(0.6 * pmax);
// Setting the distance attenuation function so that the sprite size
// is 20 when the distance to the camera is 400.
model.autoBounds(false);
model.setSpriteSize(10, 400, QUADRATIC);
}

return model;
}



void vertex(Vec3D v) {
vertex(v.x, v.y, v.z);
}



void mouseReleased()
{
// MAKE A MODEL FROM CURRENT TRI MESH
PShape3D model = makeModel (triMesh);
if (model != null)
models.add( model );

if (models.size() > 10)
{
PShape3D first = models.removeFirst();
first.delete();
}

// clear tri mesh
triMesh.clear();
}


void mousePressed()
{
}


void mouseDragged()
{
// get 3D rotated mouse position
Vec3D pos=new Vec3D(mouseX-width/2, mouseY-height/2, 0);
pos.rotateX(rotation.x);
pos.rotateY(rotation.y);
// use distance to previous point as target stroke weight
weight+=(sqrt(pos.distanceTo(prev))*2-weight)*0.1;
// define offset points for the triangle strip

//println("weight " + weight);

//if (weight < MIN_DIST && triMeshes.size() > 0)
if (true)
{

Vec3D a=pos.add(0, 0, weight);
Vec3D b=pos.add(0, 0, -weight);

// add 2 faces to the mesh
triMesh.addFace(p, b, q);
triMesh.addFace(p, a, b);
// store current points for next iteration
prev=pos;
p=a;
q=b;
}
}




void drawMesh() {

noStroke();
fill(255,80);
beginShape(TRIANGLES);
// iterate over all faces/triangles of the mesh
for (Iterator i=triMesh.faces.iterator(); i.hasNext();) {
Face f=(Face)i.next();
// create vertices for each corner point
vertex(f.a);
vertex(f.b);
vertex(f.c);
}
endShape();
}



void drawMeshUniqueVerts() {
//  noStroke();

stroke(0,255,0);
strokeWeight(4);

beginShape(POINTS);

// get unique vertices, use with indices
float[] triVerts = triMesh.getUniqueVerticesAsArray();
for (int i=0; i < triVerts.length; i += 3)
{
vertex(triVerts[i], triVerts[i+1], triVerts[i+2]);
}
endShape();
}







void keyPressed()
{
switch(key)
{
case 'x':
//mesh.saveAsOBJ(sketchPath("doodle.obj"));
//mesh.saveAsSTL(sketchPath("doodle.stl"));
break;
case ' ':
// now models
for (PShape3D model : models)
{
model.delete();
}
models.clear();
break;
}
}