#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <helianthus.h>
#include "chunk.h"
static void pregenerate(Chunk *c, int rootSeed, int index) {
c->index = index;
srand(c->index ^ rootSeed);
c->x = c->index*CHUNK_WIDTH;
c->width = CHUNK_WIDTH;
c->dy = (randomFloat()*2 - 1)*CHUNK_HEIGHT;
c->seed = rand();
}
static void generateGround(double *p0, double *p1, double dh) {
double *p = p0 + (p1 - p0)/2;
if (p1 <= p0 || p == p0) return;
*p = (*p0 + *p1)*0.5 + dh*(randomFloat()*2 - 1);
generateGround(p0, p, 0.5*dh);
generateGround(p, p1, 0.5*dh);
}
void chunkGenerate(Chunk *c, int rootSeed, const Chunk *base, int offset) {
if (base == c) return;
memset(c, 0, sizeof(*c));
if (base) {
c->index = base->index;
c->seed = base->seed;
c->dy = base->dy;
c->y = base->y;
} else {
pregenerate(c, rootSeed, 0);
}
while(offset > 0) { c->y += c->dy; pregenerate(c, rootSeed, c->index + 1); --offset; }
while(offset < 0) { pregenerate(c, rootSeed, c->index - 1); c->y -= c->dy; ++offset; }
srand(c->seed);
double *p0 = &c->ground[0];
double *p1 = &c->ground[CHUNK_GROUND_POINTS - 1];
*p0 = 0; *p1 = c->dy;
generateGround(p0, p1, 0.5*CHUNK_HEIGHT);
c->treeCount = randomNumber(0, CHUNK_MAX_TREES);
for(int i = 0; i < c->treeCount; ++i) {
double x = randomFloat()*c->width;
double y = chunkGroundLevel(c, c->x + x) - c->y;
treeGenerate(&c->trees[i], x, y);
}
}
double chunkGroundLevel(const Chunk *c, double x) {
double xp = (x - c->x)/c->width*(CHUNK_GROUND_POINTS-1);
int xi = floor(xp);
if (xi < 0) xi = 0;
if (xi > CHUNK_GROUND_POINTS-2) xi = CHUNK_GROUND_POINTS-2;
xp -= xi;
return c->y + c->ground[xi]*(1 - xp) + c->ground[xi + 1]*xp;
}
void chunkDraw(const Chunk *c, double time, int flags) {
saveState();
translate(c->x, c->y);
if (flags && FLAG_GROUND) {
double step = c->width/(double)(CHUNK_GROUND_POINTS-1);
moveTo(0, c->ground[0]);
for(int i = 1; i < CHUNK_GROUND_POINTS; ++i)
lineTo(i*step, c->ground[i]);
strokePath();
}
if (flags & (FLAG_LEAVES | FLAG_BRANCHES))
for(int i = 0; i < c->treeCount; ++i)
treeDraw(&c->trees[i], time, flags);
restoreState();
}