Kajetan Johannes Hammerle 6 months ago
commit
69ac7938e4
2 changed files with 258 additions and 0 deletions
  1. 246 0
      Main.c
  2. 12 0
      meson.build

+ 246 - 0
Main.c

@@ -0,0 +1,246 @@
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WIDTH 400
+#define HEIGHT 400
+
+static const GLchar* vertexShaderCode = "#version 430\n"
+                                        "layout(location = 0) in vec2 pos;"
+                                        ""
+                                        "out vec2 varTex;"
+                                        ""
+                                        "void main(void) {"
+                                        "    varTex = (pos + 1.0) * 0.5;"
+                                        "    gl_Position = vec4(pos, 0.0, 1.0);"
+                                        "}";
+
+static const GLchar* fragmentShaderCode =
+    "#version 430\n"
+    ""
+    "layout(binding = 0) uniform sampler2D samp;"
+    ""
+    "const vec4 heightColors[5] = {"
+    "    vec4(0.0, 0.0, 0.7, 1.0),"
+    "    vec4(0.0, 0.0, 1.0, 1.0),"
+    "    vec4(0.0, 1.0, 0.0, 1.0),"
+    "    vec4(0.6, 0.3, 0.0, 1.0),"
+    "    vec4(0.3, 0.3, 0.3, 1.0),"
+    "};"
+    ""
+    "in vec2 varTex;"
+    ""
+    "out vec4 color;"
+    ""
+    "void main(void) {"
+    "    float f = texture(samp, varTex).r;"
+    "    //color = vec4(f, f, f, 1.0);\n"
+    "    //color = heightColors[min(int(5 * f), 4)];\n"
+    "    int a = int(min(floor(5 * f), 4));"
+    "    int b = int(min(ceil(5 * f), 4));"
+    "    color = mix(heightColors[a], heightColors[b], 5 * f - a);\n"
+    "}";
+
+static GLFWwindow* window = NULL;
+static GLuint vertexShader = 0;
+static GLuint fragmentShader = 0;
+static GLuint program = 0;
+static GLuint vertexArray = 0;
+static GLuint vertexBuffer = 0;
+static GLuint texture = 0;
+static GLfloat noise[WIDTH][HEIGHT];
+static unsigned long long seed = 0;
+
+static float nextFloat() {
+    seed = seed * 534492383lu + 31;
+    return (unsigned int)(seed >> 16) / (float)(-1u);
+}
+
+static void smooth(int size) {
+    float divider = 1.0f / (size * size);
+    static GLfloat newNoise[WIDTH][HEIGHT];
+    for(int x = 0; x < WIDTH; x++) {
+        for(int y = 0; y < HEIGHT; y++) {
+            float sum = 0.0f;
+            for(int mx = 0; mx < size; mx++) {
+                for(int my = 0; my < size; my++) {
+                    sum += noise[(x + mx) % WIDTH][(y + my) % HEIGHT];
+                }
+            }
+            newNoise[x][y] = sum * divider;
+        }
+    }
+    memcpy(noise, newNoise, sizeof(newNoise));
+}
+
+static void normalize() {
+    float min = noise[0][0];
+    float max = noise[0][0];
+    for(int x = 0; x < WIDTH; x++) {
+        for(int y = 0; y < HEIGHT; y++) {
+            min = (min < noise[x][y] ? min : noise[x][y]);
+            max = (max > noise[x][y] ? max : noise[x][y]);
+        }
+    }
+    float divider = 1.0f / (max - min);
+    for(int x = 0; x < WIDTH; x++) {
+        for(int y = 0; y < HEIGHT; y++) {
+            noise[x][y] = (noise[x][y] - min) * divider;
+        }
+    }
+}
+
+static void generateNoise() {
+    for(int x = 0; x < WIDTH; x++) {
+        for(int y = 0; y < HEIGHT; y++) {
+            noise[x][y] = nextFloat();
+        }
+    }
+    smooth(2);
+    smooth(4);
+    smooth(8);
+    smooth(16);
+    smooth(32);
+    smooth(64);
+    normalize();
+
+    (void)normalize;
+    (void)smooth;
+}
+
+static bool checkShaderError(GLuint shader, const char* name) {
+    GLint status;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+    if(!status) {
+        printf("cannot compile %s shader:\n", name);
+        GLchar error[256];
+        glGetShaderInfoLog(shader, 256, NULL, error);
+        puts(error);
+        return true;
+    }
+    return false;
+}
+
+static bool initShaders() {
+    vertexShader = glCreateShader(GL_VERTEX_SHADER);
+    glShaderSource(vertexShader, 1, &vertexShaderCode, NULL);
+    glCompileShader(vertexShader);
+    if(checkShaderError(vertexShader, "vertex")) {
+        return true;
+    }
+    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL);
+    glCompileShader(fragmentShader);
+    if(checkShaderError(fragmentShader, "fragment")) {
+        return true;
+    }
+
+    program = glCreateProgram();
+    glAttachShader(program, vertexShader);
+    glAttachShader(program, fragmentShader);
+    glLinkProgram(program);
+
+    GLint linked;
+    glGetProgramiv(program, GL_LINK_STATUS, &linked);
+    if(!linked) {
+        puts("cannot link program:");
+        GLchar error[256];
+        glGetProgramInfoLog(program, 256, NULL, error);
+        puts(error);
+        return true;
+    }
+    glUseProgram(program);
+    return false;
+}
+
+static void initVertexBuffer() {
+    glGenVertexArrays(1, &vertexArray);
+    glBindVertexArray(vertexArray);
+
+    glGenBuffers(1, &vertexBuffer);
+    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+
+    glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(GLfloat) * 2, NULL);
+    glEnableVertexAttribArray(0);
+
+    GLfloat data[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
+                      1.0f,  1.0f,  -1.0f, 1.0f, 1.0f, -1.0f};
+    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+}
+
+static void initTexture() {
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    generateNoise();
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, WIDTH, HEIGHT, 0, GL_RED, GL_FLOAT,
+                 noise);
+}
+
+static bool init() {
+    if(glewInit() != GLEW_OK) {
+        puts("cannot init glew");
+        return true;
+    }
+    if(initShaders()) {
+        return true;
+    }
+    initVertexBuffer();
+    initTexture();
+    return false;
+}
+
+static bool createWindow() {
+    glfwWindowHint(GLFW_RESIZABLE, false);
+    window = glfwCreateWindow(WIDTH, HEIGHT, "Noise", NULL, NULL);
+    if(window == NULL) {
+        puts("cannot create window");
+        return true;
+    }
+    glfwMakeContextCurrent(window);
+    return false;
+}
+
+static void cleanUp() {
+    glDeleteBuffers(1, &vertexBuffer);
+    glDeleteVertexArrays(1, &vertexArray);
+    glDeleteTextures(1, &texture);
+    glDeleteShader(vertexShader);
+    glDeleteShader(fragmentShader);
+    glDeleteProgram(program);
+    if(window != NULL) {
+        glfwDestroyWindow(window);
+    }
+    glfwTerminate();
+}
+
+static void start() {
+    if(createWindow() || init()) {
+        return;
+    }
+    while(!glfwWindowShouldClose(window)) {
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        glBindTexture(GL_TEXTURE_2D, texture);
+        glActiveTexture(GL_TEXTURE0);
+        glBindVertexArray(vertexArray);
+        glDrawArrays(GL_TRIANGLES, 0, 6);
+
+        glfwSwapBuffers(window);
+        glfwPollEvents();
+    }
+}
+
+int main() {
+    if(!glfwInit()) {
+        puts("glfw init error");
+        return 0;
+    }
+    start();
+    cleanUp();
+    return 0;
+}

+ 12 - 0
meson.build

@@ -0,0 +1,12 @@
+project('noise', 'c')
+
+glew_dep = dependency('glew')
+glfw_dep = dependency('glfw3')
+
+cc = meson.get_compiler('c')
+math_dep = cc.find_library('m', required : true)
+
+executable('noise', 
+    sources: ['Main.c'],
+    dependencies : [glew_dep, glfw_dep, math_dep],
+    c_args: ['-Wall', '-Wextra', '-pedantic', '-Werror'])