diff --git a/forest/chunk.c b/forest/chunk.c new file mode 100644 index 0000000..4875a2b --- /dev/null +++ b/forest/chunk.c @@ -0,0 +1,89 @@ + +#include +#include +#include + +#include + +#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(); +} + diff --git a/forest/chunk.h b/forest/chunk.h new file mode 100644 index 0000000..6bb4cb4 --- /dev/null +++ b/forest/chunk.h @@ -0,0 +1,35 @@ +#ifndef CHUNK_H +#define CHUNK_H + + +#include "common.h" +#include "tree.h" + + +#define CHUNK_WIDTH 10 +#define CHUNK_HEIGHT 2 +#define CHUNK_GROUND_SUBDIVISIONS 3 +#define CHUNK_GROUND_POINTS ((1 << CHUNK_GROUND_SUBDIVISIONS) + 1) +#define CHUNK_MAX_TREES 1 + + +typedef struct { + int index; + int seed; + + double x, y; + double width; + double dy; + double ground[CHUNK_GROUND_POINTS]; + + int treeCount; + Tree trees[CHUNK_MAX_TREES]; +} Chunk; + + +void chunkGenerate(Chunk *c, int rootSeed, const Chunk *base, int offset); +double chunkGroundLevel(const Chunk *c, double x); +void chunkDraw(const Chunk *c, double time, int flags); + + +#endif diff --git a/forest/common.h b/forest/common.h new file mode 100644 index 0000000..d7565ba --- /dev/null +++ b/forest/common.h @@ -0,0 +1,10 @@ +#ifndef COMMON_H +#define COMMON_H + + +#define FLAG_GROUND 1 +#define FLAG_LEAVES 2 +#define FLAG_BRANCHES 4 + + +#endif diff --git a/forest/main.c b/forest/main.c index 52cf90b..7954881 100644 --- a/forest/main.c +++ b/forest/main.c @@ -1,42 +1,121 @@ +#include +#include +#include +#include + #include -#include "tree.h" +#include "chunk.h" + + +#define COUNT 100 + +double t; +double x, y; +double vx = 100, vy = 0; + +int rootSeed; + +Chunk chunks[COUNT]; + + +void initChunks() { + srand(time(NULL)); + rootSeed = rand(); + Chunk *c = &chunks[0]; + chunkGenerate(c, rootSeed, NULL, -COUNT/2); + for(int i = 1; i < COUNT; ++i, ++c) + chunkGenerate(c+1, rootSeed, c, 1); +} + +void prepareChunks(double x) { + Chunk *first = chunks, *last = first + COUNT - 1; + int i0 = (int)floor(x/CHUNK_WIDTH) - COUNT/2; + int offset = i0 - chunks[0].index; + + if (offset < 0) { + Chunk *next = last, *prev = first; + if (offset > -COUNT) { + memmove(first - offset, first, sizeof(*chunks)*(COUNT + offset)); + prev = first - offset; + next = prev - 1; + offset = 1; + } + while(next >= first) + { chunkGenerate(next, rootSeed, prev, offset); prev = next--; offset = -1; } + } else + if (offset > 0) { + Chunk *next = first, *prev = last; + if (offset < COUNT) { + memmove(first, first + offset, sizeof(*chunks)*(COUNT - offset)); + prev = last - offset; + next = prev + 1; + offset = 1; + } else { + offset -= COUNT - 1; + } + while(next <= last) + { chunkGenerate(next, rootSeed, prev, offset); prev = next++; offset = 1; } + } +} -#define COUNT 10 -double time; -Tree trees[COUNT]; +void drawChunks(double x, double range, double t) { + range += 5*2; + int i0 = (int)floor((x - 0.5*range)/CHUNK_WIDTH) - chunks->index; + int i1 = (int)floor((x + 0.5*range)/CHUNK_WIDTH) - chunks->index + 1; + if (i0 < 0) i0 = 0; + if (i1 > COUNT) i1 = COUNT; + + for(int i = i0; i < i1; ++i) chunkDraw(&chunks[i], t, FLAG_GROUND); + //for(int i = i0; i < i1; ++i) chunkDraw(&chunks[i], t, FLAG_LEAVES); + for(int i = i0; i < i1; ++i) chunkDraw(&chunks[i], t, FLAG_BRANCHES); +} -void generate() { - for(int i = 0; i < COUNT; ++i) - treeGenerate(&trees[i]); +double groundLevel(double x) { + int i = (int)floor(x/CHUNK_WIDTH) - chunks->index; + if (i < 0) return chunks->y; + if (i > COUNT-1) return chunks[COUNT-1].y + chunks[COUNT-1].dy; + return chunkGroundLevel(&chunks[i], x); } void init() { - generate(); + initChunks(); } void draw() { - time += worldGetFrameTime(); + double dt = worldGetFrameTime(); + t += dt; int w = worldGetWidth(); int h = worldGetHeight(); + double range = w; + + double gy = groundLevel(x); + vy = 0.5*(gy - y + 20); + x += dt*vx; + y += dt*vy; + - if (keyWentDown("space")) generate(); + if (keyWentDown("space")) initChunks(); + if (keyWentDown("right")) x += 10; + if (keyWentDown("left")) x -= 10; + if (keyWentDown("up")) y += 10; + if (keyWentDown("down")) y -= 10; saveState(); translate(0.5*w, 0.5*h); zoom(10); scale(1, -1); + translate(-x, -y); + range /= 10; - for(int i = 0; i < COUNT; ++i) - treeDraw(&trees[i], time, TRUE, FALSE); - for(int i = 0; i < COUNT; ++i) - treeDraw(&trees[i], time, FALSE, TRUE); + prepareChunks(x); + drawChunks(x, range, t); restoreState(); } diff --git a/forest/tree.c b/forest/tree.c index 8339fd9..3e68e2b 100644 --- a/forest/tree.c +++ b/forest/tree.c @@ -12,7 +12,7 @@ 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.1; +static const double branchesPerSegment = 0.05; 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 @@ -86,28 +86,28 @@ static void branch(double x, double y, double angle, double width, double time) } -void treeGenerate(Tree *t) { +void treeGenerate(Tree *t, double x, double y) { memset(t, 0, sizeof(*t)); t->seed = rand(); - t->x = randomIncrement(20); - t->y = randomIncrement(20); + 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 leafs, int branches) { +void treeDraw(const Tree *t, double time, int flags) { saveState(); translate(t->x, t->y); - if (leafs) { + if (flags & FLAG_LEAVES) { fill(colorByName("green")); noStroke(); srand(t->seed); branch(0, 0, t->angle, t->width, time); } - if (branches) { + if (flags & FLAG_BRANCHES) { noFill(); stroke(colorByName("black")); srand(t->seed); diff --git a/forest/tree.h b/forest/tree.h index 00e96e5..2aa57bc 100644 --- a/forest/tree.h +++ b/forest/tree.h @@ -2,6 +2,9 @@ #define TREE_H +#include "common.h" + + typedef struct { int seed; double x, y; @@ -10,8 +13,8 @@ typedef struct { } Tree; -void treeGenerate(Tree *t); -void treeDraw(const Tree *t, double time, int leafs, int branches); +void treeGenerate(Tree *t, double x, double y); +void treeDraw(const Tree *t, double time, int flags); #endif