you can fuck with the mandelbrot
This commit is contained in:
121
main.cpp
121
main.cpp
@@ -113,6 +113,30 @@ const int SIDEBAR_WIDTH = 200;
|
|||||||
const int BUTTON_HEIGHT = 60;
|
const int BUTTON_HEIGHT = 60;
|
||||||
const int BUTTON_MARGIN = 10;
|
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<Slider> 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
|
// Forward declarations
|
||||||
void render_frame();
|
void render_frame();
|
||||||
GLuint load_shader_src(const char *source, GLenum type);
|
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_x = wl_fixed_to_double(sx);
|
||||||
cursor_y = wl_fixed_to_double(sy);
|
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) {
|
if (is_dragging) {
|
||||||
float dx = (cursor_x - old_x) / height;
|
float dx = (cursor_x - old_x) / height;
|
||||||
float dy = (cursor_y - old_y) / height;
|
float dy = (cursor_y - old_y) / height;
|
||||||
// Pan logic
|
|
||||||
view_x -= dx / zoom_level * 2.0;
|
view_x -= dx / zoom_level * 2.0;
|
||||||
view_y += dy / 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 (button == 0x110) { // Left click
|
||||||
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
if (cursor_x < SIDEBAR_WIDTH) {
|
if (cursor_x < SIDEBAR_WIDTH) {
|
||||||
int clicked_index = -1;
|
// Check Sliders first if Mandelbrot
|
||||||
for (size_t i = 0; i < shaders.size(); ++i) {
|
bool hit_slider = false;
|
||||||
int y_start = BUTTON_MARGIN + i * (BUTTON_HEIGHT + BUTTON_MARGIN);
|
if (shaders[current_shader_index].name == "MANDEL") {
|
||||||
int y_end = y_start + BUTTON_HEIGHT;
|
// We need to know where they are drawn.
|
||||||
if (cursor_y >= y_start && cursor_y <= y_end && cursor_x >= BUTTON_MARGIN && cursor_x <= SIDEBAR_WIDTH - BUTTON_MARGIN) {
|
// Let's assume they are drawn starting at y = 500 (bottom of sidebar?)
|
||||||
clicked_index = i;
|
// Or right after the buttons?
|
||||||
break;
|
// 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;
|
if (!hit_slider) {
|
||||||
std::cout << "Switched to shader: " << shaders[current_shader_index].name << std::endl;
|
int clicked_index = -1;
|
||||||
if (shaders[current_shader_index].name == "MANDEL") {
|
for (size_t i = 0; i < shaders.size(); ++i) {
|
||||||
zoom_level = 1.0f;
|
int y_start = BUTTON_MARGIN + i * (BUTTON_HEIGHT + BUTTON_MARGIN);
|
||||||
view_x = -0.5f;
|
int y_end = y_start + BUTTON_HEIGHT;
|
||||||
view_y = 0.0f;
|
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 {
|
} else {
|
||||||
@@ -368,6 +428,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
is_dragging = false;
|
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);
|
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
|
// 3. Render Active Shader
|
||||||
int view_w = width - SIDEBAR_WIDTH;
|
int view_w = width - SIDEBAR_WIDTH;
|
||||||
int view_h = height;
|
int view_h = height;
|
||||||
@@ -523,6 +604,16 @@ void render_frame() {
|
|||||||
GLint centerLoc = glGetUniformLocation(active.program, "u_center");
|
GLint centerLoc = glGetUniformLocation(active.program, "u_center");
|
||||||
if (centerLoc != -1) glUniform2f(centerLoc, view_x, view_y);
|
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) {
|
if (active.is_stateful) {
|
||||||
// Ping-Pong rendering
|
// Ping-Pong rendering
|
||||||
|
|
||||||
|
|||||||
BIN
shader-demo
BIN
shader-demo
Binary file not shown.
@@ -6,32 +6,45 @@ uniform vec2 u_resolution;
|
|||||||
uniform float u_zoom;
|
uniform float u_zoom;
|
||||||
uniform vec2 u_center;
|
uniform vec2 u_center;
|
||||||
|
|
||||||
|
// Sliders
|
||||||
|
uniform float u_exponent;
|
||||||
|
uniform vec2 u_z_start;
|
||||||
|
uniform vec2 u_c_offset;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Current pixel coordinate in 0..1
|
// Current pixel coordinate in 0..1
|
||||||
vec2 st = gl_FragCoord.xy / u_resolution.xy;
|
vec2 st = gl_FragCoord.xy / u_resolution.xy;
|
||||||
st.x *= u_resolution.x / u_resolution.y; // Aspect ratio correction
|
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:
|
// Center the coords:
|
||||||
vec2 c_uv = (gl_FragCoord.xy - u_resolution.xy * 0.5) / u_resolution.y;
|
vec2 c_uv = (gl_FragCoord.xy - u_resolution.xy * 0.5) / u_resolution.y;
|
||||||
|
|
||||||
// Apply Zoom and Pan
|
// Apply Zoom and Pan
|
||||||
vec2 c = (c_uv / u_zoom) + u_center;
|
vec2 c = (c_uv / u_zoom) + u_center;
|
||||||
|
|
||||||
// Mandelbrot iteration
|
// Apply C Offset from sliders (allows Julia-like effects)
|
||||||
vec2 z = vec2(0.0);
|
c += u_c_offset;
|
||||||
|
|
||||||
|
// Initial Z
|
||||||
|
vec2 z = u_z_start;
|
||||||
|
|
||||||
float iter = 0.0;
|
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++) {
|
for (float i = 0.0; i < 500.0; i++) {
|
||||||
if (i > max_iter) break;
|
if (i > max_iter) break;
|
||||||
// Z = Z^2 + C
|
|
||||||
float x = (z.x * z.x - z.y * z.y) + c.x;
|
// Generalized Z^n
|
||||||
float y = (z.y * z.x + z.x * z.y) + c.y;
|
// 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) {
|
if ((x * x + y * y) > 4.0) {
|
||||||
iter = i;
|
iter = i;
|
||||||
@@ -46,10 +59,11 @@ void main() {
|
|||||||
if (iter == 0.0) {
|
if (iter == 0.0) {
|
||||||
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
} else {
|
} else {
|
||||||
|
// More colorful palette
|
||||||
gl_FragColor = vec4(
|
gl_FragColor = vec4(
|
||||||
sqrt(t),
|
0.5 + 0.5 * cos(3.0 + t * 10.0 + u_time),
|
||||||
t * t,
|
0.5 + 0.5 * cos(3.0 + t * 10.0 + 2.0),
|
||||||
sin(t * 3.1415),
|
0.5 + 0.5 * cos(3.0 + t * 10.0 + 4.0),
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user