diff --git a/RASTER b/RASTER index c8e0a14..8b78b84 100755 Binary files a/RASTER and b/RASTER differ diff --git a/build/.cmake/api/v1/reply/index-2025-09-25T19-41-55-0596.json b/build/.cmake/api/v1/reply/index-2025-09-29T19-16-12-0602.json similarity index 100% rename from build/.cmake/api/v1/reply/index-2025-09-25T19-41-55-0596.json rename to build/.cmake/api/v1/reply/index-2025-09-29T19-16-12-0602.json diff --git a/build/CMakeFiles/RASTER.dir/source/main.cpp.o b/build/CMakeFiles/RASTER.dir/source/main.cpp.o index fab1ad4..67e8e92 100644 Binary files a/build/CMakeFiles/RASTER.dir/source/main.cpp.o and b/build/CMakeFiles/RASTER.dir/source/main.cpp.o differ diff --git a/build/bin/RASTER b/build/bin/RASTER index c8e0a14..8b78b84 100755 Binary files a/build/bin/RASTER and b/build/bin/RASTER differ diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl index 1f34b29..c34be17 100644 --- a/shaders/fragment.glsl +++ b/shaders/fragment.glsl @@ -6,10 +6,10 @@ precision mediump float; out vec4 FragColor; // Output to screen -uniform vec2 u_resolution; // <-- screen resolution from CPU -uniform float u_time; // <-- time from CPU -uniform float u_oscilator; // <-- oscislator from CPU -uniform float u_direction; // <-- direction from CPU +uniform vec2 u_resolution; // <-- screen resolution from CPU +uniform float u_time; // <-- time from CPU +uniform float u_scale; // <-- scale from CPU +uniform vec2 u_mouse; // <-- mouse from CPU vec3 hsv2rgb(vec3 c) { vec3 rgb = clamp( @@ -25,14 +25,10 @@ vec3 getPaletteColor(float idx, float seed) { float baseHue = fract(seed); // 0..1 base hue float sat = 0.9; float val = 0.9; - - // Shift hue across palette (idx ensures difference) float hue = fract(baseHue + (idx * 0.33)); - return hsv2rgb(vec3(hue, sat, val)); } - vec2 random(vec2 p) { return normalize(vec2( fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453), @@ -40,27 +36,20 @@ vec2 random(vec2 p) { ) * 2.0 - 1.0); } -int randomInt(int x, int y) { - return int(fract(sin(float(x * 12 + y * 78)) * 43758.5453) * 256.0); -} - float perlinNoise(vec2 st) { vec2 i = floor(st); vec2 f = fract(st); - // Corners vec2 g00 = random(i + vec2(0.0,0.0)); vec2 g10 = random(i + vec2(1.0,0.0)); vec2 g01 = random(i + vec2(0.0,1.0)); vec2 g11 = random(i + vec2(1.0,1.0)); - // Offsets float n00 = dot(g00, f - vec2(0.0,0.0)); float n10 = dot(g10, f - vec2(1.0,0.0)); float n01 = dot(g01, f - vec2(0.0,1.0)); float n11 = dot(g11, f - vec2(1.0,1.0)); - // Interpolation vec2 u = f*f*(3.0-2.0*f); return mix(mix(n00, n10, u.x), mix(n01, n11, u.x), u.y); } @@ -70,30 +59,103 @@ mat2 rotate2d(float angle){ sin(angle),cos(angle)); } -void main() { +vec2 morphingSeed(float t, float interval) { + float phase = floor(t / interval); + float blend = fract(t / interval); - vec2 st = gl_FragCoord.xy / u_resolution; // Normalize coordinates - st += 13.0 + (u_oscilator * 0.001); // Center the coordinates + vec2 seedA = vec2( + sin(phase * 12.9898), + cos(phase * 78.233) + ); + vec2 seedB = vec2( + sin((phase+1.0) * 12.9898), + cos((phase+1.0) * 78.233) + ); - vec2 pos = st * (2.2); - - pos = rotate2d(perlinNoise(pos)) * pos; - pos -= (u_time * (float(u_oscilator) * 0.5) * 0.1); - - float n = perlinNoise(pos); - vec3 color; - - if (n > 0.4) { - color = vec3((n + 0.4), (n + 0.4), (n + 0.4)); - // color = getPaletteColor(u_oscilator, (n + 0.5)); - } else if (n > 0.1) { - color = vec3(n + 0.5, n + 0.1 , 0.0); - // color = getPaletteColor(u_oscilator + 1, (n + 0.5)); - } else { - color = vec3(n + 0.05, n + 0.05, n + 0.05); - // color = getPaletteColor(u_oscilator + 2, (n + 0.5)); - // color = vec3(0.0); - } - FragColor = vec4(color, 1.0); + blend = smoothstep(0.0, 1.0, blend); + return mix(seedA, seedB, blend); } +vec2 morphingDirection(float t, float interval) { + float phase = floor(t / interval); + float blend = fract(t / interval); + + // Generate 2 pseudo-random direction vectors + vec2 dirA = normalize(vec2( + sin(phase * 12.9898), + cos(phase * 78.233) + )); + vec2 dirB = normalize(vec2( + sin((phase+1.0) * 93.9898), + cos((phase+1.0) * 47.233) + )); + + // Smooth interpolation between them + blend = smoothstep(0.0, 1.0, blend); + return normalize(mix(dirA, dirB, blend)); +} + +void main() { + vec2 st = gl_FragCoord.xy / u_resolution.xy; // Normalize coordinates + st.x *= u_resolution.x / u_resolution.y; // Correct aspect ratio + st -= 0.5; // Center coordinates + st += vec2(100.0,40.0); + + st *= 2.05 * u_scale; // Zoom out + vec2 seed = morphingSeed(u_time, 10.0); // 10 second interval + + vec2 pos = st + morphingDirection(u_time * 0.2, 15.0); // 15 second interval + + float pre_noise = perlinNoise((pos) * 1.5); // N = [0..1] + // noise += 0.6 * perlinNoise(pos * 4.0); + + pos += rotate2d(pre_noise) * pos * 0.2; + pos += u_time * 0.5; + + float noise = perlinNoise(pos + seed * 2.0); + // noise = smoothstep(0.0, 1.0, noise); // Smooth the noise + + // Normalize noise to [0..1] + noise = noise + 0.5; + + vec3 color; + + if (noise >= 0.9) { + color = getPaletteColor(u_time * 0.1, noise); + } else if (noise >= 0.76 ) { + color = getPaletteColor((u_time * 0.1) + 1.0, noise); + + // Estimate gradient (2D normal) + vec2 eps = vec2(0.002, 0.0); + float n0 = perlinNoise(pos + seed * 2.0); + float nx = perlinNoise(pos + seed * 2.0 + eps.xy) - n0; + float ny = perlinNoise(pos + seed * 2.0 + eps.yx) - n0; + vec2 normal = normalize(vec2(nx, ny)); + + // View direction (from pixel to "camera") + vec2 viewDir = normalize(-st); + + // Light direction (moves over time) + vec2 lightDir = normalize(vec2(cos(u_time * 0.2), sin(u_time * 0.3))); + + // Fresnel term (stronger highlight at grazing angles) + float fresnel = pow(1.0 - max(dot(viewDir, normal), 0.0), 3.0); + + // Specular component + float spec = pow(max(dot(normal, lightDir), 0.0), 32.0); + + // Combine Fresnel + spec + float gloss = fresnel + 0.5 * spec; + + // Stronger at edges (transition zone of blob) + float edge = smoothstep(0.8, 0.9, noise) * (1.0 - smoothstep(0.9, 1.0, noise)); + gloss *= edge * 2.0; + + // Add colored glossy highlight (slightly bluish tint) + color += gloss * vec3(0.8, 0.9, 1.0); + } else { + color = vec3(0.0); + } + + FragColor = vec4(color, 1.0); +} diff --git a/source/main.cpp b/source/main.cpp index ad1b6fc..c9a55e9 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -106,9 +106,9 @@ int main() { glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // REQUIRED on macOS glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_SAMPLES, 16); // 16x MSAA + glfwWindowHint(GLFW_SAMPLES, 8); // 8x MSAA - GLFWwindow* window = glfwCreateWindow((int)SCR_WIDTH, (int)SCR_HEIGHT, "OpenGL Template", nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow((int)SCR_WIDTH, (int)SCR_HEIGHT, "RASTER", nullptr, nullptr); if (!window) { glfwTerminate(); return -1; @@ -196,44 +196,89 @@ int main() { glUniform2f(resLoc, SCR_WIDTH, SCR_HEIGHT); // hardcode for now GLint timeLoc = glGetUniformLocation(shaderProgram, "u_time"); - GLint directionLoc = glGetUniformLocation(shaderProgram, "u_direction"); - GLint oscilationLoc = glGetUniformLocation(shaderProgram, "u_oscilator"); + GLint scaleLoc = glGetUniformLocation(shaderProgram, "u_scale"); + GLint mouseLoc = glGetUniformLocation(shaderProgram, "u_mouse"); glEnable(GL_MULTISAMPLE); - float oscillation = 5.0f; + float scale = 1.0f; + int frameCount = 0; + float mousePos[2] = {0.0f, 0.0f}; + + + // FPS tracking + double lastTime = glfwGetTime(); // when we last printed FPS + double fps = 0.0; + // Render loop while (!glfwWindowShouldClose(window)) { - static float direction = 1.0f; - static int frameCount = 0; - static unsigned char invert = 0; float timeValue = (float)glfwGetTime(); + double xpos, ypos; + // Get mouse positions + glfwGetCursorPos(window, &xpos, &ypos); + mousePos[0] = (float)xpos; + mousePos[1] = (float)(SCR_HEIGHT - ypos); // Invert y-axis for OpenGL coordinates // Input glfwPollEvents(); - if (frameCount++ % 24 == 0) { - if (oscillation > 40) invert = 1; - if (oscillation < 5) invert = 0; + if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) { + glDeleteProgram(shaderProgram); + shaderProgram = createShaderProgram(VERTEX_FILE, FRAGMENT_FILE); + modelLoc = (unsigned int) glGetUniformLocation(shaderProgram, "model"); + viewLoc = (unsigned int) glGetUniformLocation(shaderProgram, "view"); + projLoc = (unsigned int) glGetUniformLocation(shaderProgram, "projection"); - if (invert) oscillation -= 0.01f; - else oscillation += 0.001f; + glUseProgram(shaderProgram); + glUniformMatrix4fv((int) modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv((int) viewLoc, 1, GL_FALSE, glm::value_ptr(view)); + glUniformMatrix4fv((int) projLoc, 1, GL_FALSE, glm::value_ptr(projection)); - // Debug - // std::cout << "Oscillation: " << oscillation << "\t"; - // std::cout << "Invert: " << invert << std::endl; + resLoc = glGetUniformLocation(shaderProgram, "u_resolution"); + glUniform2f(resLoc, SCR_WIDTH, SCR_HEIGHT); // hardcode for now - direction = rand() % 50; // change direction every 300 frames + timeLoc = glGetUniformLocation(shaderProgram, "u_time"); + scaleLoc = glGetUniformLocation(shaderProgram, "u_scale"); + + std::cout << "Shaders recompiled!\n"; + } + + // Scroll to zoom in/out + if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { + scale += 0.01f; + if (scale > 10.0f) scale = 10.0f; // Max zoom + } + + if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { + scale -= 0.01f; + if (scale < 0.1f) scale = 0.1f; // Min zoom + } + + // --- FPS Counter --- + double currentTime = glfwGetTime(); + double delta = currentTime - lastTime; + + if (delta >= 1.0) { // print every ~1 second + fps = double(frameCount) / delta; + std::cout << "FPS: " << fps + << " Time: " << timeValue + << " Scale: " << scale + << " Mouse: (" << mousePos[0] << ", " << mousePos[1] << ")" + << std::endl; + + frameCount = 0; + lastTime = currentTime; } glUniform1f(timeLoc, timeValue); - glUniform1f(directionLoc, direction); - glUniform1f(oscilationLoc, oscillation); + glUniform1f(scaleLoc, scale); + glUniform2f(mouseLoc, mousePos[0], mousePos[1]); + frameCount++; - glClearColor(0.01f, 0.01f, 0.01f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);