Created
December 22, 2017 23:59
-
-
Save rm-hull/825011d54b6b29f56c685591738e5b1a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Pixel Spaceships | |
// David Bollinger - July 2006 | |
// http://www.davebollinger.com | |
// for Processing 0115 beta | |
// (updated for 0119 Beta) | |
/** | |
Click mouse to advance early to next pattern<br> | |
*/ | |
PixelSpaceshipFitter fitter; | |
PixelSpaceship ship; | |
miniMT rng; // want a slightly more robust rng for 32 significant bits | |
int currentSeed = 0; | |
void setup() { | |
size(480,480,P3D); | |
frameRate(30); | |
fitter = new PixelSpaceshipFitter(480/16, 480/16); | |
rng = new miniMT(); | |
next(); | |
} | |
void mousePressed() { | |
next(); | |
} | |
void next() { | |
background(255); | |
fitter.make(++currentSeed); | |
} | |
void draw() { | |
fitter.drawone(); | |
if (fitter.at00()) | |
next(); | |
} | |
// the generator | |
class PixelSpaceship { | |
static final int cols = 12; | |
static final int rows = 12; | |
static final int EMPTY = 0; | |
static final int AVOID = 1; | |
static final int SOLID = 2; | |
static final int COKPT = 3; // ::added to aid coloring | |
int seed; | |
int colorseed; // ::added to aid coloring | |
int[][] grid; | |
int xscale, yscale; | |
int xmargin, ymargin; | |
PixelSpaceship() { | |
grid = new int[rows][cols]; | |
xscale = yscale = 1; | |
xmargin = ymargin = 0; | |
} | |
void recolor() { // ::added to aid coloring | |
colorseed = rng.generate(); | |
} | |
int getHeight() { | |
return rows*yscale + ymargin*2; | |
} | |
int getWidth() { | |
return cols*xscale + xmargin*2; | |
} | |
void setMargins(int xm, int ym) { | |
xmargin = xm; | |
ymargin = ym; | |
} | |
void setScales(int xs, int ys) { | |
xscale = xs; | |
yscale = ys; | |
} | |
void setSeed(int s) { | |
seed = s; | |
} | |
void wipe() { | |
for (int r=0; r<rows; r++) | |
for (int c=0; c<cols; c++) | |
grid[r][c] = EMPTY; | |
} // wipe() | |
void generate() { | |
wipe(); | |
// FILL IN THE REQUIRED SOLID CELLS | |
int [] solidcs = { 5,5,5,5,5 }; | |
int [] solidrs = { 2,3,4,5,9 }; | |
for (int i=0; i<5; i++) { | |
int c = solidcs[i]; | |
int r = solidrs[i]; | |
grid[r][c] = SOLID; | |
} | |
// FILL IN THE SEED-SPECIFIED BODY CELLS, AVOID OR EMPTY | |
int [] avoidcs = { 4,5,4,3,4,3,4,2,3,4,1,2,3,1,2,3,1,2,3,1,2,3,4,3,4,5 }; | |
int [] avoidrs = { 1,1,2,3,3,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,9,10,10,10 }; | |
int bitmask = 1; | |
for (int i=0; i<26; i++) { | |
int c = avoidcs[i]; | |
int r = avoidrs[i]; | |
grid[r][c] = ((seed & bitmask) != 0) ? AVOID : EMPTY; | |
bitmask <<= 1; | |
} | |
// FLIP THE SEED-SPECIFIED COCKPIT CELLS, SOLID OR EMPTY | |
int [] emptycs = { 4,5,4,5,4,5 }; | |
int [] emptyrs = { 6,6,7,7,8,8 }; | |
bitmask = 1 << 26; | |
for (int i=0; i<6; i++) { | |
int c = emptycs[i]; | |
int r = emptyrs[i]; | |
grid[r][c] = ((seed & bitmask) != 0) ? SOLID : COKPT; // ::added to aid coloring | |
bitmask <<= 1; | |
} | |
// SKINNING -- wrap the AVOIDs with SOLIDs where EMPTY | |
for (int r=0; r<rows; r++) { | |
for (int c=0; c<cols; c++) { | |
int here = grid[r][c]; | |
if (here != EMPTY) continue; | |
boolean needsolid = false; | |
if ((c>0) && (grid[r][c-1]==AVOID)) needsolid=true; | |
if ((c<cols-1) && (grid[r][c+1]==AVOID)) needsolid=true; | |
if ((r>0) && (grid[r-1][c]==AVOID)) needsolid=true; | |
if ((r<rows-1) && (grid[r+1][c]==AVOID)) needsolid=true; | |
if (needsolid) | |
grid[r][c] = SOLID; | |
} | |
} | |
// mirror left side into right side | |
for (int r=0; r<rows; r++) { | |
for (int c=0; c<cols/2; c++) | |
grid[r][cols-1-c] = grid[r][c]; | |
} | |
} | |
void draw(int basex, int basey) { | |
// ::added to aid coloring | |
// here's one (of many) possible ways you might color them... | |
float[] sats = { 40,60,80,100,80,60, 80,100,120, 100,80,60 }; | |
float[] bris = { 40,70,100,130,160,190,220, 220,190,160,130,100,70,40 }; | |
noStroke(); | |
for (int r=0; r<rows; r++) { | |
for (int c=0; c<cols; c++) { | |
int x1 = basex + xmargin + c * xscale; | |
int y1 = basey + ymargin + r * yscale; | |
int m = grid[r][c]; | |
// ::added to aid coloring | |
// for monochrome just draw SOLID's as black and you're done | |
// otherwise... | |
if (m==SOLID) { | |
fill(#000000); | |
rect(x1,y1,xscale,yscale); | |
} | |
else | |
if (m == AVOID) { | |
float mysat = sats[r]; | |
float mybri = bris[c]; //+90; | |
int h = 0; | |
if (r < 6) h = (colorseed & 0xff00) >> 8; | |
else if (r < 9) h = (colorseed & 0xff0000) >> 16; | |
else h = (colorseed & 0xff000000) >> 24; | |
colorMode(HSB); | |
fill(h, mysat, mybri); | |
rect(x1,y1,xscale,yscale); | |
} | |
else | |
if (m == COKPT) { | |
float mysat = sats[c]; | |
float mybri = bris[r]+40; | |
colorMode(HSB); | |
int h = (colorseed & 0xff); | |
fill(h, mysat, mybri); | |
rect(x1,y1,xscale,yscale); | |
} | |
} | |
} | |
} | |
} | |
class PixelSpaceshipFitter { | |
PixelSpaceship ship; | |
int cols, rows; | |
int col, row; | |
int seed; | |
// cells store the box fit pattern, contents are byte encoded as: | |
// (cell >> 16) & 0xff == work to do | |
// (cell) & 0xff == size of allocated area | |
// (this somewhat odd encoding scheme is a remnant of the | |
// fractal subdivision method used for the pixel robots t-shirt image) | |
int [][] cells; | |
// the types of work that may occur in a cell | |
static final int WORK_NONE = 0; | |
static final int WORK_DONE = 1; | |
PixelSpaceshipFitter(int c, int r) { | |
cols = c; | |
rows = r; | |
ship = new PixelSpaceship(); | |
cells = new int[rows][cols]; | |
} | |
// reset the pattern grid | |
void wipe() { | |
for (int r=0; r<rows; r++) | |
for (int c=0; c<cols; c++) | |
cells[r][c] = 0; | |
col = row = 0; | |
} | |
// determines if cells already contain defined area(s) | |
boolean isOccupied(int col, int row, int wid, int hei) { | |
for (int r=row; r<row+hei; r++) { | |
for (int c=col; c<col+wid; c++) { | |
if (cells[r][c] != 0) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
// marks cells as containing an area | |
void doOccupy(int col, int row, int wid, int hei, int val) { | |
for (int r=row; r<row+hei; r++) { | |
for (int c=col; c<col+wid; c++) { | |
cells[r][c] = val; | |
} | |
} | |
} | |
// define the pattern grid | |
void make(int s) { | |
seed = s; | |
randomSeed(seed); | |
wipe(); | |
for (int r=0; r<rows; r++) { | |
for (int c=0; c<cols; c++) { | |
int cell = cells[r][c]; | |
if (cell != 0) continue; | |
// figure out the size of area to occupy | |
int sizer, limit; | |
do { | |
limit = min(cols-c, rows-r); | |
limit = min(limit, 8); | |
sizer = int(random(limit))+1; | |
} while(isOccupied(c,r,sizer,sizer)); | |
// flag all cells as occupied by width x height area | |
doOccupy(c,r,sizer,sizer,sizer); | |
// indicate work to perform in upper-left cell | |
int work = WORK_DONE; | |
cells[r][c] |= (work<<16); | |
} // for c | |
} // for r | |
} | |
// is cursor at 0,0 | |
boolean at00() { | |
return ((col==0) && (row==0)); | |
} | |
// step the cursor forward | |
void advance(int advcol) { | |
col += advcol; | |
if (col >= cols) { | |
col = 0; | |
row++; | |
if (row >= rows) { | |
row = 0; | |
} | |
} | |
} | |
// advance through the pattern and draw the next robot | |
void drawone() { | |
boolean drawn = false; | |
do { | |
int cell = cells[row][col]; | |
int work = (cell>>16) & 0xff; | |
int sizer = (cell) & 0xff; | |
if (work != WORK_NONE) { | |
int y1 = 16*row; | |
int x1 = 16*col; | |
ship.setScales( sizer, sizer ); | |
ship.setMargins( 2*sizer, 2*sizer ); | |
ship.setSeed(rng.generate()); | |
ship.generate(); | |
ship.recolor(); | |
ship.draw( x1, y1 ); | |
drawn = true; | |
} | |
advance(sizer); | |
if (at00()) return; | |
} while (!drawn); | |
} | |
} | |
// a minimal version of the Mersenne Twister | |
class miniMT { | |
private long seed; | |
private static final int N = 624; | |
private static final int M = 397; | |
private static final int MATRIX_A = 0x9908b0df; | |
private static final int UPPER_MASK = 0x80000000; | |
private static final int LOWER_MASK = 0x7fffffff; | |
private static final int TEMPERING_MASK_B = 0x9d2c5680; | |
private static final int TEMPERING_MASK_C = 0xefc60000; | |
private int mt[]; | |
private int mti; | |
private int mag01[] = { 0x0, MATRIX_A }; | |
public miniMT() { | |
this.setSeed(0); | |
} | |
public miniMT(long seed) { | |
this.setSeed(seed); | |
} | |
public void setSeed(final long _seed) { | |
seed=_seed; | |
mt = new int[N]; | |
mt[0]= (int)(seed & 0xfffffff); | |
for (mti=1; mti<N; mti++) { | |
mt[mti] = (1812433253 * (mt[mti-1] ^ (mt[mti-1] >>> 30)) + mti); | |
mt[mti] &= 0xffffffff; | |
} | |
} | |
public final int generate() { | |
int y; | |
if (mti >= N) { | |
int kk; | |
for (kk = 0; kk < N - M; kk++) { | |
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); | |
mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1]; | |
} | |
for (; kk < N-1; kk++) { | |
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); | |
mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1]; | |
} | |
y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK); | |
mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1]; | |
mti = 0; | |
} | |
y = mt[mti++]; | |
y ^= y >>> 11; | |
y ^= (y << 7) & TEMPERING_MASK_B; | |
y ^= (y << 15) & TEMPERING_MASK_C; | |
y ^= (y >>> 18); | |
return y; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment