Blob Blame Raw

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