summaryrefslogtreecommitdiff
path: root/src/chunk.c
blob: 4918d22222ca6debc258a8c75306d2155cd5bb7c (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include "chunk.h"
#include "block.h"
#include "world.h"
#include "cglm/cglm.h"
#include <stdlib.h>
#include <string.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_WIDTH; x++) {
        for (int y = 0; y < CHUNK_LENGTH; 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, h, -y };
                block_init(pos, blk);
                chunk->blocks[x][y][h] = blk;
            }
        }
    }
    chunk->loaded = 1;
}


// Kind of like the block_update of chunks
void chunk_load(struct chunk *chunk, int coord[2]) {
    vec3 translation = {CHUNK_WIDTH * coord[0], 0, - (CHUNK_LENGTH * coord[1])};
    for (int x = 0; x < CHUNK_WIDTH; x++) {
        for (int y = 0; y < CHUNK_HEIGHT; y++) {
            for (int z = 0; z < CHUNK_LENGTH; z++) {
                struct block* blk = chunk->blocks[x][z][y];
                if (blk != NULL) {
                    // If chunk is unloaded, send block data to GPU
                    if (chunk->loaded == 0) {
                        // Add GPU data
                        block_load_gpu(blk);
                    }
                    // Translate to world coordinates
                    // First do block updates, set the position of the block in local 
                    // chunk coordinates
                    block_update(blk);
                    // Then translate them to world coordinates
                    glm_translate(blk->model, translation);
                }
            }
        }
    }
    if (chunk->loaded == 0) {
        //We've reloaded all data - flip bit again
        chunk->loaded = 1;
    }
}

void chunk_draw(struct chunk* chunk, struct shader* shader) {
    int counter = 0;
    for (int i = 0; i < CHUNK_WIDTH; i++) {
        for (int j = 0; j < CHUNK_LENGTH; j++) {
            for (int k = 0; k < CHUNK_HEIGHT; k++) {
                struct block* blk = chunk->blocks[i][j][k];
                if (blk == NULL) {
                    continue;
                }
                block_draw(blk, shader);
                counter += 1;
            }
        }
    }
}

void chunk_unload(struct chunk* chunk) {
    for (int i = 0; i < CHUNK_WIDTH; i++) {
        for (int j = 0; j < CHUNK_LENGTH; j++) {
            for (int k = 0; k < CHUNK_HEIGHT; k++) {
                struct block* blk = chunk->blocks[i][j][k];
                if (blk == NULL) {
                    continue;
                }
                block_unload(blk);
            }
        }
    }
    chunk->loaded = 0;

}