#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);