#include "mandelbrot.h" #include #include #include #include #include #include #include #include #include #include #include #include extern int points[WINDOW_WIDTH * WINDOW_HEIGHT]; int main(void) { if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) { fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); return -1; } SDL_Window* window = SDL_CreateWindow(WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_HIDDEN); if (window == NULL) { fprintf(stderr, "CreateWindow failed: %s\n", SDL_GetError()); SDL_Quit(); return -1; } SDL_Surface* surface = SDL_GetWindowSurface(window); if (!surface) { fprintf(stderr, "GetWindowSurface failed: %s\n", SDL_GetError()); SDL_DestroyWindow(window); SDL_Quit(); return -1; } SDL_Renderer* renderer = SDL_CreateSoftwareRenderer(surface); if (renderer == NULL) { fprintf(stderr, "CreateSoftwareRenderer failed: %s\n", SDL_GetError()); SDL_DestroyWindow(window); SDL_Quit(); return -1; } SDL_Event e; bool running = true; SDL_ShowWindow(window); position_t position; position.x_min = -2.0; position.x_max = 1.0; position.y_min = -1.2; position.y_max = 1.2; bool pos_updated = true; char debug_text[256] = ""; bool is_dragging = false; float drag_start_x, drag_start_y; double drag_start_x_min, drag_start_x_max; double drag_start_y_min, drag_start_y_max; while (running) { while (SDL_PollEvent(&e)) { if (e.type == SDL_EVENT_QUIT) { running = false; } if (e.type == SDL_EVENT_MOUSE_WHEEL) { float mx, my; SDL_GetMouseState(&mx, &my); double cr = position.x_min + (position.x_max - position.x_min) * mx / (WINDOW_WIDTH - 1); double ci = position.y_min + (position.y_max - position.y_min) * my / (WINDOW_HEIGHT - 1); double range_y = position.y_max - position.y_min; float factor = (e.wheel.y > 0) ? 0.9f : 1.1f; double new_height = range_y * factor; double aspect = (double)WINDOW_WIDTH / WINDOW_HEIGHT; double new_width = new_height * aspect; position.x_min = cr - (double)mx / (WINDOW_WIDTH - 1) * new_width; position.x_max = position.x_min + new_width; position.y_min = ci - (double)my / (WINDOW_HEIGHT - 1) * new_height; position.y_max = position.y_min + new_height; pos_updated = true; } if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { if (e.button.button == SDL_BUTTON_LEFT) { is_dragging = true; drag_start_x = (float)e.button.x; drag_start_y = (float)e.button.y; // store current view drag_start_x_min = position.x_min; drag_start_x_max = position.x_max; drag_start_y_min = position.y_min; drag_start_y_max = position.y_max; } float mx, my; SDL_GetMouseState(&mx, &my); double cr = position.x_min + (position.x_max - position.x_min) * mx / (WINDOW_WIDTH - 1); double ci = position.y_min + (position.y_max - position.y_min) * my / (WINDOW_HEIGHT - 1); int iter; double zr, zi; mandelbrot_at_point(cr, ci, &iter, &zr, &zi); snprintf(debug_text, sizeof(debug_text), "c = %.6f %+.6fi | z = %.6f %+.6fi | iteration %d", cr, ci, zr, zi, iter); } if (e.type == SDL_EVENT_MOUSE_MOTION) { if (is_dragging) { float mx = (float)e.motion.x; float my = (float)e.motion.y; double dx = mx - drag_start_x; double dy = my - drag_start_y; double view_width = drag_start_x_max - drag_start_x_min; double view_height = drag_start_y_max - drag_start_y_min; // Pan: shift the view opposite to mouse movement double x_shift = dx * view_width / (WINDOW_WIDTH - 1); double y_shift = dy * view_height / (WINDOW_HEIGHT - 1); position.x_min = drag_start_x_min - x_shift; position.x_max = drag_start_x_max - x_shift; position.y_min = drag_start_y_min - y_shift; position.y_max = drag_start_y_max - y_shift; pos_updated = true; } } if (e.type == SDL_EVENT_MOUSE_BUTTON_UP) { if (e.button.button == SDL_BUTTON_LEFT) { is_dragging = false; } } } if (pos_updated) { calculate_points(&position); pos_updated = false; } draw_points(surface); if (debug_text[0] != '\0') { SDL_SetRenderDrawColor(renderer, 64, 224, 208, 255); SDL_RenderDebugText(renderer, 10, 10, debug_text); } SDL_RenderPresent(renderer); SDL_UpdateWindowSurface(window); SDL_Delay(16); } SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }