Trouble with shapes

Hi. I’m having some trouble with drawing shapes.
I’m trying to draw a B and it doesn’t fill the whole shape.
Acording to the example on the beginContour() doc page, you don’t have to draw the starting point at the end, which I thought is needed. If you do, Processing wil set the coords to (0, 0). I understand, that the shape and the contour and the shape have to be drawn in oposite directions to each other.
I should also mention, that I’ve ran the sketch on Android.

void setup(){
  fullScreen();
}

void draw(){
  background(0);
  
  pushMatrix();
  translate(100, 100);
  scale(2);
  PVector[][] b = new PVector[][]{getPointsBOut(10), getPointsBTop(10), getPointsBBottom(10)};
  
  fill(#FF0000);
  noStroke();
  stroke(255);
  
  beginShape();
  for(PVector pv:b[0]){
    vertex(pv.x * 400 + 100, pv.y * 400 + 100);
  }
  //vertex(b[0][0].x, b[0][0].y);
  
  beginContour();
  for(int i = b[2].length - 1; i >= 0; i --){
    PVector pv = b[2][i];
    vertex(pv.x * 400 + 100, pv.y * 400 + 100);
  }
  //vertex(b[2][0].x, b[2][0].y);
  endContour();
  
  beginContour();
  for(int i = b[1].length - 1; i >= 0; i --){
    PVector pv = b[1][i];
    vertex(pv.x * 400 + 100, pv.y * 400 + 100);
  }
  //vertex(b[1][0].x, b[1][0].y);
  endContour();
  endShape(CLOSE);
  
  noFill();
  stroke(#007FFF);
  
  for(PVector[] pvl:b){
    beginShape();
    for(PVector pv:pvl){
      vertex(pv.x * 400 + 100, pv.y * 400 + 100);
    }
    endShape(CLOSE);
  }
  
  for(PVector[] pvl:b){
    for(PVector pv:pvl){
      ellipse(pv.x * 400 + 100, pv.y * 400 + 100, 10, 10);
    }
  }
  popMatrix();
}

PVector[] getPointsBOut(int curveDetail){
  curveDetail = max(2, curveDetail);
  PVector[] pts = new PVector[2 + curveDetail * 2];
  pts[0] = new PVector(0, 0);
  for(int i = 0; i < curveDetail; i ++){
    pts[1 + i] = new PVector(0.4 + sin(i * PI / curveDetail) * 0.25, 0.25 - cos(i * PI / curveDetail) * 0.25);
  }
  for(int i = 0; i < curveDetail + 1; i ++){
    pts[curveDetail + i] = new PVector(0.4 + sin(i * PI / curveDetail) * 0.25, 0.75 - cos(i * PI / curveDetail) * 0.25);
  }
  pts[pts.length - 1] = new PVector(0, 1);
  return pts;
}

PVector[] getPointsBTop(int curveDetail){
  curveDetail = max(2, curveDetail);
  PVector[] pts = new PVector[3 + curveDetail];
  pts[0] = new PVector(0.1, 0.1);
  for(int i = 0; i < curveDetail + 1; i ++){
    pts[1 + i] = new PVector(0.4 + sin(i * PI / curveDetail) * 0.15, 0.25 - cos(i * PI / curveDetail) * 0.15);
  }
  pts[pts.length - 1] = new PVector(0.1, 0.4);
  return pts;
}

PVector[] getPointsBBottom(int curveDetail){
  curveDetail = max(2, curveDetail);
  PVector[] pts = new PVector[3 + curveDetail];
  pts[0] = new PVector(0.1, 0.6);
  for(int i = 0; i < curveDetail + 1; i ++){
    pts[1 + i] = new PVector(0.4 + sin(i * PI / curveDetail) * 0.15, 0.75 - cos(i * PI / curveDetail) * 0.15);
  }
  pts[pts.length - 1] = new PVector(0.1, 0.9);
  return pts;
}

![Screenshot_20191208-103015_APDE Sketch Preview|236x500](upload://igLZ55kJJCCqFQbSRY9lfaMFq65.jpeg) 

THAT IS YOUR PICTURE, i just copy out if your code, so we see it:

as your example is not so easy,
in a first step i needed to confirm that contour can CUT OUT
2 “windows” as needed for the inner of your “B”

looks good

int x,y,w,h;

void setup() {
  size(200, 200);
}

void draw() {
  background(200, 200, 0);
  translate(width/2,height/2);
  beginShape();
  stroke(255);
  fill(200, 0, 200);
  // Exterior part of shape, clockwise winding
  x = -40; 
  y = -40; 
  w = 80; 
  h = 80;
  vertex(x, y);
  vertex(x, y+h);
  vertex(x+w, y+h);
  vertex(x+w, y);

  // Interior part of shape, counter-clockwise winding
  x = -35; 
  y = -35; 
  w = 20; 
  h = 20;
  beginContour();
  vertex(x, y);
  vertex(x+w, y);
  vertex(x+w, y+h);
  vertex(x, y+h);
  endContour();

  x = 15; 
  y = 15; 
  w = 20; 
  h = 20;
  beginContour();
  vertex(x, y);
  vertex(x+w, y);
  vertex(x+w, y+h);
  vertex(x, y+h);
  endContour();

  endShape(CLOSE);
}

your code / just with a reasonable setting for my monitor
works here

so, sorry must be a problem with your Android environment??

I mean, you can just use the text() function.

@kll Android Processing does have a lot of bugs and errors, so I’m not even surprised all that much.

@unique_username I don’t want a simple texture. I want to make an animation creating the outline and then filling the interior, like this. Also, this works on Android.

PGraphics[] gl;
int fps = 15;
float start = -0;
int frameImage = 0;
boolean loading = true;
boolean realTimeGen = false;
float scale = 0.5;
int w = 1600;
int h = 1200;
float[] l = new float[]{1, 0.5, 0.5, 1, 0.5};
AriaEasingArgument[] aea = new AriaEasingArgument[]{
  new AriaEasingArgument(AriaEasing.Type.SINE, 2, AriaEasing.Type.SINE, 2),
  new AriaEasingArgument(AriaEasing.Type.EXPONENTIAL, 2, AriaEasing.Type.EXPONENTIAL, 2),
  new AriaEasingArgument(AriaEasing.Type.POLYNOMIAL, 4, AriaEasing.Type.POLYNOMIAL, 4),
  new AriaEasingArgument(AriaEasing.Type.SINE, 2, AriaEasing.Type.SINE, 2),
  new AriaEasingArgument(AriaEasing.Type.POLYNOMIAL, 2, AriaEasing.Type.POLYNOMIAL, 2),
};
int[] sr = new int[]{-1, 0, 0, 1, 3};

void setup(){
  //size(640, 480);
  //surface.setResizable(true);
  fullScreen();
  frameRate(fps);
  //orientation(LANDSCAPE);
  
  w = width;
  h = height;
  
  float sum = 0;
  for(float f:l) sum += f;
  gl = new PGraphics[int(sum * fps - start * fps + 1)];
}

void draw(){
  background(0);
  
  textSize(50);
  textAlign(LEFT, TOP);
  imageMode(CENTER);
  if(realTimeGen){
    line(0, 100, frameImage * width / gl.length, 100);
    text("Displaying " + frameImage + " / " + (gl.length - 1), 0, 120);
    PGraphics pg = getImage();
    float scale = min(float(width) / pg.width, float(height) / pg.height);
    image(pg, width / 2, height / 2, pg.width * scale, pg.height * scale);
    frameImage ++;
    if(frameImage == gl.length) frameImage = gl.length - 1;
  }
  else{
    if(loading){
      loadNextImage();
      line(0, 100, frameImage * width / gl.length, 100);
      text("Loading " + frameImage + " / " + (gl.length - 1), 0, 120);
    }
    else{
      line(0, 100, frameImage * width / gl.length, 100);
      text("Displaying " + frameImage + " / " + (gl.length - 1), 0, 120);
      float scale = min(float(width) / gl[frameImage].width, float(height) / gl[frameImage].height);
      image(gl[frameImage], width / 2, height / 2, gl[frameImage].width * scale, gl[frameImage].height * scale);
      frameImage ++;
      if(frameImage == gl.length) frameImage = gl.length - 1;
    }
  }
  save(dataPath((frameCount >= 10000 ? "" : "0") + (frameCount >= 1000 ? "" : "0") + (frameCount >= 100 ? "" : "0") + (frameCount >= 10 ? "" : "0") + frameCount + ".png"));
}

PGraphics getImage(){
  float t = float(frameImage) / float(fps) + start;
  //float t = (float)(millis()) / 4000;
  return new LogoFurryNightShade().getGraphics(int(w * scale), int(h * scale), 1, t, l[0], l[1], l[2], l[3], l[4], sr, aea[0], aea[1], aea[2], aea[3], aea[4]);
}

void loadNextImage(){
  gl[frameImage] = getImage();
  frameImage ++;
  if(frameImage == gl.length){
    loading = false;
    frameImage = 0;
  }
}

//------------------------------------------------------------------------

//AriaEasing
//Version 1.0
//Doesn't require any other libraries

static class AriaEasing{
  enum Type{
    LINEAR, HOLD, IMMEDIATE, POLYNOMIAL, EXPONENTIAL, SINE, EULER
  }
  
  static double get(double time, double startTime, double endTime, double startValue, double endValue, AriaEasing.Type type, double tension){
    if(startTime >= endTime) return endValue;
    if(startValue == endValue) return endValue;
    return startValue + (endValue - startValue) * AriaEasing.getNormalized((time - startTime) / (endTime - startTime), type, tension);
  }
  static double get(double time, double startTime, double endTime, double startValue, double endValue, AriaEasing.Type type1, double tension1, AriaEasing.Type type2, double tension2){
    if(startTime >= endTime) return endValue;
    if(startValue == endValue) return endValue;
    return startValue + (endValue - startValue) * AriaEasing.getNormalized((time - startTime) / (endTime - startTime), type1, tension1, type2, tension2);
  }
  static double getNormalized(double time, AriaEasing.Type type1, double tension1, AriaEasing.Type type2, double tension2){
    if(time < 0) return 0;
    if(time > 1) return 1;
    if(time == 0.5) return 0.5;
    if(time < 0.5) return 0.5 * AriaEasing.getNormalized(time * 2, type1, tension1);
    return 1 - 0.5 * AriaEasing.getNormalized(2 - time * 2, type2, tension2);
  }
  static double getNormalized(double time, AriaEasing.Type type, double tension){
    if(time <= 0) return 0;
    if(time >= 1) return 1;
    
    if(Math.abs(tension) < 1) return 1 - AriaEasing.getNormalized(1 - time, type, 1 / tension);
    
    double rawOutput = 0;
    
    if(type == null) type = AriaEasing.Type.LINEAR;
    if(type == AriaEasing.Type.LINEAR) rawOutput = AriaEasing.getLinear(time);
    if(type == AriaEasing.Type.HOLD) rawOutput = AriaEasing.getHold(time);
    if(type == AriaEasing.Type.IMMEDIATE) rawOutput = AriaEasing.getImmediate(time);
    if(type == AriaEasing.Type.POLYNOMIAL) rawOutput = AriaEasing.getPolynomial(time, tension);
    if(type == AriaEasing.Type.EXPONENTIAL) rawOutput = AriaEasing.getExponential(time, tension);
    if(type == AriaEasing.Type.SINE) rawOutput = AriaEasing.getSine(time, tension);
    if(type == AriaEasing.Type.EULER) rawOutput = AriaEasing.getEuler(time, tension);
    
    return rawOutput;
  }
  
  static private double getLinear(double time){
    return time;
  }
  static private double getHold(double time){
    return time < 1 ? 0 : 1;
  }
  static private double getImmediate(double time){
    return time > 0 ? 1 : 0;
  }
  static private double getPolynomial(double time, double tension){
    if(tension < 0) return AriaEasing.getImmediate(time);
    return Math.pow(time, tension);
  }
  static private double getExponential(double time, double tension){
    return Math.pow(tension, time * 10 - 10);
  }
  static private double getSine(double time, double tension){
    if(tension < 0) return AriaEasing.getImmediate(time);
    if(tension < 1) return 1 - AriaEasing.getSine(1 - time, 1 / tension);
    return Math.pow(1 - Math.cos(time * PI / 2), tension / 2);
  }
  static private double getEuler(double time, double tension){
    if(tension < 0) return AriaEasing.getImmediate(time);
    return (Math.pow(exp(1), time * tension) - 1) / (Math.pow(exp(1), tension) - 1);
  }
}

//---------------------------------------------------

class AriaEasingArgument{
  AriaEasing.Type type1, type2;
  double tension1, tension2;
  
  AriaEasingArgument(AriaEasing.Type type1, double tension1, AriaEasing.Type type2, double tension2){
    this.type1 = type1;
    this.type2 = type2;
    this.tension1 = tension1;
    this.tension2 = tension2;
  }
}

//------------------------------------------------------

class LogoFurryNightShade{
  boolean procedureDebug = false;
  boolean errorDebug = true;
  boolean warningDebug = true;
  boolean finalDebug = false;
  String tabText = procedureDebug ? "   " : "";
  
  PVector[] pointsf = new PVector[]{
    new PVector(0, 0),
    new PVector(4 / 9.0, 0),
    new PVector(4 / 9.0, 1 / 9.0),
    new PVector(1 / 9.0, 1 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0, 6 / 9.0)
  };
  
  PVector[] pointsu = new PVector[]{
    new PVector(0, 2 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 5 / 9.0),
    new PVector(2 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(3 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(2 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0, 5 / 9.0)
  };
  
  PVector[] pointsr = new PVector[]{
    new PVector(0 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(2 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 3 / 9.0),
    new PVector(2 / 9.0, 3 / 9.0),
    new PVector(1 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 6 / 9.0)
  };
  
  PVector[] pointsy = new PVector[]{
    new PVector(0 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 8 / 9.0),
    new PVector(3 / 9.0, 9 / 9.0),
    new PVector(1 / 9.0, 9 / 9.0),
    new PVector(0 / 9.0, 8 / 9.0),
    new PVector(0 / 9.0, 7 / 9.0),
    new PVector(1 / 9.0, 7 / 9.0),
    new PVector(1 / 9.0, 8 / 9.0),
    new PVector(3 / 9.0, 8 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 5 / 9.0)
  };
  
  PVector[] pointsn = new PVector[]{
    new PVector(0 / 9.0, 0 / 9.0),
    new PVector(1 / 9.0, 0 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(3 / 9.0, 0 / 9.0),
    new PVector(4 / 9.0, 0 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 6 / 9.0)
  };
  
  PVector[] pointsi = new PVector[]{
    new PVector(0 / 9.0, 3 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 6 / 9.0)
  };
  
  PVector[] pointsic = new PVector[]{
    new PVector(0 / 9.0, 1 / 9.0),
    new PVector(1 / 9.0, 1 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(0 / 9.0, 2 / 9.0)
  };
  
  PVector[] pointsg = new PVector[]{
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(3 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 3 / 9.0),
    new PVector(4 / 9.0, 8 / 9.0),
    new PVector(3 / 9.0, 9 / 9.0),
    new PVector(1 / 9.0, 9 / 9.0),
    new PVector(0 / 9.0, 8 / 9.0),
    new PVector(0 / 9.0, 7 / 9.0),
    new PVector(1 / 9.0, 7 / 9.0),
    new PVector(1 / 9.0, 8 / 9.0),
    new PVector(3 / 9.0, 8 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 5 / 9.0),
    new PVector(0 / 9.0, 3 / 9.0)
  };
  
  PVector[] pointsgc = new PVector[]{

    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(1 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 3 / 9.0)
  };
  
  PVector[] pointsh = new PVector[]{
    new PVector(0 / 9.0, 0 / 9.0),
    new PVector(1 / 9.0, 0 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 3 / 9.0),
    new PVector(4 / 9.0, 4 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 6 / 9.0)
  };
  
  PVector[] pointst = new PVector[]{
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(2 / 9.0, 2 / 9.0),
    new PVector(2 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(2 / 9.0, 4 / 9.0),
    new PVector(2 / 9.0, 5 / 9.0),
    new PVector(4 / 9.0, 5 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 4 / 9.0),
    new PVector(0 / 9.0, 4 / 9.0),
    new PVector(0 / 9.0, 3 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0)
  };
  
  PVector[] pointss = new PVector[]{
    new PVector(0 / 9.0, 0 / 9.0),
    new PVector(4 / 9.0, 0 / 9.0),
    new PVector(4 / 9.0, 1 / 9.0),
    new PVector(1 / 9.0, 1 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 3 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(0 / 9.0, 3 / 9.0)
  };
  
  PVector[] pointsa = new PVector[]{

    new PVector(3 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(0 / 9.0, 3 / 9.0),
    new PVector(0 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 1 / 9.0),
    new PVector(3 / 9.0, 1 / 9.0),
    new PVector(4 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(2 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 5 / 9.0),
    new PVector(0 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0)
  };
  
  PVector[] pointsac = new PVector[]{
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 5 / 9.0),
    new PVector(2 / 9.0, 5 / 9.0)
  };
  
  PVector[] pointsd = new PVector[]{

    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 0 / 9.0),
    new PVector(4 / 9.0, 0 / 9.0),
    new PVector(4 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(2 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 5 / 9.0),
    new PVector(0 / 9.0, 4 / 9.0)
  };
  
  PVector[] pointse = new PVector[]{
    new PVector(1 / 9.0, 1 / 9.0),
    new PVector(3 / 9.0, 1 / 9.0),
    new PVector(4 / 9.0, 2 / 9.0),
    new PVector(4 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 4 / 9.0),
    new PVector(1 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 5 / 9.0),
    new PVector(4 / 9.0, 4 / 9.0),
    new PVector(4 / 9.0, 5 / 9.0),
    new PVector(3 / 9.0, 6 / 9.0),
    new PVector(1 / 9.0, 6 / 9.0),
    new PVector(0 / 9.0, 5 / 9.0),
    new PVector(0 / 9.0, 2 / 9.0)
  };
  
  PVector[] pointsec = new PVector[]{
    new PVector(3 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 2 / 9.0),
    new PVector(1 / 9.0, 3 / 9.0),
    new PVector(3 / 9.0, 3 / 9.0)
  };
  
  PVector[] pointsdc = this.pointsac;
  
  float strokeSize = 0.02;
  color strokeColor = #00F5FF;
  color bgGradLT = #FF96FD;
  color bgGradRB = #D9FF96;
  color bgGradLT2 = #984DFF;
  color bgGradRB2 = #4DFFFD;
  
  
  LogoFurryNightShade(){
    
  }
  
  LogoFurryNightShade(float strokeSize, color strokeColor, color bgGradLT, color bgGradRB){
    this.strokeSize = strokeSize;
    this.strokeColor = strokeColor;
    this.bgGradLT = bgGradLT;
    this.bgGradRB = bgGradRB;
  }
  
  PGraphics getGraphics(int x, int y, float logoSize, float animationTime, float animCS, float animM, float animCF, float animLS, float animLF, int[] startReq, AriaEasingArgument aeaCS, AriaEasingArgument aeaM, AriaEasingArgument aeaCF, AriaEasingArgument aeaLS, AriaEasingArgument aeaLF){
    if(procedureDebug){
      print("\nLogoFurryNightShade.getGraphics(x:" + x + ", y:" + y + ", logoSize:" + logoSize + ", animCS:" + animCS + ", animM:" + animM + ", animCF:" + animCF + ", animLS:" + animLS + ", animLF:" + animLF + ", startReq:");
      if(startReq == null) println("null);");
      else{
        print("new int[]{");
        for(int i = 0; i < startReq.length; i ++){
          if(i != 0) print(", ");
          print(startReq[i]);
        }
        print("});");
      }
    }
    
    if(procedureDebug) println("Checking inpited values...");
    if(x <= 0 || y <= 0){
      if(errorDebug) println(tabText + "Error: Size must be greater than 0 in both directions (" + x + ", " + y + ").");
      if(finalDebug) println(tabText + "Returned null.");
      return null;
    }
    logoSize = constrain(logoSize, 0, 1);
    if(logoSize <= 0){
      if(errorDebug) println(tabText + "Error: Logo size must be greater than 0 (" + logoSize + ").");
      if(finalDebug) println(tabText + "Returned empty PGraphics.");
      return createGraphics(x, y);
    }
    if(animationTime <= 0){
      if(errorDebug) println(tabText + "Error: Time must be greater than 0 (" + animationTime + ").");
      if(finalDebug) println(tabText + "Returned rmpty PGraphics.");
      return createGraphics(x, y);
    }
    animCF = animCF < 0 ? 0 : animCF;
    animCS = animCS < 0 ? 0 : animCS;
    animM = animM < 0 ? 0 : animM;
    animLF = animLF < 0 ? 0 : animLF;
    animLS = animLS < 0 ? 0 : animLS;
    
    if(procedureDebug) println("Checking startReq...");
    if(startReq == null){
      if(warningDebug) println(tabText + "startReq is null. Setting startReq to default...");
      startReq = new int[]{-1, 0, 1, 2, 3};
    }
    if(startReq.length != 5){
      if(warningDebug) println(tabText + "startReq is not 5 values long(" + startReq.length + "). Setting startReq to default...");
      startReq = new int[]{-1, 0, 1, 2, 3};
    }
    
    if(procedureDebug) println("Checking for startReq loops...");
    for(int i = 0; i < startReq.length; i ++){
      int req = startReq[i];
      boolean loopFound = false;
      IntList history = new IntList();
      history.append(req);
      while(req >= 0 && req < 5){
        if(req == i){
          loopFound = true;
          history.append(req);
          break;
        }
        history.append(req);
        req = startReq[req];
      }
      if(loopFound){
        if(errorDebug){
          print(tabText + "Found a loop in startReq of length " + (history.size() - 1) + "(");
          for(int j = 0; j < history.size(); j ++){
            if(j != 0) print(" > ");
            print(history.get(j));
          }
          print(").");
        }
        if(finalDebug) println(tabText + "Returned empty PGraphics.");
        return createGraphics(x, y);
      }
    }
    
    float scale = logoSize * min(x / 6.0, y / 1.0);
    if(scale * x < 1 || scale * y < 1){
      if(errorDebug) println(tabText + "Error: Scaled size must be greater than 0 in both directions (" + int(x * scale) + ", " + int(y * scale) + ").");
      if(finalDebug) println(tabText + "Returned null.");
      return null;
    }
    
    return this.generateGraphics(x, y, logoSize, animationTime, animCS, animM, animCF, animLS, animLF, startReq, aeaCS, aeaM, aeaCF, aeaLS, aeaLF);
  }
  
  private PGraphics generateGraphics(int x, int y, float logoSize, float animationTime, float animCS, float animM, float animCF, float animLS, float animLF, int[] startReq, AriaEasingArgument aeaCS, AriaEasingArgument aeaM, AriaEasingArgument aeaCF, AriaEasingArgument aeaLS, AriaEasingArgument aeaLF){
    if(this.procedureDebug) println("Generating graphics...");
    if(this.procedureDebug) println("Calculating time values...");
    float[] animLength = new float[]{animCS, animM, animCF, animLS, animLF};
    int[] deps = new int[5];
    for(int i = 0; i < 5; i ++){
      int l = -1;
      int req = i;
      while(req >= 0 && req < 5){
        l ++;
        req = startReq[req];
      }
      deps[i] = l;
    }
    float[] animStart = new float[5];
    float[] animEnd = new float[5];
    for(int dep = 0; dep < 5; dep ++){
      for(int i = 0; i < 5; i ++){
        if(deps[i] == dep){
          if(dep == 0) animStart[i] = 0;
          else animStart[i] = animEnd[startReq[i]];
          animEnd[i] = animStart[i] + animLength[i];
        }
      }
    }
    
    if(frameCount == 30){
      printArray(animStart);
      printArray(animEnd);
    }
    
    float scale = logoSize * min(x * 9.0 / 72.0, y / 9.0);
    
    float animCSP = constrain((animationTime - animStart[0]) / (animEnd[0] - animStart[0]), 0, 1);
    float animMP = constrain((animationTime - animStart[1]) / (animEnd[1] - animStart[1]), 0, 1);
    float animCFP = constrain((animationTime - animStart[2]) / (animEnd[2] - animStart[2]), 0, 1);
    float animLSP = constrain((animationTime - animStart[3]) / (animEnd[3] - animStart[3]), 0, 1);
    float animLFP = constrain((animationTime - animStart[4]) / (animEnd[4] - animStart[4]), 0, 1);
    
    animCSP = (float)(aeaCS == null ? animCSP : (aeaCS.type2 == null ? AriaEasing.getNormalized(animCSP, aeaCS.type1, aeaCS.tension1) : AriaEasing.getNormalized(animCSP, aeaCS.type1, aeaCS.tension1, aeaCS.type2, aeaCS.tension2)));
    animMP = (float)(aeaM == null ? animMP : (aeaM.type2 == null ? AriaEasing.getNormalized(animMP, aeaM.type1, aeaM.tension1) : AriaEasing.getNormalized(animMP, aeaM.type1, aeaM.tension1, aeaM.type2, aeaM.tension2)));
    animCFP = (float)(aeaCF == null ? animCFP : (aeaCF.type2 == null ? AriaEasing.getNormalized(animCFP, aeaCF.type1, aeaCF.tension1) : AriaEasing.getNormalized(animCFP, aeaCF.type1, aeaCF.tension1, aeaCF.type2, aeaCF.tension2)));
    animLSP = (float)(aeaCS == null ? animLSP : (aeaLS.type2 == null ? AriaEasing.getNormalized(animLSP, aeaLS.type1, aeaLS.tension1) : AriaEasing.getNormalized(animLSP, aeaLS.type1, aeaLS.tension1, aeaLS.type2, aeaLS.tension2)));
    animLFP = (float)(aeaLF == null ? animLFP : (aeaLF.type2 == null ? AriaEasing.getNormalized(animLFP, aeaLF.type1, aeaLF.tension1) : AriaEasing.getNormalized(animLFP, aeaLF.type1, aeaLF.tension1, aeaLF.type2, aeaLF.tension2)));
    
    float left = x / 2 - 72.0 / 18.0 * scale;
    float right = x - left;
    float top = y / 2 - scale;
    float bottom = y - top;
    float bw = (right - left) / 72;
    
    if(this.procedureDebug) println("Generating fill templates...");
    PImage bgTemplateCapital = createImage(int(right - left), int(bottom - top), RGB);
    PImage bgTemplateLowercase = createImage(int(right - left), int(bottom - top), RGB);
    bgTemplateCapital.loadPixels();
    bgTemplateLowercase.loadPixels();
    
    for(int xc = 0; xc < bgTemplateCapital.width; xc ++){
      for(int yc = 0; yc < bgTemplateCapital.height; yc ++){
        float percentage = (xc + yc) / float(bgTemplateCapital.width + bgTemplateCapital.height);
        bgTemplateCapital.pixels[xc + yc * bgTemplateCapital.width] = percentage <= animCFP ? lerpColor(this.bgGradLT, this.bgGradRB, percentage) : color(0, 0);
        bgTemplateLowercase.pixels[xc + yc * bgTemplateLowercase.width] = percentage <= animLFP ? lerpColor(this.bgGradLT2, this.bgGradRB2, percentage) : color(0, 0);
      }
    }
    
    bgTemplateCapital.updatePixels();
    bgTemplateLowercase.updatePixels();
    
    float lf = left + (28.5 - 28.5 * animMP) * bw;
    float lu = lf + 5 * bw;
    float lr1 = lf + 10 * bw;
    float lr2 = lf + 15 * bw;
    float ly = lf + 20 * bw;
    float ln = left + (33.5 - 8.5 * animMP) * bw;
    float li = ln + 5 * bw;
    float lg = ln + 7 * bw;
    float lh1 = ln + 12 * bw;
    float lt = ln + 17 * bw;
    float ls = left + (38.5 + 8.5 * animMP) * bw;
    float lh2 = ls + 5 * bw;
    float la = ls + 10 * bw;
    float ld = ls + 15 * bw;
    float le = ls + 20 * bw;
    float lfes = lf + 5 * bw + 19 * bw * animMP;
    float lnes = ln + 5 * bw + 16 * bw * animMP;
    float lses = ls + 5 * bw + 19 * bw * animMP;
    
    if(this.procedureDebug) println("Generating text template...");
    PGraphics strokeText = createGraphics(x, y);
    strokeText.beginDraw();
    strokeText.stroke(this.strokeColor);
    strokeText.noFill();
    strokeText.strokeWeight(this.strokeSize * scale);
    
    this.drawShapeStroke(this.pointsf, strokeText, lf, top, bw, animCSP, "F");
    this.drawShapeStroke(this.pointsu, strokeText, lu, top, bw, animLSP, "u");
    this.drawShapeStroke(this.pointsr, strokeText, lr1, top, bw, animLSP, "r");
    this.drawShapeStroke(this.pointsr, strokeText, lr2, top, bw, animLSP, "r");
    this.drawShapeStroke(this.pointsy, strokeText, ly, top, bw, animLSP, "y");
    this.removeRight(strokeText, lfes);
    this.drawShapeStroke(this.pointsn, strokeText, ln, top, bw, animCSP, "N");
    this.drawShapeStroke(this.pointsi, strokeText, li, top, bw, animLSP, "i");
    this.drawShapeStroke(this.pointsic, strokeText, li, top, bw, animLSP, "i");
    this.drawShapeStroke(this.pointsg, strokeText, lg, top, bw, animLSP, "g");
    this.drawShapeStroke(this.pointsgc, strokeText, lg, top, bw, animLSP, "g");
    this.drawShapeStroke(this.pointsh, strokeText, lh1, top, bw, animLSP, "h");
    this.drawShapeStroke(this.pointst, strokeText, lt, top, bw, animLSP, "t");
    this.removeRight(strokeText, lnes);
    this.drawShapeStroke(this.pointss, strokeText, ls, top, bw, animCSP, "S");
    this.drawShapeStroke(this.pointsh, strokeText, lh2, top, bw, animLSP, "h");
    this.drawShapeStroke(this.pointsa, strokeText, la, top, bw, animLSP, "a");
    this.drawShapeStroke(this.pointsac, strokeText, la, top, bw, animLSP, "a");
    this.drawShapeStroke(this.pointsd, strokeText, ld, top, bw, animLSP, "d");
    this.drawShapeStroke(this.pointsdc, strokeText, ld, top, bw, animLSP, "d");
    this.drawShapeStroke(this.pointse, strokeText, le, top, bw, animLSP, "e");
    this.drawShapeStroke(this.pointsec, strokeText, le, top, bw, animLSP, "e");
    this.removeRight(strokeText, lses);
    
    strokeText.endDraw();
    
    PGraphics fillTemplate = createGraphics(x, y);
    fillTemplate.beginDraw();
    fillTemplate.fill(255);
    fillTemplate.noStroke();
    
    this.drawShapeFill(this.pointsf, null, fillTemplate, lf, top, bw, "F");
    this.drawShapeFill(this.pointsu, null, fillTemplate, lu, top, bw, "u");
    this.drawShapeFill(this.pointsr, null, fillTemplate, lr1, top, bw, "r");
    this.drawShapeFill(this.pointsr, null, fillTemplate, lr2, top, bw, "r");
    this.drawShapeFill(this.pointsy, null, fillTemplate, ly, top, bw, "y");
    this.removeRight(fillTemplate, lfes);
    this.drawShapeFill(this.pointsn, null, fillTemplate, ln, top, bw, "N");
    this.drawShapeFill(this.pointsi, null, fillTemplate, li, top, bw, "i");
    this.drawShapeFill(this.pointsic, null, fillTemplate, li, top, bw, "i");
    this.drawShapeFill(this.pointsg, this.pointsgc, fillTemplate, lg, top, bw, "g");
    this.drawShapeFill(this.pointsh, null, fillTemplate, lh1, top, bw, "h");
    this.drawShapeFill(this.pointst, null, fillTemplate, lt, top, bw, "t");
    this.removeRight(fillTemplate, lnes);
    this.drawShapeFill(this.pointss, null, fillTemplate, ls, top, bw, "S");
    this.drawShapeFill(this.pointsh, null, fillTemplate, lh2, top, bw, "h");
    this.drawShapeFill(this.pointsa, this.pointsac, fillTemplate, la, top, bw, "a");
    this.drawShapeFill(this.pointsd, this.pointsdc, fillTemplate, ld, top, bw, "d");
    this.drawShapeFill(this.pointse, this.pointsec, fillTemplate, le, top, bw, "e");
    this.removeRight(fillTemplate, lses);
    
    fillTemplate.endDraw();
    
    if(this.procedureDebug) println("Generating final PGraphics...");
    PGraphics pg = createGraphics(x, y);
    pg.beginDraw();
    
    pg.loadPixels();
    fillTemplate.loadPixels();
    bgTemplateCapital.loadPixels();
    bgTemplateLowercase.loadPixels();
    for(int xc = 0; xc < bgTemplateCapital.width; xc ++){
      for(int yc = 0; yc < bgTemplateCapital.height; yc ++){
        boolean isAtCapital = false;
        if(left + xc >= lf && left + xc <= lf + 4 * bw) isAtCapital = true;
        else if(left + xc >= ln && left + xc <= ln + 4 * bw) isAtCapital = true;
        else if(left + xc >= ls && left + xc <= ls + 4 * bw) isAtCapital = true;
        
        if(isAtCapital)
          if(fillTemplate.pixels[int(left) + xc + int(top + yc) * fillTemplate.width] == color(255)) pg.pixels[int(left) + xc + int(top + yc) * pg.width] = bgTemplateCapital.pixels[xc + yc * bgTemplateCapital.width];
        if(!isAtCapital)
          if(fillTemplate.pixels[int(left) + xc + int(top + yc) * fillTemplate.width] == color(255)) pg.pixels[int(left) + xc + int(top + yc) * pg.width] = bgTemplateLowercase.pixels[xc + yc * bgTemplateLowercase.width];
      }
    }
    pg.updatePixels();
    fillTemplate.updatePixels();
    bgTemplateCapital.updatePixels();
    bgTemplateLowercase.updatePixels();
    
    pg.imageMode(CORNERS);
    pg.image(strokeText, 0, 0);
    
    pg.endDraw();
    
    if(this.finalDebug) println("Returned PGraphics.");
    return pg;
  }
  
  private void drawShapeStroke(PVector[] pts, PGraphics pg, float x, float y, float bw, float perc, String s){
    if(this.procedureDebug) println("Generating text stroke template for '" + s + "'...");
    
    float length = 0;
    float usedDistance = 0;
    for(int i = 0; i < pts.length; i ++){
      PVector a = pts[i];
      PVector b = pts[(i + 1) % pts.length];
      length += dist(a.x, a.y, b.x, b.y);
    }
    length *= perc;
    
    for(int i = 0; i < pts.length; i ++){
      PVector a = pts[i];
      PVector b = pts[(i + 1) % pts.length];
      float d = dist(a.x, a.y, b.x, b.y);
      float totald = d;
      if(d >= length - usedDistance && perc != 1){
        d = length - usedDistance;
        float dp = d / totald;
        //println(dp + " = " + d + " / " + totald);
        float x1 = x + bw * 9 * a.x;
        float y1 = y + bw * 9 * a.y;
        float x2 = x + bw * 9 * ((b.x - a.x) * dp + a.x);
        float y2 = y + bw * 9 * ((b.y - a.y) * dp + a.y);
        pg.line(x1, y1, x2, y2);
        break;
      }
      else{
        pg.line(x + bw * a.x * 9, y + bw * a.y * 9, x + bw * b.x * 9, y + bw * b.y * 9);
        usedDistance += d;
      }
    }
  }
  
  private void removeRight(PGraphics pg, float x){
    pg.loadPixels();
    for(int xc = int(x); xc < pg.width; xc ++){
      for(int yc = 0; yc < pg.height; yc ++){
        pg.pixels[xc + yc * pg.width] = color(0, 0);
      }
    }
    pg.updatePixels();
  }
  
  private void drawShapeFill(PVector[] pts, PVector[] c, PGraphics pg, float x, float y, float bw, String s){
    if(this.procedureDebug) println("Generating text fill template for '" + s + "'...");
    
    pg.beginShape();
    for(int i = 0; i < pts.length + 1; i ++){
      PVector a = pts[(i + 1) % pts.length];
      
      pg.vertex(x + bw * a.x * 9, y + bw * a.y * 9);
    }
    if(c != null){
      pg.beginContour();
      for(int i = 0; i < c.length + 1; i ++){
        PVector a = c[(i) % c.length];
        
        pg.vertex(x + bw * a.x * 9, y + bw * a.y * 9);
      }
      pg.endContour();
    }
    pg.endShape(CLOSE);
    
  }
}
1 Like