Blob Blame Raw

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <helianthus.h>

#include "tree.h"


static const double segmentLength = 0.2;
static const double segmentWidth = 0.004;
static const double minWidth = 0.02;
static const double rootWidth = 0.8;
static const double branchesPerSegment = 0.2;
static const double leafSize = 8;
static const double leafPerBranch = 1;
static const double leafThreshold = 0.02 + 8/4/0.2*0.004; // minWidth + leafSize/4/segmentLength*segmentWidth


static double randomRange(double min, double max)
  { return randomFloat()*(max - min) + min; }

static double randomIncrement(double deviation)
  { return randomRange(-deviation, deviation); }

static double randomAmplifier(double deviation)
  { return randomRange(1 - deviation, 1 + deviation); }


static void leaf(double x, double y, double size) {
  double r = 0.5*size;//*randomAmplifier(0.5);
  saveState();
  noStroke();
  circle(x, y, r);
  restoreState();
}


static void branch(double x, double y, double angle, double width, double time, int flags) {
  double da = sin(time*randomRange(0.5, 1) + randomIncrement(PI));

  saveState();
  while(TRUE) {
    double length = segmentLength * randomAmplifier(0.1);

    double s = sin(angle/180*PI);
    double c = cos(angle/180*PI);
    double nx = x + c*length;
    double ny = y + s*length;
    double nw = width - segmentWidth;
    strokeWidth(width);
    line(x, y, nx, ny);

    if (width > leafThreshold && nw <= leafThreshold && randomFloat() < leafPerBranch && y > leafSize/2) {
      double dl = randomRange(0, length);
      leaf(x + c*dl, y + s*dl, leafSize);
    }

    if (width < minWidth || ny < 0)
      break;

    x = nx;
    y = ny;
    s += randomRange(0, 0.2);
    c += randomIncrement(0.15);
    angle = atan2(s, c)/PI*180;
    width -= segmentWidth;

    translate(x, y);
    rotate(da*pow(minWidth/width, 2));
    translate(-x, -y);

    if (randomFloat() < branchesPerSegment) {
      double k = randomRange(0, 0.3);
      double w = sqrt(width*width*k);
      if (w > minWidth) {
        width = sqrt(width*width*(1-k));
        double a = randomNumber(0, 1) ? angle - 90 + randomRange(0, 45)
                                      : angle + 90 - randomRange(0, 45);
        branch(x, y, a, w, time, flags);
      }
    }
  }
  restoreState();
}


void treeGenerate(Tree *t, double x, double y) {
  memset(t, 0, sizeof(*t));
  t->seed = rand();
  t->x = x;
  t->y = y;
  t->angle = 90 + randomIncrement(30);
  t->width = rootWidth*randomAmplifier(0.5);
}


void treeDraw(const Tree *t, double time, int flags) {
  saveState();
  translate(t->x, t->y);
  
  fill(colorByRGBA(0, 0.5, 0, 0.5));
  stroke(COLOR_BLACK);
  srand(t->seed);
  branch(0, 0, t->angle, t->width, time, flags);
  
  restoreState();
}


void treePrerender(Tree *t, Framebuffer fb) {
  srand(t->seed);
  branch(0, 0, t->angle, t->width, 0, FLAG_BOUNDS);
}


void treeDrawPrerendered(Tree *t);