#include #include #include #include #include #include #include #define WIDTH 800 #define HEIGHT 800 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 int seed = 1; static float nextSeededFloat(unsigned int x, unsigned int y) { unsigned int s = y + ((x + y) * (x + y + 1)) / 2; s ^= s * (x + seed) * 534492383u; s ^= s * (y + seed) * 23537u; return s / (float)(-1u); } static float interpolate(float a, float b, float f) { return (b - a) * (3.0 - f * 2.0) * f * f + a; } static float dot(int ix, int iy, float x, float y, float zoom) { float f = nextSeededFloat(ix % (int)(WIDTH / zoom), iy % (int)(HEIGHT / zoom)) * M_PI * 2.0f; return (x - ix) * cosf(f) + (y - iy) * sinf(f); } float perlin(float x, float y, float zoom) { x /= zoom; y /= zoom; int ix = x; int iy = y; int ix1 = ix + 1; int iy1 = iy + 1; float sx = x - ix; return interpolate( interpolate(dot(ix, iy, x, y, zoom), dot(ix1, iy, x, y, zoom), sx), interpolate(dot(ix, iy1, x, y, zoom), dot(ix1, iy1, x, y, zoom), sx), y - iy); } float transform(float x, float y, float zoom) { return (perlin(x, y, zoom) + 1.0f) * 0.5f; } float turbulence(int x, int y) { float sum = transform(x, y, 80.0f); sum += transform(x, y, 200.0f); sum += transform(x, y, 400.0f); return sum / 3.0f; } 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] = turbulence(x, y); } } normalize(); (void)normalize; } 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, HEIGHT, WIDTH, 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; } int i = 0; while(!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, texture); if(i++ == 100) { seed++; i = 0; generateNoise(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, HEIGHT, WIDTH, 0, GL_RED, GL_FLOAT, noise); } 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; }