« Back to the project

Source Code:

//
// Bitalizer v1.2
//
// Brian Reavis
// brianreavis@inwo.com
// http://random.inwo.com/bitalizer/
//
// This is licenced under a use-modify-and
// distribute-however-you-like license. All 
// I ask is that you don't change a few lines
// and take complete credit for it. Other than
// that, have fun with it. If you make something
// with it, send me a link!
//

import processing.video.*;

//---- initial configuration ----

boolean renderVideo = false;
String filename = "shell32.dll";
color bgColor  = #000000;
color color0   = #ff002a;
color color255 = #00ffea;
color subdivisionColor = #202020;
int bytesPerFrame = 128;
float walkLength = 0.5;
float angleSpan = PI/8;

//---- setup the environment ----

void setup(){
  size(468, 320);
  frameRate(30);

  //initial positioning
  startX = width/2;
  startY = height/2;
  camX=startX;
  camY=startY;
  x = startX;
  y = startY;
  
  BUFFER_WIDTH = 256;
  BUFFER_HEIGHT = 256;
  
  //strokes and fills
  colorMode(HSB, 255);
  strokeWeight(2);
  smooth();
  background(bgColor);
  
  //initalizing the video rendering
  if (renderVideo){
    video = new MovieMaker(
      this, 
      width, 
      height, 
      str(day())+"-"+str(month())+"-"+str(year())+" "+str(hour())+str(minute())+str(second()) + ".mov", 
      30, 
      MovieMaker.ANIMATION, 
      MovieMaker.HIGH
    );
  }

  //set up the first buffer that we're going to render into
  initalizeRenderBuffers();
}

//---- general variables & functions----

int startX, startY;
float x, y;
float theta = 0;
byte[] bytes; 
MovieMaker video;
float camX,camY;
float scaleAmt = 1.0;
boolean stopRendering = false;

void keyPressed(){
    switch(key){
      case '-':
        scaleAmt -= 0.05;
        break;
      case '+':
        scaleAmt += 0.05;
        break;
      case ' ':
        stopRendering = true;
        break;
    }
}

void draw(){
  switch(frameCount){
    case 1:
      background(bgColor);
      return;
    case 2:
      loadData(filename);
      break;
    default:
      background(bgColor);
      camX -= (camX-x)/30;
      camY -= (camY-y)/30;
      scale(scaleAmt);
      translate((width/2/scaleAmt - camX), (height/2/scaleAmt - camY));
      //draw to the off-screen buffers
      if (!stopRendering) render();
      //show the buffers
      drawRenderBuffers();
      drawStartpoint();
      drawEndpoint();
      if (renderVideo){
        video.addFrame();
      }
      break;
  }
}

//---- render buffers for out-of-window rendering ----

int currentBufferI = 0;
int currentBufferJ = 0;
int relativeX = 0;
int relativeY = 0;
int BUFFER_WIDTH;
int BUFFER_HEIGHT;
PGraphics renderBuffers[];
PGraphics currentBuffer;
int renderBuffers_iAssociations[];
int renderBuffers_jAssociations[];

void initalizeRenderBuffers(){
  renderBuffers = new PGraphics[0];
  renderBuffers_iAssociations = new int[0];
  renderBuffers_jAssociations = new int[0]; 
  switchRenderBuffer(0, 0);
}

PGraphics addRenderBuffer(int iIdx, int jIdx){
  PGraphics newBuffer = createGraphics(BUFFER_WIDTH, BUFFER_HEIGHT, JAVA2D);
  newBuffer.background(bgColor);
  newBuffer.strokeWeight(0.7);
  int newBufferIdx = renderBuffers.length;
  renderBuffers = (PGraphics[])append(renderBuffers, newBuffer);
  renderBuffers_iAssociations = append(renderBuffers_iAssociations, iIdx);
  renderBuffers_jAssociations = append(renderBuffers_jAssociations, jIdx);
  
  return newBuffer;
}

