]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/server/terrain_gen.c
b258b1d2208f73ad32120c76c54f1388393e8564
[dragonblocks_alpha.git] / src / server / terrain_gen.c
1 #include <math.h>
2 #include <stdlib.h>
3 #include "environment.h"
4 #include "perlin.h"
5 #include "server/biomes.h"
6 #include "server/server_terrain.h"
7 #include "server/terrain_gen.h"
8 #include "server/trees.h"
9
10 s32 terrain_gen_get_base_height(v2s32 pos)
11 {
12         return 1.0
13                 * (pnoise2d(U32(pos.x) /  32.0, U32(pos.y) /  32.0, 0.45, 5, seed + OFFSET_HEIGHT)    * 16.0 + 0.0)
14                 * (pnoise2d(U32(pos.x) / 256.0, U32(pos.y) / 256.0, 0.45, 5, seed + OFFSET_HILLYNESS) *  0.5 + 0.5)
15                 + 32.0;
16 }
17
18 // generate a chunk (does not manage chunk state or threading)
19 void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks)
20 {
21         TerrainChunkMeta *meta = chunk->extra;
22
23         BiomeArgsChunk chunk_args;
24         BiomeArgsRow row_args;
25         BiomeArgsHeight height_args;
26         BiomeArgsGenerate generate_args;
27         TreeArgsCondition condition_args;
28
29         chunk_args.chunk = condition_args.chunk = chunk;
30         chunk_args.changed_chunks = generate_args.changed_chunks = changed_chunks;
31
32         v3s32 chunkp = {
33                 chunk->pos.x * CHUNK_SIZE,
34                 chunk->pos.y * CHUNK_SIZE,
35                 chunk->pos.z * CHUNK_SIZE,
36         };
37
38         unsigned char *chunk_data[COUNT_BIOME] = {NULL};
39         bool has_biome[COUNT_BIOME] = {false};
40
41         for (s32 x = 0; x < CHUNK_SIZE; x++) {
42                 s32 pos_x = chunkp.x + x;
43
44                 for (s32 z = 0; z < CHUNK_SIZE; z++) {
45                         row_args.pos = height_args.pos = (v2s32) {pos_x, chunkp.z + z};
46
47                         condition_args.biome = get_biome(row_args.pos, &condition_args.factor);
48                         BiomeDef *biome_def = &biomes[condition_args.biome];
49
50                         height_args.factor = generate_args.factor = row_args.factor
51                                 = condition_args.factor;
52
53                         if (biome_def->chunk_data_size && !chunk_data[condition_args.biome])
54                                 chunk_data[condition_args.biome] = malloc(biome_def->chunk_data_size);
55
56                         chunk_args.chunk_data = row_args.chunk_data = height_args.chunk_data =
57                                 generate_args.chunk_data = condition_args.chunk_data =
58                                 chunk_data[condition_args.biome];
59
60                         if (!has_biome[condition_args.biome]) {
61                                 if (biome_def->before_chunk)
62                                         biome_def->before_chunk(&chunk_args);
63
64                                 has_biome[condition_args.biome] = true;
65                         }
66
67                         unsigned char row_data[biome_def->row_data_size];
68                         row_args.row_data = height_args.row_data = generate_args.row_data =
69                                 condition_args.row_data = row_data;
70
71                         if (biome_def->before_row)
72                                 biome_def->before_row(&row_args);
73
74                         height_args.height = terrain_gen_get_base_height(height_args.pos);
75                         s32 height = biome_def->height(&height_args);
76
77                         for (s32 y = 0; y < CHUNK_SIZE; y++) {
78                                 generate_args.offset = (v3s32) {x, y, z};
79
80                                 generate_args.pos = condition_args.pos = (v3s32)
81                                         {row_args.pos.x, chunkp.y + y, row_args.pos.y};
82                                 generate_args.diff = generate_args.pos.y - height;
83
84                                 generate_args.humidity = condition_args.humidity =
85                                         get_humidity(generate_args.pos);
86                                 generate_args.temperature = condition_args.temperature =
87                                         get_temperature(generate_args.pos);
88
89                                 NodeType node = biome_def->generate(&generate_args);
90
91                                 if (biome_def->snow
92                                                 && generate_args.diff <= 1
93                                                 && generate_args.temperature < 0.0
94                                                 && node == NODE_AIR)
95                                         node = NODE_SNOW;
96
97                                 if (generate_args.diff == 1) for (int i = 0; i < NUM_TREES; i++) {
98                                         TreeDef *def = &tree_definitions[i];
99
100                                         if (def->condition(&condition_args)
101                                                         && noise2d(condition_args.pos.x, condition_args.pos.z, 0, seed + def->offset) * 0.5 + 0.5 < def->probability
102                                                         && smooth2d(U32(condition_args.pos.x) / def->spread, U32(condition_args.pos.z) / def->spread, 0, seed + def->area_offset) * 0.5 + 0.5 < def->area_probability) {
103                                                 def->generate(condition_args.pos, changed_chunks);
104                                                 break;
105                                         }
106                                 }
107
108                                 pthread_mutex_lock(&chunk->mtx);
109                                 if (meta->tgsb.raw.nodes[x][y][z] <= STAGE_TERRAIN) {
110                                         chunk->data[x][y][z] = terrain_node_create(node, (Blob) {0, NULL});
111                                         meta->tgsb.raw.nodes[x][y][z] = STAGE_TERRAIN;
112                                 }
113                                 pthread_mutex_unlock(&chunk->mtx);
114                         }
115
116                         if (biome_def->after_row)
117                                 biome_def->after_row(&row_args);
118                 }
119         }
120
121         for (Biome i = 0; i < COUNT_BIOME; i++) {
122                 if (has_biome[i]) {
123                         chunk_args.chunk_data = chunk_data[i];
124
125                         if (biomes[i].after_chunk)
126                                 biomes[i].after_chunk(&chunk_args);
127
128                         if (chunk_args.chunk_data)
129                                 free(chunk_args.chunk_data);
130                 }
131         }
132 }