Skip to content

Instantly share code, notes, and snippets.

@nossidge
Created April 21, 2014 15:17
Show Gist options
  • Save nossidge/11145652 to your computer and use it in GitHub Desktop.
Save nossidge/11145652 to your computer and use it in GitHub Desktop.
Naturalistic cross-hatching effect
// Scratchy rectangle shapes.
// Lines with origin and destination points that are subtly randomised around a point.
// Creates a naturalistic cross-hatching effect.
// Save as animated GIF
// Requires gifAnimation Processing Library
// http://www.extrapixel.ch/processing/gifAnimation/
import gifAnimation.*;
GifMaker gifExport;
boolean saveToGif = false;
int gifFrameCount = 0;
int gifFrameDelay = 1000;
////////////////////////////////////////////////////////////////////////////////
// GIF stuff.
void gifCreateNew() {
if (saveToGif) {
gifExport = new GifMaker(this, System.currentTimeMillis() + ".gif");
gifExport.setRepeat(0);
gifFrameCount = 0;
}
}
void gifAddFrame() {
if (saveToGif) {
gifExport.setDelay(gifFrameDelay);
gifExport.addFrame();
gifFrameCount++;
}
}
void gifSave() {
if (saveToGif) {
gifExport.setDelay(gifFrameDelay);
gifExport.finish();
saveToGif = false;
println("Frames saved: " + gifFrameCount );
}
}
void keyPressed(){
switch( int(key) ) {
case 112: save(System.currentTimeMillis() + ".png"); break; // P= save as png
case 114: saveToGif=true; gifCreateNew(); break; // R= record new animated gif
case 115: gifSave(); break; // S= save the current gif
}
}
void stop() {
gifSave();
}
////////////////////////////////////////////////////////////////////////////////
void setup() {
frameRate(1);
size(900,700);
strokeWeight(0);
stroke(0);
draw();
}
////////////////////////////////////////////////////////////////////////////////
void draw() {
background(103);
final int shapeType = 5;
// 1) Difference between border before fill or border after fill.
if ( shapeType == 1 ) {
float zoom = 0.6;
size(int(900*zoom),int(700*zoom));
ScratchyRect rectLBorderUnder = new ScratchyRect(100*zoom,100*zoom,300*zoom,500*zoom,5,true,30,33,true,235,2,true,true);
ScratchyRect rectRBorderOver = new ScratchyRect(500*zoom,100*zoom,300*zoom,500*zoom,5,true,30,33,true,235,2,false,true);
rectLBorderUnder.draw();
rectRBorderOver.draw();
}
if ( shapeType == 2 ) {
float zoom = 0.6;
size(int(800*zoom),int(700*zoom));
ScratchyRect bigRectN = new ScratchyRect(100*zoom,100*zoom,600*zoom,250*zoom,5,true,30,33,true,255,2,false,false);
bigRectN.drawBorderE = false;
bigRectN.drawBorderS = false;
bigRectN.draw();
ScratchyRect bigRectE = new ScratchyRect(400*zoom,100*zoom+3,300*zoom,500*zoom,5,true,30,33,true,255,2,false,false);
bigRectE.drawBorderW = false;
bigRectE.drawBorderN = false;
bigRectE.draw();
}
if ( shapeType == 3 ) {
float zoom = 1.2;
size(int(400*zoom),int(350*zoom));
ScratchyRect bigRectN = new ScratchyRect(50*zoom,50*zoom,300*zoom,125*zoom,5,true,30,33,true,235,2,true,false);
bigRectN.drawBorderE = false;
bigRectN.drawBorderS = false;
bigRectN.draw();
ScratchyRect bigRectE = new ScratchyRect(200*zoom,50*zoom+2,150*zoom,250*zoom,5,true,30,33,true,235,2,true,false);
bigRectE.drawBorderW = false;
bigRectE.drawBorderN = false;
bigRectE.draw();
ScratchyRect bigRectSW = new ScratchyRect(30*zoom,195*zoom,150*zoom,125*zoom,5,true,30,33,true,235,2,true,false);
bigRectSW.drawBorderE = false;
bigRectSW.drawBorderN = false;
bigRectSW.draw();
}
// Four quadrants, only outer line borders.
if ( shapeType == 4 ) {
float zoom = 1.1;
size(int(400*zoom),int(350*zoom));
ScratchyRect borderRect = new ScratchyRect(50*zoom,50*zoom,300*zoom,250*zoom,7,true,0,22,false,255,2,true,false);
borderRect.draw();
ScratchyRect bigRectNW = new ScratchyRect(50*zoom,50*zoom,150*zoom,125*zoom,5,false,30,33,true,235,2,true,false);
bigRectNW.drawBorderN = false;
bigRectNW.drawBorderE = false;
bigRectNW.drawBorderS = false;
bigRectNW.drawBorderW = false;
bigRectNW.draw();
ScratchyRect bigRectNE = new ScratchyRect(200*zoom,50*zoom,150*zoom,125*zoom,5,false,30,33,true,235,2,true,false);
bigRectNE.drawBorderN = false;
bigRectNE.drawBorderE = false;
bigRectNE.drawBorderS = false;
bigRectNE.drawBorderW = false;
bigRectNE.draw();
ScratchyRect bigRectSE = new ScratchyRect(200*zoom,175*zoom,150*zoom,125*zoom,5,false,30,33,true,235,2,true,false);
bigRectSE.drawBorderN = false;
bigRectSE.drawBorderE = false;
bigRectSE.drawBorderS = false;
bigRectSE.drawBorderW = false;
bigRectSE.draw();
ScratchyRect bigRectSW = new ScratchyRect(50*zoom,175*zoom,150*zoom,125*zoom,5,false,30,33,true,235,2,true,false);
bigRectSW.drawBorderN = false;
bigRectSW.drawBorderE = false;
bigRectSW.drawBorderS = false;
bigRectSW.drawBorderW = false;
bigRectSW.draw();
}
// Mondrian
if ( shapeType == 5 ) {
float zoom = 4;
size(int(100*zoom),int(100*zoom));
background(255);
float borderRandomVariance = 3.2;
// Draw the colour cells first
ScratchyRect rectTopRed = new ScratchyRect(0*zoom,0*zoom,45*zoom,40*zoom,borderRandomVariance,true,0,33,true,color(210,0,0),4,false,false);
rectTopRed.drawBorderN = false;
rectTopRed.drawBorderW = false;
rectTopRed.draw();
ScratchyRect rectBotYellow = new ScratchyRect(0*zoom,65*zoom,10*zoom,35*zoom,borderRandomVariance,true,0,33,true,color(253,209,1),4,false,false);
rectBotYellow.drawBorderS = false;
rectBotYellow.drawBorderW = false;
rectBotYellow.draw();
ScratchyRect rectBotBlue = new ScratchyRect(45*zoom,65*zoom,32.5*zoom,30*zoom,borderRandomVariance,true,0,33,true,color(51,35,93),4,false,false);
rectBotBlue.draw();
// Then draw the white
ScratchyRect rectTopWhite = new ScratchyRect(45*zoom,0*zoom,55*zoom,40*zoom,borderRandomVariance,true,0,33,true,color(252,243,220),4,false,false);
rectTopWhite.drawBorderN = false;
rectTopWhite.drawBorderE = false;
rectTopWhite.draw();
ScratchyRect rectMidLeft = new ScratchyRect(0*zoom,40*zoom,45*zoom,25*zoom,borderRandomVariance,true,0,33,true,color(252,243,220),4,false,false);
rectMidLeft.drawBorderW = false;
rectMidLeft.draw();
ScratchyRect rectMidRight = new ScratchyRect(45*zoom,40*zoom,55*zoom,25*zoom,borderRandomVariance,true,0,33,true,color(252,243,220),4,false,false);
rectMidRight.drawBorderE = false;
rectMidRight.draw();
ScratchyRect rectBotLeftWhite = new ScratchyRect(10*zoom,65*zoom,35*zoom,35*zoom,borderRandomVariance,true,0,33,true,color(252,243,220),4,false,false);
rectBotLeftWhite.drawBorderS = false;
rectBotLeftWhite.draw();
ScratchyRect rectBotBlueUnder = new ScratchyRect(45*zoom,95*zoom,32.5*zoom,30*zoom,borderRandomVariance,true,0,33,true,color(252,243,220),4,false,false);
rectBotBlueUnder.draw();
ScratchyRect rectBotRightWhite = new ScratchyRect(77.5*zoom,65*zoom,22.5*zoom,35*zoom,borderRandomVariance,true,0,33,true,color(252,243,220),4,false,false);
rectBotRightWhite.drawBorderS = false;
rectBotRightWhite.drawBorderE = false;
rectBotRightWhite.draw();
}
gifAddFrame();
}
////////////////////////////////////////////////////////////////////////////////
// A line whose start and end point randomly "huddles" around fixed start & end points.
// Remembers the random variance, so subsequent draw()s will display the same line.
// No encapsulation. All variables are exposed.
class ScratchyLine {
// Position of line.
float xPos1, yPos1, xPos2, yPos2;
// Random variance for the x/y positions of the line.
float randomPosRange = 2;
// How many times should we draw over the scratchy lines?
int lineIterations = 4;
// Colour of the line.
color lineColour = 0;
// Store the varience of the positions.
float[] xPos1Rand;
float[] yPos1Rand;
float[] xPos2Rand;
float[] yPos2Rand;
// Empty constructor.
ScratchyLine() {
calculateRandomNos();
}
// Everything constructor.
ScratchyLine (float xPos1arg, float yPos1arg, float xPos2arg, float yPos2arg,
float randomPosRangeArg, int lineIterationsArg, color lineColourArg) {
xPos1 = xPos1arg;
yPos1 = yPos1arg;
xPos2 = xPos2arg;
yPos2 = yPos2arg;
randomPosRange = randomPosRangeArg;
lineIterations = lineIterationsArg;
lineColour = lineColourArg;
calculateRandomNos();
}
// Calculate the random variance of the positions.
void calculateRandomNos() {
xPos1Rand = new float[lineIterations];
yPos1Rand = new float[lineIterations];
xPos2Rand = new float[lineIterations];
yPos2Rand = new float[lineIterations];
for (int i = 0; i < lineIterations; i++) {
xPos1Rand[i] = random(-randomPosRange,randomPosRange);
yPos1Rand[i] = random(-randomPosRange,randomPosRange);
xPos2Rand[i] = random(-randomPosRange,randomPosRange);
yPos2Rand[i] = random(-randomPosRange,randomPosRange);
}
}
// Draw the line.
void draw() {
stroke(lineColour);
for (int i = 0; i < lineIterations; i++) {
line(xPos1+xPos1Rand[i],
yPos1+yPos1Rand[i],
xPos2+xPos2Rand[i],
yPos2+yPos2Rand[i]
);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// A rect made out of ScratchyLines. Rounded corners not supported.
// No encapsulation. All variables are exposed.
class ScratchyRect {
// Position & size of rectangle.
float xPos = 0;
float yPos = 0;
float xWidth = 50;
float yHeight = 50;
// Random variance for the x/y positions of the borders.
float randomPosRange = 2;
// Colour of the borders and the fill.
// (Borders are all the same colour)
color borderColour = 0;
color fillColour = 255;
// How many times should we draw over the scratchy lines?
int borderIterations = 4;
int fillIterations = 2;
// Should we fill the interior of the rect?
Boolean drawFill = true;
// Increment of x and y axis when drawing the fill hatching.
// Do be sure that this is greater than zero...
int fillLineIncrement = 1;
// Should we draw the inside fill before the border,
// or the border before the inside fill?
Boolean fillBeforeBorder = true;
// Should we recalculate the random variances each time we draw?
Boolean recalculate = false;
Boolean alreadyCalculated = false; // Don't alter this.
// Arrays of ScratchyLine objects.
ScratchyLine[] borderLines;
ScratchyLine[] fillLinesX;
ScratchyLine[] fillLinesY;
// Draw all / individual borders.
// ( Should I use both "drawBorders" and "drawBorderS"?
// Java is case sensitive, but still... )
Boolean drawBorders = true;
Boolean drawBorderN = true;
Boolean drawBorderS = true;
Boolean drawBorderE = true;
Boolean drawBorderW = true;
// Empty constructor.
ScratchyRect() {}
// Everything constructor.
ScratchyRect (float xPosArg, float yPosArg, float xWidthArg, float yHeightArg,
float randomPosRangeArg,
Boolean drawBordersArg, color borderColourArg, int borderIterationsArg,
Boolean drawFillArg, color fillColourArg, int fillIterationsArg,
Boolean fillBeforeBorderArg, Boolean recalculateArg) {
xPos = xPosArg;
yPos = yPosArg;
xWidth = xWidthArg;
yHeight = yHeightArg;
randomPosRange = randomPosRangeArg;
borderIterations = borderIterationsArg;
fillIterations = fillIterationsArg;
drawBorders = drawBordersArg;
borderColour = borderColourArg;
drawFill = drawFillArg;
fillColour = fillColourArg;
fillBeforeBorder = fillBeforeBorderArg;
recalculate = recalculateArg;
}
void draw() {
// Number of borders to draw.
int intN = (drawBorderN) ? 1 : 0;
int intS = (drawBorderS) ? 1 : 0;
int intE = (drawBorderE) ? 1 : 0;
int intW = (drawBorderW) ? 1 : 0;
int borderCount = intN + intS + intE + intW;
if (recalculate || !alreadyCalculated) {
borderLines = new ScratchyLine[borderCount];
// Only draw the specified borders.
int index = 0;
if (drawBorderW) borderLines[index++] = new ScratchyLine(xPos,yPos,xPos,yPos+yHeight,randomPosRange,borderIterations,borderColour);
if (drawBorderN) borderLines[index++] = new ScratchyLine(xPos,yPos,xPos+xWidth,yPos,randomPosRange,borderIterations,borderColour);
if (drawBorderS) borderLines[index++] = new ScratchyLine(xPos+xWidth,yPos+yHeight,xPos,yPos+yHeight,randomPosRange,borderIterations,borderColour);
if (drawBorderE) borderLines[index++] = new ScratchyLine(xPos+xWidth,yPos+yHeight,xPos+xWidth,yPos,randomPosRange,borderIterations,borderColour);
}
// Draw the borders.
if (drawBorders && fillBeforeBorder) {
for (int i = 0; i < borderCount; i++) {
borderLines[i].draw();
}
}
// Draw a fill line for each X and Y axis line, plus fillLineIncrement.
if (drawFill) {
// Make sure it hasn't been set to a foolish value.
if (fillLineIncrement <= 0) fillLineIncrement = 1;
if (recalculate || !alreadyCalculated) {
fillLinesX = new ScratchyLine[int(xWidth)];
for (int x = 0; x < int(xWidth); x=x+fillLineIncrement) {
fillLinesX[x] = new ScratchyLine(xPos+x,yPos,xPos+x,yPos+yHeight,2,fillIterations,fillColour);
}
fillLinesY = new ScratchyLine[int(yHeight)];
for (int y = 0; y < int(yHeight); y=y+fillLineIncrement) {
fillLinesY[y] = new ScratchyLine(xPos,yPos+y,xPos+xWidth,yPos+y,2,fillIterations,fillColour);
}
}
// Draw them!
for (int x = 0; x < int(xWidth); x=x+fillLineIncrement) {
fillLinesX[x].draw();
}
for (int y = 0; y < int(yHeight); y=y+fillLineIncrement) {
fillLinesY[y].draw();
}
alreadyCalculated = true;
}
// Draw the borders.
if (drawBorders && !fillBeforeBorder) {
for (int i = 0; i < borderCount; i++) {
borderLines[i].draw();
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment