From 186ea5f20489964e50aade27de89c34dcdfedb42 Mon Sep 17 00:00:00 2001 From: onezplpl Date: Sat, 13 Jul 2024 11:18:12 -0400 Subject: [PATCH] perlin noise --- const.h | 33 +++++++++++--- cubes.c | 126 ++++++++++++++++++++++++++++++++++++++------------- cubes.h | 3 +- gen.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gen.h | 5 +++ linmath.h | 3 +- main.c | 39 ++++++++-------- 7 files changed, 279 insertions(+), 61 deletions(-) create mode 100644 gen.c create mode 100644 gen.h diff --git a/const.h b/const.h index 530a739..62368f3 100644 --- a/const.h +++ b/const.h @@ -1,15 +1,25 @@ #ifndef V_CONST_H #define V_CONST_H +#include "linmath.h" typedef struct Vertex { - float pos[3]; -} Vertex; + vec3 pos; +} Vertex; -#define CHUNK_LENGTH 64 //32 -#define CHUNK_RADIUS_H 8 -#define CHUNK_RADIUS_V 4 +typedef struct VertexI { + int pos[3]; +} VertexI; + + +typedef struct Vertex2 { + vec2 pos; +} Vertex2; + + +#define CHUNK_LENGTH 16 +#define CHUNK_RADIUS_H 4//8 +#define CHUNK_RADIUS_V 4 //4 -#define CTRI_ALL BLOCK_ALL * 18 * sizeof(Vertex) #define TEXT_GAP_H 1 / 3.0 #define TEXT_GAP_V 1 / 1.0 @@ -18,5 +28,16 @@ typedef struct Vertex { #define CHUNK_ALL CHUNK_DIAMETER_H *CHUNK_DIAMETER_H *CHUNK_DIAMETER_V #define BLOCK_ALL CHUNK_LENGTH *CHUNK_LENGTH *CHUNK_LENGTH #define CBLOCK_ALL BLOCK_ALL *CHUNK_ALL +#define CBUF_ALL 25 + +#define CTRI_ALL CBLOCK_ALL * 18 * sizeof(Vertex) + +typedef struct Chunk { + unsigned char exists; + unsigned int x; + unsigned int y; + unsigned int z; + unsigned int blocks[BLOCK_ALL]; +} Chunk; #endif \ No newline at end of file diff --git a/cubes.c b/cubes.c index 204b078..dde7969 100644 --- a/cubes.c +++ b/cubes.c @@ -1,28 +1,35 @@ #include "const.h" -//#include -#include +#include "gen.h" +#include +#include -// placeholder function -int cubeExists(int x, int y, int z) { - srand(x ^ y ^ z); - return ((rand() % 3 == 0) && y == 1); -} +struct args { + Vertex *cube; + VertexI pos; + int is_text; + int a; + int i; +}; -void gen_face(Vertex *cube, int i, int x, int y, int z, int j, int is_text) { - Vertex a = {{x, y, z}}; +void gen_face(Vertex *cube, int i, int x, int y, int z, int x2, int y2, int z2, + int j, int is_text, Chunk dat) { + VertexI a = {{x, y, z}}; + Vertex a2 = {{x, y, z}}; if (is_text) { a.pos[i]--; - int exists = - cubeExists(x, y, z) != cubeExists(a.pos[0], a.pos[1], a.pos[2]); - a.pos[0] = exists ? TEXT_GAP_H * i : -1.0; - a.pos[1] = exists ? TEXT_GAP_V * i : -1.0; - a.pos[2] = 0; + int exists = 0; + exists = (cube_exists(x, y, z, dat) != + cube_exists(a.pos[0], a.pos[1], a.pos[2], dat)); + + a2.pos[0] = exists ? TEXT_GAP_H * i : -1.0; + a2.pos[1] = exists ? TEXT_GAP_V * i : -1.0; + a2.pos[2] = 0; } - Vertex b = a; - Vertex c = a; - Vertex d = a; + Vertex b = a2; + Vertex c = a2; + Vertex d = a2; if (is_text) { b.pos[0] += TEXT_GAP_H; @@ -36,7 +43,7 @@ void gen_face(Vertex *cube, int i, int x, int y, int z, int j, int is_text) { d.pos[(i == 2) ? 1 : 2]++; } - cube[j] = a; + cube[j] = a2; cube[j + 1] = b; cube[j + 2] = c; cube[j + 3] = c; @@ -44,24 +51,79 @@ void gen_face(Vertex *cube, int i, int x, int y, int z, int j, int is_text) { cube[j + 5] = d; } -void gen_cubes(Vertex *cube, int x, int y, int z, int is_text) { - int i = 0; - for (int y2 = y; y2 < y + CHUNK_LENGTH; y2++) { - int y3 = y2; - for (int x2 = x; x2 < x + CHUNK_LENGTH; x2++) { - int x3 = x2; - for (int z2 = z; z2 < z + CHUNK_LENGTH; z2++) { - int z3 = z2; +void *gen_chunk(void *args) { + struct args args2 = ((struct args *)args)[0]; - if (is_text) { - x3 = y3 = z3 = 0; - } + int i = args2.i; + int x2 = args2.pos.pos[0]; + int y2 = args2.pos.pos[1]; + int z2 = args2.pos.pos[2]; + Vertex *cube = args2.cube; + int is_text = args2.is_text; + Chunk chunk = + fetch_chunk(x2 / CHUNK_LENGTH, y2 / CHUNK_LENGTH, z2 / CHUNK_LENGTH); - gen_face(cube, 0, x2, y2, z2, i, is_text); - gen_face(cube, 1, x2, y2, z2, i + 6, is_text); - gen_face(cube, 2, x2, y2, z2, i + 12, is_text); + printf("progress on this thread (%i / %i)\n", args2.a, CHUNK_ALL); + + purge_chunks(); + for (int y4 = 0; y4 < CHUNK_LENGTH; y4++) { + + for (int x4 = 0; x4 < CHUNK_LENGTH; x4++) { + + for (int z4 = 0; z4 < CHUNK_LENGTH; z4++) { + int y3 = y2 + y4; + int x3 = x2 + x4; + int z3 = z2 + z4; + + gen_face(cube, 0, x3, y3, z3, x4, y4, z4, i, is_text, chunk); + gen_face(cube, 1, x3, y3, z3, x4, y4, z4, i + 6, is_text, chunk); + gen_face(cube, 2, x3, y3, z3, x4, y4, z4, i + 12, is_text, chunk); i += 18; } } } + return NULL; +} + +void gen_cubes(Vertex *cube, int x, int y, int z, int is_text) { + int i = 0; + int a = 0; + x *= CHUNK_LENGTH; + y *= CHUNK_LENGTH; + z *= CHUNK_LENGTH; + + pthread_t thread_id[24]; + for (int y2 = y - CHUNK_RADIUS_H * CHUNK_LENGTH; + y2 <= y + CHUNK_RADIUS_H * CHUNK_LENGTH; y2 += CHUNK_LENGTH) { + + for (int x2 = x - CHUNK_RADIUS_H * CHUNK_LENGTH; + x2 <= x + CHUNK_RADIUS_H * CHUNK_LENGTH; x2 += CHUNK_LENGTH) { + + for (int z2 = z - CHUNK_RADIUS_V * CHUNK_LENGTH; + z2 <= z + CHUNK_RADIUS_V * CHUNK_LENGTH; z2 += CHUNK_LENGTH) { + + VertexI pos = {{x2, y2, z2}}; + struct args args = {cube, pos, is_text, a, i}; + + gen_chunk((void *)&args); + + i += CHUNK_LENGTH * CHUNK_LENGTH * CHUNK_LENGTH * 18; + + /* buggy + pthread_create(&(thread_id[i]), NULL, gen_chunk, (void *)&args); + + if (i == 23) { + for (int k = 0; k < 24; k++) { + pthread_join((thread_id[k]), NULL); + } + i = 0; + } else { + i++; + } + */ + + a++; + } + } + } } \ No newline at end of file diff --git a/cubes.h b/cubes.h index 9162443..d82f6fb 100644 --- a/cubes.h +++ b/cubes.h @@ -1,3 +1,4 @@ #include "const.h" -void gen_cubes(Vertex *cube, int x, int y, int z, int is_text); \ No newline at end of file +void gen_cubes(Vertex *cube, int x, int y, int z, int is_text); +void gen_face(Vertex *cube, int i, int x, int y, int z, int j, int is_text); \ No newline at end of file diff --git a/gen.c b/gen.c new file mode 100644 index 0000000..8a6bbde --- /dev/null +++ b/gen.c @@ -0,0 +1,131 @@ +#include "const.h" +#include +#include +#include + +Chunk *chunks = NULL; +int lastI = 0; + +double interpolate(double a0, double a1, double w) { + return (a1 - a0) * (3.0 - w * 2.0) * w * w + a0; +} + +int hash_combine(int a, int b) { return b + 0x9e3779b9 + (a << 6) + (a >> 2); } + +Vertex2 perlin_grad(int x, int y) { + srand(x); + int x_hash = rand(); + srand(y); + int y_hash = rand(); + + double random = hash_combine(x_hash, y_hash) * (M_PI / ~(~0u >> 1)); + Vertex2 out = {cos(random), sin(random)}; + return out; +} + +double perlin_dot(double ix, double iy, double x, double y) { + Vertex2 grad = perlin_grad(ix, iy); + + double dx = x - (double)ix; + double dy = y - (double)iy; + return (dx * grad.pos[0] + dy * grad.pos[1]); +} + +double perlin_calc(double x, double y, double s) { + x /= s; + y /= s; + + int x0 = (int)floor(x); + int x1 = x0 + 1; + int y0 = (int)floor(y); + int y1 = y0 + 1; + + float sx = x - (float)x0; + float sy = y - (float)y0; + + float n0, n1, ix0, ix1, value; + + n0 = perlin_dot(x0, y0, x, y); + n1 = perlin_dot(x1, y0, x, y); + ix0 = interpolate(n0, n1, sx); + + n0 = perlin_dot(x0, y1, x, y); + n1 = perlin_dot(x1, y1, x, y); + ix1 = interpolate(n0, n1, sx); + + value = interpolate(ix0, ix1, sy); + + return value; +} + +Chunk fetch_chunk(int x, int y, int z) { + if (chunks == NULL) { + chunks = calloc(CBUF_ALL, sizeof(Chunk)); + } + Chunk chunk; + + int i, j; + for (j = 0; j < CBUF_ALL; j++) { + i = (j + lastI) % CBUF_ALL; + chunk = chunks[i]; + if (chunk.x == x && chunk.y == y && chunk.z == z && chunk.exists) { + // lastI = i; + return chunk; + } + } + + for (j = CBUF_ALL - 1; j >= 0; j--) { + i = j; + chunk = chunks[i]; + if (!chunk.exists) + break; + } + + lastI = i; + + if (i > CBUF_ALL - 1) + i = CBUF_ALL - 1; + + chunk.exists = 1; + chunk.x = x; + chunk.y = y; + chunk.z = z; + + int c = 0; + + for (int x2 = 0; x2 < CHUNK_LENGTH; x2++) { + int x3 = x2 + x * CHUNK_LENGTH; + for (int z2 = 0; z2 < CHUNK_LENGTH; z2++) { + int z3 = z2 + z * CHUNK_LENGTH; + double hp = (perlin_calc(x3, z3, 256.0) * 128.0); + int h = hp + 64; + + for (int y2 = 0; y2 < CHUNK_LENGTH; y2++) { + int y3 = y2 + y * CHUNK_LENGTH; + chunk.blocks[c] = (y3 < h); + c++; + } + } + } + + chunks[i] = chunk; + + return chunk; +} + +void purge_chunks() { + free(chunks); + chunks = calloc(CBUF_ALL, sizeof(Chunk)); +} + +int cube_exists(int x, int y, int z, Chunk dat) { + if (x < 0 || y < 0 || z < 0) return 0; + + if (dat.exists == 0 || dat.x != (x / CHUNK_LENGTH) || dat.y != (y / CHUNK_LENGTH) || dat.z != (z / CHUNK_LENGTH) ) + dat = + fetch_chunk((x / CHUNK_LENGTH), (y / CHUNK_LENGTH), (z / CHUNK_LENGTH)); + int h = dat.blocks[(y % CHUNK_LENGTH) + (z % CHUNK_LENGTH) * CHUNK_LENGTH + + (x % CHUNK_LENGTH) * CHUNK_LENGTH * CHUNK_LENGTH]; + + return h; +} \ No newline at end of file diff --git a/gen.h b/gen.h new file mode 100644 index 0000000..65ff61a --- /dev/null +++ b/gen.h @@ -0,0 +1,5 @@ +#include "const.h" + +int cube_exists(int x, int y, int z, Chunk dat); +Chunk fetch_chunk(int x, int y, int z); +void purge_chunks(); \ No newline at end of file diff --git a/linmath.h b/linmath.h index 50c1dc8..dca11b1 100644 --- a/linmath.h +++ b/linmath.h @@ -1,4 +1,5 @@ -// https://github.com/glfw/glfw/blob/master/deps/linmath.h +// adapted from +// https://github.com/datenwolf/linmath.h #ifndef LINMATH_H #define LINMATH_H diff --git a/main.c b/main.c index d35b88d..7ac82e0 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,3 @@ -// adapted from -// https://github.com/glfw/glfw/blob/master/examples/triangle-opengl.c - #define GLAD_GL_IMPLEMENTATION #include "gl.h" #define GLFW_INCLUDE_NONE @@ -17,26 +14,26 @@ static const char *vertex_shader_text = "#version 330\n" - "layout (location = 0) in vec3 vPos;" - "layout (location = 1) in vec3 vOff;" - "uniform mat4 MVP;\n" - "out vec2 vTex;\n" + "layout (location = 0) in vec3 v_pos;" + "layout (location = 1) in vec3 v_off;" + "uniform mat4 mvp;\n" + "out vec2 v_tex;\n" "void main()\n" "{\n" - " gl_Position = MVP * vec4(vPos, 1.0);\n" - " vTex=vec2(vOff);\n" + " gl_Position = mvp * vec4(v_pos, 1.0);\n" + " v_tex=vec2(v_off);\n" "}\n"; static const char *fragment_shader_text = "#version 330\n" "out vec4 color;\n" - "in vec2 vTex;\n" - "uniform sampler2D texSampler;\n" + "in vec2 v_tex;\n" + "uniform sampler2D sampler_tex;\n" "void main()\n" "{\n" - //" color=vec4(vTex.rg,0.5,0.5);\n" - " if (vTex.x < 0.0 || vTex.y < 0.0) { discard; }\n" - " color=vec4(texture(texSampler, vTex).rgb,0.5);\n" + //" color=vec4(v_tex.rg,0.5,0.5);\n" + " if (v_tex.x < 0.0 || v_tex.y < 0.0) { discard; }\n" + " color=vec4(texture(sampler_tex, v_tex).rgb,0.5);\n" "}\n"; int isCursor = 0; @@ -87,9 +84,8 @@ int main(void) { Vertex *cube = malloc(CTRI_ALL); Vertex *text = malloc(CTRI_ALL); - gen_cubes(cube, 0, 0, 0, 0); - gen_cubes(text, 0, 0, 0, 1); - + gen_cubes(cube, 1024,0,1024, 0); + gen_cubes(text, 1024,0,1024, 1); GLuint vertex_buffer[2]; GLuint vertex_array; @@ -121,8 +117,8 @@ int main(void) { glAttachShader(program, fragment_shader); glLinkProgram(program); - GLint tex_location = glGetUniformLocation(program, "texSampler"); - GLint mvp_location = glGetUniformLocation(program, "MVP"); + GLint tex_location = glGetUniformLocation(program, "sampler_tex"); + GLint mvp_location = glGetUniformLocation(program, "mvp"); unsigned char *pixels; @@ -136,7 +132,7 @@ int main(void) { glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, cursor_position_callback); - vec3 pos = {0, 0, 0}; + vec3 pos = {1024*CHUNK_LENGTH, 0, 1024*CHUNK_LENGTH}; int x = 0, y = 25, z = 0; glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); @@ -195,13 +191,14 @@ int main(void) { glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat *)&mvp); glBindVertexArray(vertex_array); - glDrawArrays(GL_TRIANGLES, 0, BLOCK_ALL * 18); + glDrawArrays(GL_TRIANGLES, 0, CBLOCK_ALL * 18); glfwSwapBuffers(window); glfwPollEvents(); } free(cube); + free(text); glfwDestroyWindow(window);