#include #include #include #include #include #include #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; }