-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmesh.cpp
More file actions
201 lines (166 loc) · 6.73 KB
/
Copy pathmesh.cpp
File metadata and controls
201 lines (166 loc) · 6.73 KB
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include "mesh.h"
#ifdef __APPLE__
#define GL_SILENCE_DEPRECATION
#include <GLUT/glut.h>
#else
#include "GL/glut.h"
#endif
#include <iostream>
#include <random>
#include <cmath>
#include <utility>
#include "PerlinNoise/PerlinNoise.hpp"
#define LAKE_DEPRESSION 20.0
#define RIVER_DEPRESSION 10.0
/* Helper functions */
// 2D Gaussian function
float gaussian2D(int x, int z, int c_x, int c_z, float height, float var_x, float var_z) {
float exponent = -(powf(x - c_x, 2.0)/var_x + powf(z - c_z, 2.0)/var_z);
return height * expf(exponent);
}
// Dot product
float dot(std::pair<float, float> v, std::pair<float, float> w) {
return (v.first * w.first) + (v.second * w.second);
}
// Distance between two points
float dist(std::pair<float, float> v, std::pair<float, float> w) {
std::pair<float, float> diff(v.first - w.first, v.second - w.second);
return sqrtf(dot(diff, diff));
}
// Returns distance between point and line segment
// p - point, s0 - segment point 0, s1 - segment point 1
// Referenced from https://geomalgorithms.com/a02-_lines.html
float distanceFromSegment(int p_x, int p_z, int s0_x, int s0_z, int s1_x, int s1_z) {
std::pair<float, float> p(p_x, p_z);
std::pair<float, float> s0(s0_x, s0_z);
std::pair<float, float> s1(s1_x, s1_z);
std::pair<float, float> v(s1.first - s0.first, s1.second - s0.second);
std::pair<float, float> w(p.first - s0.first, p.first - s0.first);
float c1 = dot(v, w);
if (c1 <= 0)
return dist(p, s0);
float c2 = dot(v, v);
if (c2 <= c1)
return dist(p, s1);
float b = c1 / c2;
std::pair<float, float> pb(s0.first + (b * v.first), s0.second + (b * v.second));
return dist(p, pb);
}
/* Mesh methods */
Mesh::Mesh(int dimX, int dimZ, uint32_t s, float maxh, float offset, float freq, int octaves)
: worldDimX(dimX), worldDimZ(dimZ), seed(s), max_height(maxh), offset(offset),
perlin_freq(freq), perlin_octaves(octaves) {
// Init heightmap
// () initializes to 0
hmap = new float[worldDimX * worldDimZ]();
}
Mesh::~Mesh() {
delete[] hmap;
delete[] verts;
delete[] indicies;
}
void Mesh::generateGaussianHeightMap() {
/* Generate terrain */
std::srand(std::time(nullptr));
std::default_random_engine generator;
std::normal_distribution<float> distribution(2.0,0.25);
for (int z = 0; z < worldDimZ; z++) {
for (int x = 0; x < worldDimX; x++) {
hmap[(z * worldDimX) + x] = distribution(generator);
}
}
}
void Mesh::generateHeightMap() {
/* Generate terrain */
siv::BasicPerlinNoise<float> perlin(seed);
float fx = worldDimX / perlin_freq;
float fz = worldDimZ / perlin_freq;
for (std::int32_t z = 0; z < worldDimZ; z++) {
for (std::int32_t x = 0; x < worldDimX; x++) {
// TODO: Introduce clamp
// float r = perlin.accumulatedOctaveNoise2D_0_1(x / fx, z / fz, perlin_octaves);
float r = perlin.accumulatedOctaveNoise2D_0_1(x / fx, z / fz, perlin_octaves);
// += as it builds upon encourager's height values
hmap[(z * worldDimX) + x] += (r * max_height) - (max_height / 2.0);
}
}
}
void Mesh::generateMesh() {
// Procedural generation
// generateGaussianHeightMap();
generateHeightMap();
/* Calculate plane verticies + indicies */
// 3 coordinates for every vertex/point in tilemap
vertsSize = 3 * (worldDimX + 1) * (worldDimZ + 1);
verts = new float[vertsSize * sizeof(float)];
// 2 triangles * 3 verts/tri * num tiles
indiciesSize = 2 * 3 * worldDimX * worldDimZ;
indicies = new GLushort[indiciesSize * sizeof(GLushort)];
// Calculate verticies (+ 1 for tiles -> verticies)
int w = 0;
for (int z = 0; z < (worldDimZ + 1); z++) {
for (int x = 0; x < (worldDimX + 1); x++) {
// 3 coordinates per vertex
int base = 3 * ((z * (worldDimX + 1)) + x);
verts[base + 0] = x;
verts[base + 1] = hmap[(z * worldDimX) + x] + offset;
// verts[base + 1] = 0.0;
verts[base + 2] = z;
}
}
// Calculate indicies (2 tris per tile)
// std::cout << "Indicies:" << std::endl;
for (int z = 0; z < worldDimZ; z++) {
for (int x = 0; x < worldDimX; x++) {
/*
* |2 /|
* | / |
* |/ 1|
*/
// 6 indicies stored per tile
int base = 2 * 3 * ((z * worldDimX) + x);
// (worldDimX + 1) for tiles -> verticies
// Triangle 1 (0,0), (0,1), (1,1)
indicies[base + 0] = (z * (worldDimX + 1)) + x;
indicies[base + 1] = (z * (worldDimX + 1)) + (x + 1);
indicies[base + 2] = ((z + 1) * (worldDimX + 1)) + (x + 1);
// Triangle 2 (0,0), (1,0), (1,1)
indicies[base + 3] = (z * (worldDimX + 1)) + x;
indicies[base + 4] = ((z + 1) * (worldDimX + 1)) + x;
indicies[base + 5] = ((z + 1) * (worldDimX + 1)) + (x + 1);
// std::cout << "(" << x << ", " << z << "):" << base << "\t(" << (int)indicies[base] << ", " << (int)indicies[base + 1] << ", " << (int)indicies[base + 2] << ") (" << (int)indicies[base + 3] << ", " << (int)indicies[base + 4] << ", " << (int)indicies[base + 5] << ")" << std::endl;
}
}
}
void Mesh::encourageMountain(int c_x, int c_z, float height, float width) {
for (int z = 0; z < worldDimZ; z++) {
for (int x = 0; x < worldDimX; x++) {
// Apply gaussian curve to heightmap
// += as it builds upon other encourager's/perlin noise height values
hmap[(z * worldDimX) + x] += gaussian2D(x, z, c_x, c_z, height, width, width);
}
}
}
void Mesh::encourageLake(int c_x, int c_z, float width) {
for (int z = 0; z < worldDimZ; z++) {
for (int x = 0; x < worldDimX; x++) {
// Apply negative gaussian curve to heightmap
// += as it builds upon other encourager's/perlin noise height values
hmap[(z * worldDimX) + x] += gaussian2D(x, z, c_x, c_z, -LAKE_DEPRESSION, width, width);
}
}
}
void Mesh::encourageRiver(int x0, int z0, int x1, int z1) {
std::cout << "test: " << distanceFromSegment(0, 10, 0, 0, 50, 50) << std::endl;
for (int z = 0; z < worldDimZ; z++) {
for (int x = 0; x < worldDimX; x++) {
// Apply distance function of every point to line segment (river)
// += as it builds upon other encourager's/perlin noise height values
float d = distanceFromSegment(x, z, x0, z0, x1, z1);
if (d < 0.2)
hmap[(z * worldDimX) + x] += -(RIVER_DEPRESSION);
else
hmap[(z * worldDimX) + x] += -(RIVER_DEPRESSION)/powf(d, 2.0);
}
}
}