Add transparency handling
authorLukas Jiriste <ljiriste@student.42prague.com>
Wed, 3 Apr 2024 20:21:20 +0000 (22:21 +0200)
committerLukas Jiriste <ljiriste@student.42prague.com>
Wed, 3 Apr 2024 20:21:20 +0000 (22:21 +0200)
Unfortunately this makes the program even slower...

solution/main.c

index 3f4c8128204b3a788776ca69182788c82f58e5ab..7695c4e376dd7b1d6ca846a8cce57d7ea2964a0c 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <marvin@42.fr>                    +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2024/04/02 08:44:53 by ljiriste          #+#    #+#             */
-/*   Updated: 2024/04/03 22:18:06 by ljiriste         ###   ########.fr       */
+/*   Updated: 2024/04/03 22:20:56 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <X11/X.h>
 #include <X11/keysym.h>
+#include <limits.h>
 
 #include <stdio.h>
 #include <jpeglib.h>
@@ -64,6 +65,61 @@ void decompress_to_image(struct jpeg_decompress_struct *cinfo,
        return ;
 }
 
+typedef struct s_argb
+{
+       unsigned char   a;
+       unsigned char   r;
+       unsigned char   g;
+       unsigned char   b;
+}                      t_argb;
+
+t_argb uint_to_argb(unsigned int uint_color)
+{
+       t_argb  res;
+
+       res.a = uint_color >> (8 * 3);
+       res.r = uint_color >> (8 * 2);
+       res.g = uint_color >> (8 * 1);
+       res.b = uint_color >> (8 * 0);
+       return (res);
+}
+
+unsigned int   argb_to_uint(t_argb color)
+{
+       unsigned int    res;
+
+       res = 0;
+       res |= color.a << (8 * 3);
+       res |= color.r << (8 * 2);
+       res |= color.g << (8 * 1);
+       res |= color.b << (8 * 0);
+       return (res);
+}
+
+void   flip_alpha(t_mlx_data *img)
+{
+       char    *pixel;
+       int             x;
+       int             y;
+       t_argb  color;
+
+       x = 0;
+       while (x < img->width)
+       {
+               y = 0;
+               while (y < img->height)
+               {
+                       pixel = (char *)img->addr + y * img->line_length + x * img->bits_per_pixel / CHAR_BIT;
+                       color = uint_to_argb(*(unsigned int *)pixel);
+                       color.a = 255 - color.a;
+                       *(unsigned int *)pixel = argb_to_uint(color);
+                       ++y;
+               }
+               ++x;
+       }
+       return ;
+}
+
 //     This function is written as to have
 //     the same signature as mlx_png_file_to_image
 void   *mlx_jpeg_file_to_image(void *mlx_ptr, char *filename,
@@ -92,9 +148,74 @@ void        *mlx_jpeg_file_to_image(void *mlx_ptr, char *filename,
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        fclose(source);
+       flip_alpha(&img);
        return (img.img);
 }
 
+//     This function probably could do the arithmetic in uint form
+//     but this way it is more legible I think
+unsigned int   mix_colors(unsigned int back_uint, unsigned int front_uint)
+{
+       t_argb  back;
+       t_argb  front;
+       t_argb  res;
+
+       back = uint_to_argb(back_uint);
+       front = uint_to_argb(front_uint);
+       res.a = front.a - (255 - back.a) * front.a / 255;
+       res.r = (front.r * (255 - front.a) + back.r * (255 - back.a) * front.a / 255) / (255 - res.a);
+       res.g = (front.g * (255 - front.a) + back.g * (255 - back.a) * front.a / 255) / (255 - res.a);
+       res.b = (front.b * (255 - front.a) + back.b * (255 - back.a) * front.a / 255) / (255 - res.a);
+       return (argb_to_uint(res));
+}
+
+void   copy_image(t_mlx_data *dest, t_mlx_data *src, int x, int y)
+{
+       char    *dest_pix;
+       char    *src_pix;
+       int             i;
+       int             j;
+
+       i = 0;
+       while (i + x < dest->width && i < src->width)
+       {
+               j = 0;
+               while (j + y < dest->height && j < src->height)
+               {
+                       dest_pix = (char *)dest->addr + ((j + y) * dest->line_length + (i + x) * dest->bits_per_pixel / CHAR_BIT);
+                       src_pix = (char *)src->addr + (j * src->line_length + i * src->bits_per_pixel / CHAR_BIT);
+                       *(unsigned int *)dest_pix = mix_colors(*(unsigned int *)dest_pix, *(unsigned int *)src_pix);
+                       ++j;
+               }
+               ++i;
+       }
+       return ;
+}
+
+//     First use has to be with the largest picture, as that initializes the image
+int    mlx_put_image_to_window_transparency(t_mlx_session *s, t_mlx_data *img, int x, int y)
+{
+       static t_mlx_data       to_print;
+
+       if (!s->mlx_win)
+       {
+               mlx_destroy_image(s->mlx, to_print.img);
+               return (0);
+       }
+       if (!to_print.img)
+       {
+               to_print.img = mlx_new_image(s->mlx, img->width, img->height);
+               if (!to_print.img)
+                       return (1);
+               to_print.addr = mlx_get_data_addr(to_print.img, &to_print.bits_per_pixel, &to_print.line_length, &to_print.endian);
+               to_print.width = img->width;
+               to_print.height = img->height;
+       }
+       copy_image(&to_print, img, x, y);
+       mlx_put_image_to_window(s->mlx, s->mlx_win, to_print.img, 0, 0);
+       return (0);
+}
+
 int    mlx_close_win(t_mlx_session *s)
 {
        mlx_destroy_window(s->mlx, s->mlx_win);
@@ -140,12 +261,12 @@ int       no_event_handle(t_graphics *g)
        }
        if (y + g->red_frame.height < g->background.height)
        {
-               mlx_put_image_to_window(g->mlx_ses.mlx, g->mlx_ses.mlx_win, g->background.img, 0, 0);
-               mlx_put_image_to_window(g->mlx_ses.mlx, g->mlx_ses.mlx_win, g->red_frame.img, x, y);
+               mlx_put_image_to_window_transparency(&g->mlx_ses, &g->background, 0, 0);
+               mlx_put_image_to_window_transparency(&g->mlx_ses, &g->red_frame, x, y);
                /*
                if (emoji_encountered(image, emoji, x, y))
                {
-                       mlx_put_image_to_window(s->mlx, s->mlx_win, green_frame, x, y);
+                       mlx_put_image_to_window_transparency(s->mlx, s->mlx_win, green_frame, x, y);
                        record_pos(state, x, y);
                }
                */
@@ -180,7 +301,7 @@ void        display(char **argv)
                mlx_hook(graphics.mlx_ses.mlx_win, DestroyNotify, NoEventMask,
                                mlx_close_win, &graphics.mlx_ses);
                mlx_loop_hook(graphics.mlx_ses.mlx, no_event_handle, &graphics);
-               mlx_put_image_to_window(graphics.mlx_ses.mlx, graphics.mlx_ses.mlx_win, graphics.background.img, 0, 0);
+               mlx_put_image_to_window_transparency(&graphics.mlx_ses, &graphics.background, 0, 0);
                mlx_loop(graphics.mlx_ses.mlx);
        }
        cleanup(&graphics);