summaryrefslogtreecommitdiff
path: root/src/chunk.c
blob: 374162999a215ea6fd191c5fd188148dfc8574ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "chunk.h"
#include "block.h"
#include "cglm/io.h"
#include "cglm/util.h"
#include "cglm/vec2.h"
#include "cglm/vec3.h"
#include "world.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


#define MIN(x, y) (x < y) ? x : y
#define MAX(x, y) (x > y) ? x : y

void _chunk_plains_gen(struct chunk* chunk);

int chunk_gen(struct world* world, vec2 coord, struct chunk **chunk) {
    *chunk = malloc(sizeof(struct chunk));
    memcpy((*chunk)->coord,coord, sizeof(vec2));
    // struct chunk* neighbor_top = { 0 };
    // struct chunk* neighbor_bottom = { 0 };
    // struct chunk* neighbor_left = { 0 };
    // struct chunk* neighbor_right = { 0 };
    // vec2 top = { 0, 1 };
    // vec2 bottom = { 0, -1 };
    // vec2 left = { -1, 0 };
    // vec2 right = { 1, 0 };
    // glm_vec2_add(top, coord, top);
    // glm_vec2_add(bottom, coord, bottom);
    // glm_vec2_add(left, coord, left);
    // glm_vec2_add(right, coord, right);
    // world_get_chunk(world, top, &neighbor_top);
    // world_get_chunk(world, bottom, &neighbor_bottom);
    // world_get_chunk(world, left, &neighbor_left);
    // world_get_chunk(world, right, &neighbor_right);

    // world_get_chunk(world, chunk->coord, &neighbor);
    _chunk_plains_gen(*chunk);
    // switch (chunk->biome) {
    //     case JUNK_BIOME_PLAINS:
    //         _
    //         break;
    //     default:
    //         break;
    // }
    return 0;
}

float _chunk_plains_get_z(vec2 target, vec3 poi, float m, int base_z) {
    vec2 unit = { (target[0] - poi[0]), (target[1] - poi[1]) };
    glm_vec2_normalize(unit);
    // Line direction vector
    vec3 r = { unit[0], unit[1], m };
    // r*t + poi = { x, y, z }, solve first for t, then get z
    float t = 0;
    // Parallel to X-axis
    if (r[0] == 0.0f && r[1] != 0.0f) {
        t = (target[1] - poi[1]) / r[1];
    }
    // Parallel to Y-axis
    else if (r[1] == 0.0f && r[0] != 0.0f) {
        t = (target[0] - poi[0]) / r[0];
    }
    else if (r[0] != 0.0f && r[1] != 0.0f) {
        // Non-parallel line, either X or y works
        t = (target[0] - poi[0]) / r[0];
    }
    else {
        //Else we are POI itself, no need to do anything. t will be zero and
        //the value of z == poi[2]. We subtract -1 from base_z because
        //otherwise the POI will be a single block at it's z, all others will
        //always be strictly less than it. This levels the plains
        base_z -= 1;
    }
    float z_off = poi[2] + t * r[2];

    return MAX(base_z, base_z + z_off);
}

/**
 * Basic Plains chunk generation
 * Algorithm: Pick 2 points of interest (POI). These points will either be elevations or depressions.
 * Each block will get a invisible "offset" value based on their distance from the chosen point.
 * Chosen point height itself will range from some non zero value to another, plus in negative.
 * The offset value determines how block heights are created
 *
 */
void _chunk_plains_gen(struct chunk* chunk) {
    // ============ KNOBS ============
    // Minimum ground
    int z = 2;
    // Min POI block height
    int poi_min = 3;
    // Max POI block height
    int poi_max = 5;
    // Descent/Ascent rate
    float m = -.5;
    memset(chunk->blocks, 0, CHUNK_HEIGHT * CHUNK_LENGTH * CHUNK_WIDTH * sizeof(struct block*));
    // X, Y, POI Height
    vec3 poi1 = { rand() % CHUNK_WIDTH, rand() % CHUNK_LENGTH, poi_min + (rand() % (poi_max - poi_min))};
    vec3 poi2 = { rand() % CHUNK_WIDTH, rand() % CHUNK_LENGTH, -poi_min + (rand() % (poi_max - poi_min))};
    
    for (int x = 0; x < CHUNK_LENGTH; x++) {
        for (int y = 0; y < CHUNK_WIDTH; y++) {
            // Minimum z height
            // Interpolation formula - simple linear
            vec2 target = { x, y };
            float z1 = _chunk_plains_get_z(target, poi1, m, z);
            float z2 = _chunk_plains_get_z(target, poi2, -m, z);
            int z_final = (z1 + z2) / 2;
            for (int h = 0; h < z_final; h++) {
                struct block* blk = malloc(sizeof(struct block));
                // Adjust block coordinates with global chunk coordinates
                vec3 pos = {x + (CHUNK_WIDTH * chunk->coord[0]), h, -y - (CHUNK_LENGTH * chunk->coord[1])};
                block_init(pos, blk);
                chunk->blocks[x][y][h] = blk;
            }
        }
    }
}