void switchRenderBuffer(int iIdx, int jIdx){
  if (currentBuffer != null)
    currentBuffer.endDraw();
  currentBufferI = iIdx;
  currentBufferJ = jIdx;
  relativeX = -currentBufferI * BUFFER_WIDTH;
  relativeY = -currentBufferJ * BUFFER_HEIGHT;
  for (int i = 0; i < renderBuffers_iAssociations.length; i++){
    if (renderBuffers_iAssociations[i] == iIdx && renderBuffers_jAssociations[i] == jIdx){
      currentBuffer = renderBuffers[i];
      currentBuffer.beginDraw();
      return;
    }
  }
  try {
    currentBuffer = addRenderBuffer(iIdx, jIdx);
    currentBuffer.beginDraw();
  }catch(Exception e){
    //and... we're out of memory :(
    stopRendering = true;
  }
}

void drawRenderBuffers(){
  for (int n = 0; n < renderBuffers.length; n++){
    int x = renderBuffers_iAssociations[n]*BUFFER_WIDTH;
    int y = renderBuffers_jAssociations[n]*BUFFER_HEIGHT;
    renderBuffers[n].endDraw();
    image(renderBuffers[n], renderBuffers_iAssociations[n]*BUFFER_WIDTH, renderBuffers_jAssociations[n]*BUFFER_HEIGHT);
    noFill();
    stroke(subdivisionColor);
    strokeWeight(1);
    rect(renderBuffers_iAssociations[n]*BUFFER_WIDTH, renderBuffers_jAssociations[n]*BUFFER_HEIGHT, BUFFER_WIDTH, BUFFER_HEIGHT);
  }
}

//---- draw the bits... ----

void render(){
    currentBuffer.beginDraw();
    strokeWeight(0.5);
    float newX, newY;
    int upperBound = min(bytes.length, bytesPerFrame);
    for (int i = 0; i < upperBound; i++){
      currentBuffer.stroke(lerpColor(color0, color255, int(bytes[i])/255f), 80);
      for (int j = 0; j < 8; j++){
        int bit = bitofbyte(bytes[i],j);
        theta = theta + (bit==1?1:-1)*angleSpan; 
        newX = x + cos(theta)*walkLength;
        newY = y + sin(theta)*walkLength;
        float plot0x = x + relativeX;
        float plot0y = y + relativeY;
        float plot1x = newX + relativeX;
        float plot1y = newY + relativeY;
        currentBuffer.line(plot0x, plot0y, plot1x, plot1y);
        int bI = plot0x >= BUFFER_WIDTH ? 1 : (plot0x < 0 ? -1 : 0);
        int bJ = plot0y >= BUFFER_HEIGHT ? 1 : (plot0y < 0 ? -1 : 0);
        if (bI != 0 || bJ != 0){
          switchRenderBuffer(currentBufferI+bI, currentBufferJ+bJ);
          currentBuffer.stroke(lerpColor(color0, color255, int(bytes[i])/255f), 80);
          currentBuffer.line(plot0x - BUFFER_WIDTH*bI, plot0y - BUFFER_HEIGHT*bJ, plot1x - BUFFER_WIDTH*bI, plot1y - BUFFER_HEIGHT*bJ);
        }
        x = newX;
        y = newY;
      }
    }
    currentBuffer.endDraw();
    bytes = subset(bytes, upperBound);
    if (bytes.length == 0 && renderVideo){
      video.finish();
      exit(); 
    }
}

//---- other rendering functions ----

void drawStartpoint(){
  fill(0);
  stroke(#d8ff00);
  strokeWeight(2);
  ellipseMode(CENTER);
  ellipse(startX, startY, 3, 3);
}

void drawEndpoint(){
  fill(0);
  stroke(#d8ff00);
  strokeWeight(2);
  ellipseMode(CENTER);
  ellipse(x, y, 3, 3);
}

//---- auxiliary functions ----

int bitofbyte(byte bite, int idx){
  return (bite & 1 << (7 - idx)) != 0 ? 1 : 0;
}

void loadData(String filename){
  print("Loading bytes from ");
  print(filename);
  print("...");
  bytes = loadBytes(filename);
  println(" Done.");
}

//...and that's it!