/* By: ljiriste <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/05 19:35:01 by ljiriste #+# #+# */
-/* Updated: 2024/01/17 10:31:31 by ljiriste ### ########.fr */
+/* Updated: 2024/01/17 14:42:38 by ljiriste ### ########.fr */
/* */
/* ************************************************************************** */
if (keycode == XK_Escape)
close_win(s);
else if (keycode == XK_Up || keycode == XK_w)
- move_view(0, MOVE_AMOUNT, s);
+ move_view(s, 0, MOVE_AMOUNT);
else if (keycode == XK_Left || keycode == XK_a)
- move_view(-MOVE_AMOUNT, 0, s);
+ move_view(s, -MOVE_AMOUNT, 0);
else if (keycode == XK_Down || keycode == XK_s)
- move_view(0, -MOVE_AMOUNT, s);
+ move_view(s, 0, -MOVE_AMOUNT);
else if (keycode == XK_Right || keycode == XK_d)
- move_view(MOVE_AMOUNT, 0, s);
+ move_view(s, MOVE_AMOUNT, 0);
else if (keycode == XK_KP_Add)
- change_zoom(&s->view, (t_vect2){.x = s->img.width / 2, .y = s->img.height / 2}, ZOOM_IN);
+ change_zoom(s, (t_vect2){.x = s->img.width / 2, .y = s->img.height / 2}, ZOOM_IN);
else if (keycode == XK_KP_Subtract)
- change_zoom(&s->view, (t_vect2){.x = s->img.width / 2, .y = s->img.height / 2}, ZOOM_OUT);
+ change_zoom(s, (t_vect2){.x = s->img.width / 2, .y = s->img.height / 2}, ZOOM_OUT);
if (keycode != XK_Escape)
draw_fractal(s);
return (0);
int handle_mouse_press(int button, int x, int y, t_session *s)
{
if (button == Button4)
- change_zoom(&s->view, (t_vect2){.x = x, .y = y}, ZOOM_OUT);
+ change_zoom(s, (t_vect2){.x = x, .y = y}, ZOOM_OUT);
else if (button == Button5)
- change_zoom(&s->view, (t_vect2){.x = x, .y = y}, ZOOM_IN);
+ change_zoom(s, (t_vect2){.x = x, .y = y}, ZOOM_IN);
if (button == Button4 || button == Button5)
draw_fractal(s);
return (0);
*/
int no_event_handle(t_session *s)
{
- if (s->view.resolution < 1)
+ if (s->img.undersample > 1)
{
- s->view.draw_whole = 0;
- s->view.resolution *= 2;
+ --s->img.undersample;
draw_fractal(s);
}
return (0);
/* By: ljiriste <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/27 14:29:26 by ljiriste #+# #+# */
-/* Updated: 2024/01/17 10:29:34 by ljiriste ### ########.fr */
+/* Updated: 2024/01/17 14:49:49 by ljiriste ### ########.fr */
/* */
/* ************************************************************************** */
-#include <X11/X.h>
-#include <X11/keysym.h>
-#include <mlx.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <math.h>
-#include "libft.h"
-#include "fractol.h"
#include "complex.h"
#include "color.h"
#include "vect2.h"
+#include "fractol.h"
+#include "libft.h"
+#include <mlx.h>
+#include <math.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+#include <X11/X.h>
int close_win(t_session *s)
{
return (0);
}
+void *get_pixel(t_img *img, int x, int y)
+{
+ return (img->addr + y * img->bpl + x * img->bpp / CHAR_BIT);
+}
+
void ft_putpx_img(t_img *img, int x, int y, t_color c)
{
char *px_addr;
- px_addr = img->addr + y * img->bpl + x * img->bpp / CHAR_BIT;
+ px_addr = get_pixel(img, x, y);
if (img->endian)
{
px_addr[0] = c.a;
return ;
}
-int is_black(t_img *img, int x, int y)
-{
- char *px_addr;
-
- px_addr = img->addr + y * img->bpl + x * img->bpp / CHAR_BIT;
- return (!(px_addr[0] || px_addr[1] || px_addr[2] || px_addr[3]));
-}
-
-
void free_session(t_session *s)
{
mlx_destroy_display(s->mlx);
return ;
}
-double mandelbrot(double x, double y, double resolution)
+double mandelbrot(double x, double y)
{
const double threshold = 1000;
- const double log2 = log(2);
+ const double detail = 10;
int count;
t_complex c;
t_complex z;
z.i = 0;
if (complex_norm(c) > 4)
return (0.01);
- while (complex_norm(z) < threshold && count < 100 * resolution)
+ while (complex_norm(z) < threshold && count < 100 * detail)
{
z = complex_add(complex_mul(z, z), c);
++count;
}
- if (count == 100 * resolution)
+ if (count == 100 * detail)
return (-1);
- return (fmod((count + 1 - log(log(complex_norm(z)) / log2) / log2) / 100., 1.));
+ return (fmod((count + 1 - log(log(complex_norm(z)) / log(2)) / log(2)) / 100., 1.));
+}
+
+t_color get_img_pixel_color(t_img *img, int x, int y)
+{
+ char *px_addr;
+ t_color c;
+
+ px_addr = get_pixel(img, x, y);
+ if (img->endian)
+ {
+ c.a = px_addr[0];
+ c.r = px_addr[1];
+ c.g = px_addr[2];
+ c.b = px_addr[3];
+ }
+ else
+ {
+ c.a = px_addr[3];
+ c.r = px_addr[2];
+ c.g = px_addr[1];
+ c.b = px_addr[0];
+ }
+ return (c);
}
-int draw_fractal(t_session *s)
+t_color get_color(t_session *s, int x, int y)
+{
+ double palette_param;
+
+ if (!*(bool *)ft_mat_access(&s->img.calced, x, y))
+ {
+ palette_param = s->view.fractal(
+ s->view.window_coord.x + s->view.pixel_size.x * x,
+ s->view.window_coord.y - s->view.pixel_size.y * y);
+ return (s->view.palette(palette_param));
+ }
+ else
+ {
+ return (get_img_pixel_color(&s->img, x, y));
+ }
+}
+
+void process_pixel_group(t_session *s, int x, int y)
+{
+ int i;
+ int j;
+ t_color color;
+
+ color = get_color(s, x, y);
+ i = 0;
+ while (i < s->img.undersample && x + i < s->img.width)
+ {
+ j = 0;
+ while (j < s->img.undersample && y + j < s->img.height)
+ {
+ if (!*(bool *)ft_mat_access(&s->img.calced, x + i, y + j))
+ ft_putpx_img(&s->img, x + i, y + j, color);
+ ++j;
+ }
+ ++i;
+ }
+ *(bool *)ft_mat_access(&s->img.calced, x, y) = 1;
+ return ;
+}
+
+void draw_fractal(t_session *s)
{
int x;
int y;
- double palette_param;
x = 0;
while (x < s->img.width)
y = 0;
while (y < s->img.height)
{
- if(!is_black(&s->img, x, y) && !s->view.draw_whole)
- {
- ++y;
- continue ;
- }
- palette_param = s->view.fractal(
- s->view.window_coord.x + s->view.pixel_size.x * x,
- s->view.window_coord.y - s->view.pixel_size.y * y,
- s->view.resolution);
- ft_putpx_img(&s->img, x, y, s->view.palette(palette_param));
- ++y;
+ process_pixel_group(s, x, y);
+ y += s->img.undersample;
}
- ++x;
+ x += s->img.undersample;
}
mlx_put_image_to_window(s->mlx, s->win, s->img.img, 0, 0);
- return (0);
}
-void change_zoom(t_view *view, t_vect2 invariant, double d_zoom)
+void erase_calced(t_mat *mat)
{
- view->pixel_size.x /= d_zoom;
- view->pixel_size.y /= d_zoom;
- view->window_coord.x += view->pixel_size.x * invariant.x * (d_zoom - 1);
- view->window_coord.y -= view->pixel_size.y * invariant.y * (d_zoom - 1);
- //view->resolution = 1;
- view->draw_whole = 1;
+ size_t i;
+ size_t j;
+
+ i = 0;
+ while (i < mat->rows)
+ {
+ j = 0;
+ while (j < mat->cols)
+ {
+ *(bool *)ft_mat_access(mat, i, j) = false;
+ ++j;
+ }
+ ++i;
+ }
+ return ;
+}
+
+void change_zoom(t_session *s, t_vect2 invariant, double d_zoom)
+{
+ s->view.pixel_size.x /= d_zoom;
+ s->view.pixel_size.y /= d_zoom;
+ s->view.window_coord.x += s->view.pixel_size.x * invariant.x * (d_zoom - 1);
+ s->view.window_coord.y -= s->view.pixel_size.y * invariant.y * (d_zoom - 1);
+ erase_calced(&s->img.calced);
+ s->img.undersample = 2;
return ;
}
// move_amount is ratio of move distance to length one can see
-void move_view(float move_amount_right, float move_amount_up, t_session *s)
+void move_view(t_session *s, float move_amount_right, float move_amount_up)
{
s->view.window_coord.x += move_amount_right * s->img.height * s->view.pixel_size.x;
s->view.window_coord.y += move_amount_up * s->img.height * s->view.pixel_size.y;
- s->view.draw_whole = 1;
+ erase_calced(&s->img.calced);
+ s->img.undersample = 2;
return ;
}
-void init_view(t_session *s)
+// Something like this function should be added to Libft
+// with maybe additional argument (void *) of the filler
+t_arr_stat construct_mat(t_mat *mat, size_t rows, size_t cols)
+{
+ t_vec filler_vec;
+ bool filler;
+ size_t i;
+ t_arr_stat res;
+
+ filler = false;
+ ft_vec_init(&filler_vec, sizeof(bool));
+ i = 0;
+ while (i < cols)
+ {
+ ft_vec_append(&filler_vec, &filler);
+ ++i;
+ }
+ res = ft_mat_insert_row(mat, &filler_vec, rows - 1);
+ ft_vec_free(&filler_vec, NULL);
+ return (res);
+}
+
+static void init_view(t_session *s)
{
s->view.fractal = mandelbrot;
s->view.palette = tri_color;
s->view.pixel_size.y = 0.01;
s->view.window_coord.x = -s->img.width / 2 * s->view.pixel_size.x;
s->view.window_coord.y = s->img.height / 2 * s->view.pixel_size.y;
- s->view.resolution = 10;
- s->view.draw_whole = 1;
return ;
}
+void init_session(t_session *s)
+{
+ s->mlx = mlx_init();
+ s->win = mlx_new_window(s->mlx, s->img.width, s->img.height, "Fract-ol");
+ s->img.img = mlx_new_image(s->mlx, s->img.width, s->img.height);
+ s->img.addr = mlx_get_data_addr(s->img.img, &s->img.bpp, &s->img.bpl, &s->img.endian);
+ ft_mat_init(&s->img.calced, sizeof(bool));
+ construct_mat(&s->img.calced, s->img.height, s->img.width);
+ init_view(s);
+ s->img.undersample = 2;
+}
+
void parse_args(int argc, char **argv, t_session *s)
{
if (argc == 0)
free(argv);
s->img.width = 500;
s->img.height = 500;
- init_view(s);
return ;
}
+void cleanup(t_session *s)
+{
+ ft_mat_free(&s->img.calced, NULL);
+ mlx_destroy_image(s->mlx, s->img.img);
+ free_session(s);
+}
+
int main(int argc, char **argv)
{
t_session s;
parse_args(argc, argv, &s);
- s.mlx = mlx_init();
- s.win = mlx_new_window(s.mlx, s.img.width, s.img.height, "Fract-ol");
- s.img.img = mlx_new_image(s.mlx, s.img.width, s.img.height);
- s.img.addr = mlx_get_data_addr(s.img.img, &s.img.bpp, &s.img.bpl, &s.img.endian);
+ init_session(&s);
mlx_hook(s.win, KeyPress, KeyPressMask, handle_key_press, &s);
mlx_hook(s.win, ButtonPress, ButtonPressMask, handle_mouse_press, &s);
mlx_hook(s.win, DestroyNotify, NoEventMask, close_win, &s);
mlx_loop_hook(s.mlx, no_event_handle, &s);
draw_fractal(&s);
mlx_loop(s.mlx);
- mlx_destroy_image(s.mlx, s.img.img);
- free_session(&s);
+ cleanup(&s);
return (0);
}