Load STL files without libraries

A simple STL loader (ASCII only) with a simple viewer. No libraries needed.

    PShape s; int p; String sub; Float X,Y,Z;
    float rotX, rotY, camX, camY, camZ;
 
    void setup() 
    { 
      size(640, 360, P3D); 
      background(0); 
      stroke(255);
      fill(130); 
      s=createShape(); 
      s.beginShape(TRIANGLES); 
      String[] lines = loadStrings("test.stl"); //LOAD ASCII STL ONLY!!!
      for (int i = 0 ; i < lines.length; i++) 
      { 
        p=lines[i].indexOf("vertex"); 
        if (p>-1) 
        { 
         sub=lines[i].substring(p+7); 
         String[] list = split(sub, ' ');
         X=float(list[0]); Y=float(list[1]); Z=float(list[2]);
         s.vertex(X, Y, Z);
        } 
      } 
      s.endShape(); 
      camX=width/2;
      camY=height/2;
      rotX=0;
      rotY=0;
    }
 
    void draw() 
    { 
     background(0);
     translate(camX, camY, camZ);
     rotateY(rotY);
     rotateX(rotX);
     shape(s, 0, 0);
    }
 
void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  camZ+=e*5;
}
 
void mouseDragged()
{
  if (mouseButton == LEFT)
  {
    rotY += (pmouseX - mouseX)*0.01;
    rotX += (pmouseY - mouseY)*0.01;
  }
  if (mouseButton == RIGHT)
  {
    camX -= (pmouseX - mouseX);
    camY -= (pmouseY - mouseY);
  }
  if (mouseButton == CENTER)
  {
    camZ += (pmouseY - mouseY);
  }
}
4 Likes

Finally the binary STL loader version. Maybe not the best piece of code… but it seems working. The only annoying procedure is the transformation of binary numbers between big and little endian. For this, a conversion procedure was taken somewhere in this forum. At the moment I’m not completely satisfied with that slow method but I’m not able to find a better solution.
In any case, the code loads stl files both ASCII and binary and it display them. In the future a simple directory navigation tool could be inserted. Currently, stl files should be put in the program folder.
Hope this could be useful to someone.


import java.io.FileInputStream;
import java.io.DataInputStream;

    PShape s;  
    float rotX, rotY, camX, camY, camZ;
    boolean shape=false;
    
    java.io.File folder;
    int showfiles=0;
    File[] files;

    void setup() 
    { 
      size(1024, 768, P3D); 
      background(0); 
      stroke(255);
      fill(130); 
      camX=width/2;
      camY=height/2;
      rotX=0;
      rotY=0;
    }

    void draw() 
    { 
     background(0);
     textSize(32);
     if (showfiles>0) {     
      for (int i = 0; i < files.length; i++) {
        if (files[i].isDirectory()) fill(255,0,0); else fill(150);
        text(files[i].getName(),20,32+i*32);
       }
      }
     fill(130);   
     translate(camX, camY, camZ);
     rotateY(rotY);
     rotateX(rotX);
     if (shape) shape(s, 0, 0);
      else text("Click for menu",0,0);
    }
    
void loadSTL(String filename)
{
   float N,X,Y,Z;
   int vertices=0;
   int p; String sub;
      s=createShape(); 
      s.beginShape(TRIANGLES); 
      String[] lines = loadStrings(filename); //LOAD ASCII STL ONLY!!!
      for (int i = 0 ; i < lines.length; i++) 
      { 
        p=lines[i].indexOf("vertex"); 
        if (p>-1) 
        { 
         sub=lines[i].substring(p+7); 
         String[] list = split(sub, ' ');
         X=float(list[0]); Y=float(list[1]); Z=float(list[2]);
         s.vertex(X, Y, Z);
         vertices++;
        } 
      } 
      s.endShape();
   if (vertices==0) //no vertices? it could be binary STL
    {
      println(filename,"is a binary file");
      try{
      FileInputStream fis = new FileInputStream(sketchPath(filename));
      DataInputStream input = new DataInputStream(fis);
      byte[] header = new byte[80];
      byte[] b4=new byte[4];
      byte[] attribute=new byte[2];
      byte[] normal = new byte[12];
      input.read(header);  //read header and throw away
      input.read(b4); vertices=unhex((hex(b4[3])+hex(b4[2])+hex(b4[1])+hex(b4[0]))); //again this endianity
      println("vertices: ",vertices);
      s=createShape(); 
      s.beginShape(TRIANGLES); 
      for (int i = 0 ; i < vertices; i++){
       input.read(normal); //ignore surface normals
       for (int j=0;j<3;j++){
        input.read(b4); X=annoyingEndian(b4);
        input.read(b4); Y=annoyingEndian(b4);
        input.read(b4); Z=annoyingEndian(b4);
        s.vertex(X, Y, Z);}
        input.read(attribute); //ignore attribute
      }
        s.endShape();      
        input.close();
      }
          catch (IOException e)
    {
      System.out.println("IOException : " + e);
    }
    }
   shape=true;   
}

void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  camZ+=e*5;
}

void mouseDragged()
{
  if (mouseButton == LEFT)
  {
    rotY+=(pmouseX-mouseX)*0.01;
    rotX+=(pmouseY-mouseY)*0.01;
  }
  if (mouseButton==RIGHT)
  {
    camX-=(pmouseX-mouseX);
    camY-=(pmouseY-mouseY);
  }
  if (mouseButton==CENTER)
  {
    camZ+=(pmouseY-mouseY);
  }
}

void mouseClicked()
{
 if (showfiles==0) {  
 files = listFiles(sketchPath(""));
 showfiles=1;
 }
 else
 {showfiles=0;
  if (mouseX<500)
   {
    int Choice=mouseY/32;
    if (Choice<files.length)
    {
     showfiles=1;
     String filename;
     filename=files[Choice].getName();
     println(filename);
     if (filename.toLowerCase().indexOf(".stl")>-1) loadSTL(filename);
    }
   }
 }
}

Float annoyingEndian(byte[] b)
{
  return Float.intBitsToFloat(unhex((hex(b[3])+hex(b[2])+hex(b[1])+hex(b[0]))));
}
3 Likes

Thank you for sharing this!

I see you also cross-posted this as an alternative to importing the toxiclibs library STLReader class, loadBinary method – does your version work differently than STLReader in any way, or is the point that it is simple and dependency-free?

A simple method might also be interesting to people in p5.js who periodically ask how to import STL in p5.js JavaScript – and don’t currently have a solution (I think?)

1 Like

Hi, thanks for the appreciation. Yes, the strength of this code is that is dependency-free. I have no experience in p5.js but I think that the code could be easily implemented (change mouse controls…dunno about file loading there).

1 Like

Looking for STL readers and writers, I stumbled upon this thread. I gotta say that the OP’s code (Kalium’s code) is elegant and professionally written. Just a quick copy and paste and I have myself an STL reader and display-er!

I did have to adjust a few mouse controls to get things working smoothly on the Mac and a square window works best for me. Minor changes for a cross-platform compile. Well done.

Les

2 Likes

@Kalium you should take to the next step and bundle it in a jar and make it available in the PDE’s contribution manager as a library. This is only a suggestion.

Kf

1 Like

@Kalium i am using your first example and try to import STL file into processing but so far no success. Or may be does it take long time to process ? my STL file size is 20MB.
just for info i also put the STL file into the same folder of sketch running.