diff --git a/main.cpp b/main.cpp index 1036056..bf2e827 100644 --- a/main.cpp +++ b/main.cpp @@ -113,6 +113,30 @@ const int SIDEBAR_WIDTH = 200; const int BUTTON_HEIGHT = 60; const int BUTTON_MARGIN = 10; +// Slider UI +struct Slider { + std::string name; + float* value_ptr; + float min_val; + float max_val; + bool is_dragging; +}; + +// Mandelbrot Parameters +float m_exponent = 2.0f; +float m_z_real = 0.0f; +float m_z_imag = 0.0f; +float m_c_real = 0.0f; +float m_c_imag = 0.0f; + +std::vector mandel_sliders = { + {"Exp", &m_exponent, 1.0f, 10.0f, false}, + {"Zr", &m_z_real, -1.0f, 1.0f, false}, + {"Zi", &m_z_imag, -1.0f, 1.0f, false}, + {"Cr", &m_c_real, -1.0f, 1.0f, false}, + {"Ci", &m_c_imag, -1.0f, 1.0f, false} +}; + // Forward declarations void render_frame(); GLuint load_shader_src(const char *source, GLenum type); @@ -332,10 +356,27 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uin cursor_x = wl_fixed_to_double(sx); cursor_y = wl_fixed_to_double(sy); + // Slider Logic + if (shaders[current_shader_index].name == "MANDEL") { + for (auto& s : mandel_sliders) { + if (s.is_dragging) { + // Calculate new value based on X position relative to sidebar + // Lets say slider width is SIDEBAR_WIDTH - 20 + float track_x = 10; + float track_w = SIDEBAR_WIDTH - 20; + float normalized = (float)(cursor_x - track_x) / track_w; + if (normalized < 0.0f) normalized = 0.0f; + if (normalized > 1.0f) normalized = 1.0f; + + *s.value_ptr = s.min_val + normalized * (s.max_val - s.min_val); + return; // Consume input + } + } + } + if (is_dragging) { float dx = (cursor_x - old_x) / height; float dy = (cursor_y - old_y) / height; - // Pan logic view_x -= dx / zoom_level * 2.0; view_y += dy / zoom_level * 2.0; } @@ -345,22 +386,41 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin if (button == 0x110) { // Left click if (state == WL_POINTER_BUTTON_STATE_PRESSED) { if (cursor_x < SIDEBAR_WIDTH) { - int clicked_index = -1; - for (size_t i = 0; i < shaders.size(); ++i) { - int y_start = BUTTON_MARGIN + i * (BUTTON_HEIGHT + BUTTON_MARGIN); - int y_end = y_start + BUTTON_HEIGHT; - if (cursor_y >= y_start && cursor_y <= y_end && cursor_x >= BUTTON_MARGIN && cursor_x <= SIDEBAR_WIDTH - BUTTON_MARGIN) { - clicked_index = i; - break; + // Check Sliders first if Mandelbrot + bool hit_slider = false; + if (shaders[current_shader_index].name == "MANDEL") { + // We need to know where they are drawn. + // Let's assume they are drawn starting at y = 500 (bottom of sidebar?) + // Or right after the buttons? + // We have 7 buttons. 7 * 70 = 490px. + float sy = 490 + 20; + for (auto& s : mandel_sliders) { + if (cursor_y >= sy && cursor_y < sy + 20) { + s.is_dragging = true; + hit_slider = true; + } + sy += 30; // 20 height + 10 margin } } - if (clicked_index != -1) { - current_shader_index = clicked_index; - std::cout << "Switched to shader: " << shaders[current_shader_index].name << std::endl; - if (shaders[current_shader_index].name == "MANDEL") { - zoom_level = 1.0f; - view_x = -0.5f; - view_y = 0.0f; + + if (!hit_slider) { + int clicked_index = -1; + for (size_t i = 0; i < shaders.size(); ++i) { + int y_start = BUTTON_MARGIN + i * (BUTTON_HEIGHT + BUTTON_MARGIN); + int y_end = y_start + BUTTON_HEIGHT; + if (cursor_y >= y_start && cursor_y <= y_end && cursor_x >= BUTTON_MARGIN && cursor_x <= SIDEBAR_WIDTH - BUTTON_MARGIN) { + clicked_index = i; + break; + } + } + if (clicked_index != -1) { + current_shader_index = clicked_index; + // Reset slider drag states just in case + for (auto& s : mandel_sliders) s.is_dragging = false; + + if (shaders[current_shader_index].name == "MANDEL") { + // Keep zoom? Yes. + } } } } else { @@ -368,6 +428,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin } } else { is_dragging = false; + for (auto& s : mandel_sliders) s.is_dragging = false; // Release sliders } } } @@ -491,6 +552,26 @@ void render_frame() { draw_text(shaders[i].name, text_x, text_y, text_scale, 1.0f, 1.0f, 1.0f); } + // Render Sliders if Mandelbrot + if (shaders[current_shader_index].name == "MANDEL") { + float sy = 490 + 20; + for (const auto& s : mandel_sliders) { + // Track + glUseProgram(sidebar_program); + draw_quad(10, sy + 8, SIDEBAR_WIDTH - 20, 4, width, height, 0.3f, 0.3f, 0.3f); + + // Knob + float normalized = (*s.value_ptr - s.min_val) / (s.max_val - s.min_val); + float kx = 10 + normalized * (SIDEBAR_WIDTH - 20); + draw_quad(kx - 5, sy, 10, 20, width, height, 0.8f, 0.8f, 0.8f); + + // Label + draw_text(s.name, 10, sy - 8, 1.0f, 1.0f, 1.0f, 0.0f); // Yellowish + + sy += 30; + } + } + // 3. Render Active Shader int view_w = width - SIDEBAR_WIDTH; int view_h = height; @@ -523,6 +604,16 @@ void render_frame() { GLint centerLoc = glGetUniformLocation(active.program, "u_center"); if (centerLoc != -1) glUniform2f(centerLoc, view_x, view_y); + // Mandelbrot Params + GLint expLoc = glGetUniformLocation(active.program, "u_exponent"); + if (expLoc != -1) glUniform1f(expLoc, m_exponent); + + GLint zStartLoc = glGetUniformLocation(active.program, "u_z_start"); + if (zStartLoc != -1) glUniform2f(zStartLoc, m_z_real, m_z_imag); + + GLint cOffsetLoc = glGetUniformLocation(active.program, "u_c_offset"); + if (cOffsetLoc != -1) glUniform2f(cOffsetLoc, m_c_real, m_c_imag); + if (active.is_stateful) { // Ping-Pong rendering diff --git a/main.o b/main.o index 98038e2..7d82ad4 100644 Binary files a/main.o and b/main.o differ diff --git a/shader-demo b/shader-demo index 5fceda6..68dee4e 100755 Binary files a/shader-demo and b/shader-demo differ diff --git a/shaders/mandelbrot.frag b/shaders/mandelbrot.frag index 0147459..28474d4 100644 --- a/shaders/mandelbrot.frag +++ b/shaders/mandelbrot.frag @@ -6,32 +6,45 @@ uniform vec2 u_resolution; uniform float u_zoom; uniform vec2 u_center; +// Sliders +uniform float u_exponent; +uniform vec2 u_z_start; +uniform vec2 u_c_offset; + void main() { // Current pixel coordinate in 0..1 vec2 st = gl_FragCoord.xy / u_resolution.xy; st.x *= u_resolution.x / u_resolution.y; // Aspect ratio correction - // Map to Mandelbrot space using Zoom and Center - // Default (Zoom 1): -2.5 to 1.5 X, -1.5 to 1.5 Y approx? - // Let's say center is 0,0. Range -2..2. - // st is 0..AspectRatio (approx 0..1.7) - // Center the coords: vec2 c_uv = (gl_FragCoord.xy - u_resolution.xy * 0.5) / u_resolution.y; // Apply Zoom and Pan vec2 c = (c_uv / u_zoom) + u_center; + + // Apply C Offset from sliders (allows Julia-like effects) + c += u_c_offset; - // Mandelbrot iteration - vec2 z = vec2(0.0); + // Initial Z + vec2 z = u_z_start; + float iter = 0.0; - float max_iter = 100.0 + log(u_zoom) * 20.0; // Increase details with zoom + float max_iter = 100.0 + log(u_zoom) * 20.0; for (float i = 0.0; i < 500.0; i++) { if (i > max_iter) break; - // Z = Z^2 + C - float x = (z.x * z.x - z.y * z.y) + c.x; - float y = (z.y * z.x + z.x * z.y) + c.y; + + // Generalized Z^n + // Convert to Polar: r, theta + float r = length(z); + float theta = atan(z.y, z.x); + + // Z^n = r^n * (cos(n*theta) + i*sin(n*theta)) + float rn = pow(r, u_exponent); + float nt = theta * u_exponent; + + float x = rn * cos(nt) + c.x; + float y = rn * sin(nt) + c.y; if ((x * x + y * y) > 4.0) { iter = i; @@ -46,10 +59,11 @@ void main() { if (iter == 0.0) { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); } else { + // More colorful palette gl_FragColor = vec4( - sqrt(t), - t * t, - sin(t * 3.1415), + 0.5 + 0.5 * cos(3.0 + t * 10.0 + u_time), + 0.5 + 0.5 * cos(3.0 + t * 10.0 + 2.0), + 0.5 + 0.5 * cos(3.0 + t * 10.0 + 4.0), 1.0 ); }