/*
core.c
The tool with multiple enhancements and manipulations of pictures
-13.11.2022
+14.11.2022
Copyright (C) 2014, 2015, 2022 Balthasar Szczepański
return r;
}
+int perform_action (
+ uint_fast16_t n,
+ uint_fast16_t *id,
+ ILint *x0, ILint *y0, *ILint f0, ILint width, ILint height, ILint frames,
+ ACTION_F *function,
+ FLAG_TYPE *flags,
+ void *data
+)
+{
+ uint_fast16_t i, j;
+ uint_fast8_t palette_only = 1;
+ uint_fast8_t skip_frame;
+ uint_fast8_t skip_line;
+ uint_fast8_t skip_pixel;
+ ILint actual_frames = 0xFFFFFFFF;
+ ILint actual_width = 0xFFFFFFFF;
+ ILint actual_height = 0xFFFFFFFF;
+ ILint actual_colours= 0xFFFFFFFF;
+ ILint x, y, f;
+ struct PixelInfo *p;
+ int r = 0;
+
+ if (n==0)
+ return 0;
+
+ p = malloc((sizeof (struct PixelInfo)) * n);
+ if (p == NULL)
+ {
+ perror("perform_action(): malloc():");
+ return (r=errno);
+ }
+
+ for (i=0; i<n; ++i)
+ {
+ p[i].flags = flags[i] & ~(IS_MULTIPLE);
+
+ if (id[i] >= n_pictures)
+ {
+ free(p);
+ return EINVAL;
+ }
+ if (!(picture[id].open))
+ {
+ free(p);
+ return EINVAL;
+ }
+
+ get_info(id[i], &(p[i].info), 0);
+
+ if (p[i].info.num_images > 0)
+ p[i].flags |= IS_MULTIPLE;
+ if (p[i].flags & CAN_BE_MULTIPLE)
+ {
+ if (p[i].num_images+1 < actual_frames)
+ actual_frames = p[i].num_images+1;
+ }
+ else
+ actual_frames = 1;
+
+ if (p[i].info.image_width < actual_width)
+ actual_width = p[i].info.image_width;
+ if (p[i].info.image_height < actual_height)
+ actual_height = p[i].info.image_height;
+
+ if (*flags & IN_WINDOW) /* check first flags only! */
+ {
+ p[i].f0 = f0[i];
+ p[i].x0 = x0[i];
+ p[i].y0 = y0[i];
+ }
+ else
+ {
+ p[i].f0 = 0;
+ p[i].x0 = 0;
+ p[i].y0 = 0;
+ }
+
+ if ((p[i].info.image_format != IL_COLOUR_INDEX) || (!(p[i].flags & OK_PALETTE_ONLY)))
+ palette_only = 0;
+ }
+
+ if (!(*flags & IN_WINDOW)) /* check first flags only! */
+ {
+ width = actual_width;
+ height = actual_height;
+ frames = actual_frames;
+ }
+
+ for (f = 0; (f < frames) && (r == 0); ++f)
+ {
+ skip_frame = 0;
+ for (i=0; i<n; ++n)
+ {
+ p[i].f_window = f;
+ p[i].f_pict = p[i].f0 + f;
+ if ((p[i].f_pict < 0) || (p[i].f_pict > p[i].info.num_images))
+ {
+ skip_frame = 1;
+ break;
+ }
+
+ ilBindImage(picture[id[i]].handle);
+ ilActiveImage(p[i].f_pict);
+ p[i].data = ilGetData();
+ p[i].flags &= ~(IS_GRAY|IS_INDEXED|IS_OVER_8BIT|IS_PALETTE_ONLY);
+ if (palette_only)
+ p[i].flags |= IS_PALETTE_ONLY;
+
+ p[i].alpha_offset = 0;
+ p[i].value_offset = 0;
+ p[i].index_offset = 0;
+ p[i].red_offset = 0;
+ p[i].green_offset = 0;
+ p[i].blue_offset = 0;
+
+ if (palette_only)
+ {
+ if (p[i].palette_num_cols < actual_colours)
+ actual_colours = p[i].palette_num_cols;
+ }
+
+ switch (p[i].info.image_format)
+ {
+ case IL_COLOUR_INDEX:
+ p[i].flags |= IS_INDEXED;
+ p[i].palette = ilGetPalette();
+ switch (p[i].info.palette_type)
+ {
+ case IL_PAL_BGR32:
+ case IL_PAL_RGB32:
+ p[i].flags |= IS_OVER_8BIT;
+ break;
+ case IL_PAL_BGRA32:
+ p[i].flags |= HAS_ALPHA;
+ p[i].alpha_offset = 3;
+ case IL_PAL_BGR24:
+ p[i].red_offset = 2;
+ p[i].green_offset = 1;
+ p[i].blue_offset = 0;
+ break;
+ case IL_PAL_RGBA32:
+ p[i].flags |= HAS_ALPHA;
+ p[i].alpha_offset = 3;
+ case IL_PAL_RGB24:
+ default:
+ p[i].red_offset = 0;
+ p[i].green_offset = 1;
+ p[i].blue_offset = 2;
+ break;
+ }
+ break;
+ case IL_LUMINANCE_ALPHA:
+ p[i].flags |= HAS_ALPHA;
+ p[i].alpha_offset = 1 * p[i].info.image_bpc;
+ case IL_LUMINANCE:
+ p[i].flags |= IS_GRAY;
+ p[i].value_offset = 0 * p[i].info.image_bpc;
+ break;
+ case IL_BGRA:
+ p[i].flags |= HAS_ALPHA;
+ p[i].alpha_offset = 3 * p[i].info.image_bpc;
+ case IL_BGR:
+ p[i].red_offset = 2 * p[i].info.image_bpc;
+ p[i].green_offset = 1 * p[i].info.image_bpc;
+ p[i].blue_offset = 0 * p[i].info.image_bpc;
+ break;
+ case IL_RGBA:
+ p[i].flags |= HAS_ALPHA;
+ p[i].alpha_offset = 3 * p[i].info.image_bpc;
+ case IL_RGB:
+ default:
+ p[i].red_offset = 0 * p[i].info.image_bpc;
+ p[i].green_offset = 1 * p[i].info.image_bpc;
+ p[i].blue_offset = 2 * p[i].info.image_bpc;
+ break;
+ }
+ if (p[i].info.image_bpc > 1)
+ p[i].flags |= IS_OVER_8BIT;
+ }
+ if (!skip_frame)
+ {
+ if (palette_only)
+ {
+ for (i=0; i<n; ++i)
+ {
+ p[i].index = 0;
+ p[i].pal_offset = 0;
+ flags[i] |= IS_PALETE_ONLY;
+ }
+ for (j=0; (j<actual_colours) && (r==0); ++j)
+ {
+ for (i=0; i<n; ++i)
+ {
+ if (!(p[i].flags & NOT_READABLE))
+ {
+ p[i].red = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)));
+ p[i].green = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)));
+ p[i].blue = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].blue_offset)));
+ if (p[i].flags & HAS_ALPHA)
+ {
+ if (p[i].flags & CANNOT_HAVE_ALPHA)
+ p[i].alpha = 0xFF;
+ else
+ p[i].alpha = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)));
+ }
+ else if (p[i].flags & MUST_HAVE_ALPHA)
+ p[i].alpha = 0xFF;
+ if (p[i].flags & MUST_BE_GRAY)
+ p[i].value = (p[i].red + p[i].green + p[i].blue) / 3;
+ }
+ }
+
+ r = function(n, p, data);
+ if (r)
+ break;
+
+ for (i=0; i<n; ++i)
+ {
+ if (!(p[i].flags & NOT_WRITABLE))
+ {
+ if (p[i].flags & MUST_BE_GRAY)
+ {
+ p[i].red = p[i].value;
+ p[i].green = p[i].value;
+ p[i].blue = p[i].value;
+ }
+ if (p[i].flags & HAS_ALPHA)
+ {
+ if (p[i].flags & CANNOT_HAVE_ALPHA)
+ p[i].alpha = 0xFF;
+ *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)) = (ILubyte)(p[i].alpha);
+ }
+ *((ILubyte*)(p.[i]palette + p[i].pal_offset + p[i].red_offset)) = (ILubyte)(p[i].red);
+ *((ILubyte*)(p.[i]palette + p[i].pal_offset + p[i].green_offset)) = (ILubyte)(p[i].green);
+ *((ILubyte*)(p.[i]palette + p[i].pal_offset + p[i].blue_offset)) = (ILubyte)(p[i].blue);
+ }
+
+ ++(p[i].index);
+ p[i].pal_offset += p[i].info.palette_bpp;
+ }
+ }
+ }
+ else
+ {
+ for (i=0; i<n; ++i)
+ {
+ p[i].line_bytes = p[i].info.image_bytes_per_pixel * p[i].info.image_width;
+ p[i].frame_bytes = p[i].line_bytes * p[i].info.image_height;
+
+ if (p[i].info.image_origin == IL_ORIGIN_LOWER_LEFT)
+ {
+ p[i].line_start = p[i].frame_bytes - p[i].line_bytes;
+ p[i].line_bytes = 0 - p[i].line_bytes;
+ }
+ else
+ p[i].line_start = 0;
+
+ p[i].y_window = 0;
+ p[i].y_pict = p[i].y0;
+ p[i].line_offset = p[i].line_start + (p[i].y_pict * p[i].line_bytes);
+ }
+ for (y=0; (y<height) && (r == 0); ++y)
+ {
+ skip_line = 0;
+ for (i=0; i<n; ++i)
+ {
+ if ((p[i].y_pict < 0) || (p[i].y_pict >= p[i]info.image_height))
+ {
+ skip_line = 1;
+ break;
+ }
+
+ p[i].x_window = 0;
+ p[i].x_pict = p[i].x0;
+ p[i].pixel_offset = p[i].line_offset + (p[i].x_pict * p[i].info.image_bytes_per_pixel);
+ }
+ if (!skip_line)
+ {
+ for (x=0; x<width; ++x)
+ {
+ skip_pixel = 0;
+ for (i=0; i<n; ++i)
+ {
+ if ((p[i].x_pict < 0) || (p[i].x_pict >= p[i]info.image_width))
+ {
+ skip_pixel = 1;
+ break;
+ }
+ }
+ if (!skip_pixel)
+ {
+ for (i=0; i<n; ++i)
+ {
+ if (!(p[i].flags & NOT_READABLE))
+ {
+ /* can this be done better? think about it */
+ switch (p[i].info.image_type)
+ {
+ case IL_INT:
+ case IL_UNSIGNED_INT:
+ if (p[i].flags & IS_INDEXED)
+ p[i].index = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].index_offset));
+ else
+ {
+ if (p[i].flags & IS_GRAY)
+ p[i].value = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].value_offset));
+ else
+ {
+ p[i].red = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].red_offset));
+ p[i].green = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].green_offset));
+ p[i].blue = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].blue_offset));
+ }
+ if (p.flags & HAS_ALPHA)
+ p[i].alpha = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset));
+ }
+ break;
+ case IL_SHORT:
+ case IL_UNSIGNED_SHORT:
+ if (p[i].flags & IS_INDEXED)
+ p[i].index = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].index_offset)));
+ else
+ {
+ if(p.flags & IS_GRAY)
+ p[i].value = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].value_offset)));
+ else
+ {
+ p[i].red = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].red_offset)));
+ p[i].green = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].green_offset)));
+ p[i].blue = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)));
+ }
+ if(p.flags & HAS_ALPHA)
+ p[i].alpha = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)));
+ }
+ break;
+ case IL_BYTE:
+ case IL_UNSIGNED_BYTE:
+ if(p.flags & IS_INDEXED)
+ p[i].index = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].index_offset)));
+ else
+ {
+ if(p.flags & IS_GRAY)
+ p[i].value = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].value_offset)));
+ else
+ {
+ p[i].red = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].red_offset)));
+ p[i].green = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].green_offset)));
+ p[i].blue = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)));
+ }
+ if(p.flags & HAS_ALPHA)
+ p[i].alpha = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)));
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((p[i].flags & IS_INDEXED) && (p[i].flags & CANNOT_BE_INDEXED))
+ {
+ if (p[i].index < p[i].info.palette_num_cols)
+ {
+ p[i].pal_offset = p[i].index * p[i].info.palette_bpp;
+ p[i].red = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)));
+ p[i].green = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)));
+ p[i].blue = (ILuint)(*((ILubyte*)(p.[i]palette + p[i].pal_offset + p[i].blue_offset)));
+ if (p[i].flags & HAS_ALPHA)
+ p[i].alpha = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)));
+ }
+ }
+
+ if ((p.flags & IS_GRAY) && (p.flags & CANNOT_BE_GRAY))
+ {
+ p.red = p.value;
+ p.green = p.value;
+ p.blue = p.value;
+ }
+ else if (!(p.flags & IS_GRAY) && (p.flags & MUST_BE_GRAY))
+ p.value = (p.red + p.green + p.blue) / 3;
+
+ if (((!(p.flags & HAS_ALPHA)) && (p.flags & MUST_HAVE_ALPHA)) || ((p.flags & HAS_ALPHA) && (p.flags & CANNOT_HAVE_ALPHA)))
+ {
+ switch (p.info.image_type)
+ {
+ case IL_INT:
+ case IL_UNSIGNED_INT:
+ p.alpha = 0xFFFFFFFF;
+ break;
+ case IL_SHORT:
+ case IL_UNSIGNED_SHORT:
+ p.alpha = 0xFFFF;
+ break;
+ case IL_BYTE:
+ case IL_UNSIGNED_BYTE:
+ p.alpha = 0xFF;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ r = function(1, &p, data);
+ if (r)
+ break;
+
+ if (!(p.flags & NOT_WRITABLE))
+ {
+ if ((p.flags & HAS_ALPHA) && (p.flags & CANNOT_HAVE_ALPHA))
+ p.alpha = 0xFFFFFFFF;
+
+ else if (!(p.flags & IS_GRAY) && (p.flags & MUST_BE_GRAY))
+ {
+ p.red = p.value;
+ p.green = p.value;
+ p.blue = p.value;
+ }
+ else if ((p.flags & IS_GRAY) && (p.flags & CANNOT_BE_GRAY))
+ p.value = (p.red + p.green + p.blue) / 3;
+
+ switch (p.info.image_type)
+ {
+ case IL_INT:
+ case IL_UNSIGNED_INT:
+ if(p.flags & IS_INDEXED)
+ *((ILuint*)(p.data + p.pixel_offset + p.index_offset)) = p.index;
+ else
+ {
+ if(p.flags & IS_GRAY)
+ *((ILuint*)(p.data + p.pixel_offset + p.value_offset)) = p.value;
+ else
+ {
+ *((ILuint*)(p.data + p.pixel_offset + p.red_offset)) = p.red;
+ *((ILuint*)(p.data + p.pixel_offset + p.green_offset)) = p.green;
+ *((ILuint*)(p.data + p.pixel_offset + p.blue_offset)) = p.blue;
+ }
+ if(p.flags & HAS_ALPHA)
+ *((ILuint*)(p.data + p.pixel_offset + p.alpha_offset)) = (ILubyte)p.alpha;
+ }
+ break;
+ case IL_SHORT:
+ case IL_UNSIGNED_SHORT:
+ if(p.flags & IS_INDEXED)
+ *((ILushort*)(p.data + p.pixel_offset + p.index_offset)) = (ILushort)p.index;
+ else
+ {
+ if(p.flags & IS_GRAY)
+ *((ILushort*)(p.data + p.pixel_offset + p.value_offset)) = (ILushort)p.value;
+ else
+ {
+ *((ILushort*)(p.data + p.pixel_offset + p.red_offset)) = (ILushort)p.red;
+ *((ILushort*)(p.data + p.pixel_offset + p.green_offset)) = (ILushort)p.green;
+ *((ILushort*)(p.data + p.pixel_offset + p.blue_offset)) = (ILushort)p.blue;
+ }
+ if(p.flags & HAS_ALPHA)
+ *((ILushort*)(p.data + p.pixel_offset + p.alpha_offset)) = (ILushort)p.alpha;
+ }
+ break;
+ case IL_BYTE:
+ case IL_UNSIGNED_BYTE:
+ if(p.flags & IS_INDEXED)
+ *((ILubyte*)(p.data + p.pixel_offset + p.index_offset)) = (ILubyte)p.index;
+ else
+ {
+ if(p.flags & IS_GRAY)
+ *((ILubyte*)(p.data + p.pixel_offset + p.value_offset)) = (ILubyte)p.value;
+ else
+ {
+ *((ILubyte*)(p.data + p.pixel_offset + p.red_offset)) = (ILubyte)p.red;
+ *((ILubyte*)(p.data + p.pixel_offset + p.green_offset)) = (ILubyte)p.green;
+ *((ILubyte*)(p.data + p.pixel_offset + p.blue_offset)) = (ILubyte)p.blue;
+ }
+ if(p.flags & HAS_ALPHA)
+ *((ILubyte*)(p.data + p.pixel_offset + p.alpha_offset)) = (ILubyte)p.alpha;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return r;
+}
+
+
ILuint upscale_value (ILubyte x, ILint bytes)
{
ILint i;