From a5d1d96a380db3e6ae5712e1730a65a3e221b623 Mon Sep 17 00:00:00 2001 From: Stayd Date: Sat, 25 Nov 2023 19:47:49 -0700 Subject: [PATCH] Consolidate YCoCg/AlphaExp code, always decode Moves most of the code relating to YCoCg and Alpha Exponent into misc.c/h, in the interest of making the rest of the codebase cleaner. Removes the decode option from the import menu, as encoded files are always decoded now (there used to be a menu button for doing this after import, but with it gone there's no reason ever to not decode). Finally, the remaining functions in color.c were only ever called once, so these were extracted and inlined, and the empty file deleted. --- plug-ins/file-dds/color.c | 62 ----- plug-ins/file-dds/color.h | 112 --------- plug-ins/file-dds/dds.c | 146 ------------ plug-ins/file-dds/ddsread.c | 106 ++++----- plug-ins/file-dds/ddswrite.c | 81 +++---- plug-ins/file-dds/dxt.c | 180 +-------------- plug-ins/file-dds/meson.build | 1 - plug-ins/file-dds/mipmap.c | 36 ++- plug-ins/file-dds/misc.c | 419 ++++++++++++++++++++++++++-------- plug-ins/file-dds/misc.h | 27 ++- 10 files changed, 459 insertions(+), 711 deletions(-) delete mode 100644 plug-ins/file-dds/color.c delete mode 100644 plug-ins/file-dds/color.h diff --git a/plug-ins/file-dds/color.c b/plug-ins/file-dds/color.c deleted file mode 100644 index 11086cd73e..0000000000 --- a/plug-ins/file-dds/color.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * DDS GIMP plugin - * - * Copyright (C) 2004-2012 Shawn Kirst , - * with parts (C) 2003 Arne Reuter where specified. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ - -#include - -#include - -#include "color.h" - - -gfloat -linear_to_sRGB (gfloat c) -{ - gfloat v = (gfloat) c; - - if (v < 0.0f) - v = 0.0f; - else if (v > 1.0f) - v = 1.0f; - else if (v <= 0.0031308f) - v = 12.92f * v; - else - v = 1.055f * powf (v, 0.41666f) - 0.055f; - - return v; -} - -gfloat -sRGB_to_linear (gfloat c) -{ - gfloat v = (gfloat) c; - - if (v < 0.0f) - v = 0.0f; - else if (v > 1.0f) - v = 1.0f; - else if (v <= 0.04045f) - v /= 12.92f; - else - v = powf ((v + 0.055f) / 1.055f, 2.4f); - - return v; -} diff --git a/plug-ins/file-dds/color.h b/plug-ins/file-dds/color.h deleted file mode 100644 index f86c44bb1d..0000000000 --- a/plug-ins/file-dds/color.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * DDS GIMP plugin - * - * Copyright (C) 2004-2012 Shawn Kirst , - * with parts (C) 2003 Arne Reuter where specified. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __COLOR_H__ -#define __COLOR_H__ - - -#include "imath.h" - - -/* sRGB encoding & decoding */ -gfloat linear_to_sRGB (gfloat c); -gfloat sRGB_to_linear (gfloat c); - - -/* YCoCg encoding */ -static inline void -RGB_to_YCoCg (guchar *dst, gint r, gint g, gint b) -{ - gint y = ((r + (g << 1) + b) + 2) >> 2; - gint co = ((((r << 1) - (b << 1)) + 2) >> 2) + 128; - gint cg = (((-r + (g << 1) - b) + 2) >> 2) + 128; - - dst[0] = 255; - dst[1] = (cg > 255 ? 255 : (cg < 0 ? 0 : cg)); - dst[2] = (co > 255 ? 255 : (co < 0 ? 0 : co)); - dst[3] = (y > 255 ? 255 : (y < 0 ? 0 : y)); -} - - -/* Other color conversions */ -static inline gint -rgb_to_luminance (gint r, - gint g, - gint b) -{ - /* ITU-R BT.709 luma coefficients, scaled by 256 */ - return ((r * 54 + g * 182 + b * 20) + 128) >> 8; -} - -static inline gushort -pack_r5g6b5 (gint r, - gint g, - gint b) -{ - return (mul8bit (r, 31) << 11) | - (mul8bit (g, 63) << 5) | - (mul8bit (b, 31) ); -} - -static inline gushort -pack_rgba4 (gint r, - gint g, - gint b, - gint a) -{ - return (mul8bit (a, 15) << 12) | - (mul8bit (r, 15) << 8) | - (mul8bit (g, 15) << 4) | - (mul8bit (b, 15) ); -} - -static inline gushort -pack_rgb5a1 (gint r, - gint g, - gint b, - gint a) -{ - return (((a >> 7) & 0x01) << 15) | - (mul8bit (r, 31) << 10) | - (mul8bit (g, 31) << 5) | - (mul8bit (b, 31) ); -} - -static inline guchar -pack_r3g3b2 (gint r, - gint g, - gint b) -{ - return (mul8bit (r, 7) << 5) | - (mul8bit (g, 7) << 2) | - (mul8bit (b, 3) ); -} - -static inline guint -pack_rgb10a2 (gint r, gint g, gint b, gint a) -{ - return ((guint) ((a >> 6) & 0x003) << 30) | - ((guint) ((b << 2) & 0x3ff) << 20) | - ((guint) ((g << 2) & 0x3ff) << 10) | - ((guint) ((r << 2) & 0x3ff) ); -} - - -#endif /* __COLOR_H__ */ diff --git a/plug-ins/file-dds/dds.c b/plug-ins/file-dds/dds.c index b9313138dc..c15fd796e6 100644 --- a/plug-ins/file-dds/dds.c +++ b/plug-ins/file-dds/dds.c @@ -42,10 +42,6 @@ #define LOAD_PROC "file-dds-load" #define SAVE_PROC "file-dds-save" -#define DECODE_YCOCG_PROC "color-decode-ycocg" -#define DECODE_YCOCG_SCALED_PROC "color-decode-ycocg-scaled" -#define DECODE_ALPHA_EXP_PROC "color-decode-alpha-exp" - typedef struct _Dds Dds; typedef struct _DdsClass DdsClass; @@ -86,15 +82,6 @@ static GimpValueArray * dds_save (GimpProcedure *procedure, GimpMetadata *metadata, GimpProcedureConfig *config, gpointer run_data); -#if 0 -static GimpValueArray * dds_decode (GimpProcedure *procedure, - GimpRunMode run_mode, - GimpImage *image, - gint n_drawables, - GimpDrawable **drawables, - GimpProcedureConfig *config, - gpointer run_data); -#endif G_DEFINE_TYPE (Dds, dds, GIMP_TYPE_PLUG_IN) @@ -125,11 +112,6 @@ dds_query_procedures (GimpPlugIn *plug_in) list = g_list_append (list, g_strdup (LOAD_PROC)); list = g_list_append (list, g_strdup (SAVE_PROC)); -#if 0 - list = g_list_append (list, g_strdup (DECODE_YCOCG_PROC)); - list = g_list_append (list, g_strdup (DECODE_YCOCG_SCALED_PROC)); - list = g_list_append (list, g_strdup (DECODE_ALPHA_EXP_PROC)); -#endif return list; } @@ -183,12 +165,6 @@ dds_create_procedure (GimpPlugIn *plug_in, "to opaque black"), TRUE, G_PARAM_READWRITE); - - GIMP_PROC_ARG_BOOLEAN (procedure, "decode-images", - _("Automatically decode YCoCg/AE_xp images when detected"), - _("Decode YCoCg/AExp images when detected"), - TRUE, - G_PARAM_READWRITE); } else if (! strcmp (name, SAVE_PROC)) { @@ -358,78 +334,6 @@ dds_create_procedure (GimpPlugIn *plug_in, 0.0, 1.0, 0.5, G_PARAM_READWRITE); } -#if 0 - else if (! strcmp (name, DECODE_YCOCG_PROC)) - { - procedure = gimp_image_procedure_new (plug_in, name, - GIMP_PDB_PROC_TYPE_PLUGIN, - dds_decode, NULL, NULL); - - gimp_procedure_set_image_types (procedure, "RGBA"); - gimp_procedure_set_sensitivity_mask (procedure, - GIMP_PROCEDURE_SENSITIVE_DRAWABLE); - - gimp_procedure_set_menu_label (procedure, _("Decode YCoCg")); - /* gimp_procedure_add_menu_path (procedure, "/Filters/Colors"); */ - - gimp_procedure_set_documentation (procedure, - _("Converts YCoCg encoded pixels to RGB"), - _("Converts YCoCg encoded pixels to RGB"), - name); - gimp_procedure_set_attribution (procedure, - "Shawn Kirst", - "Shawn Kirst", - "2008"); - } - else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC)) - { - procedure = gimp_image_procedure_new (plug_in, name, - GIMP_PDB_PROC_TYPE_PLUGIN, - dds_decode, NULL, NULL); - - gimp_procedure_set_image_types (procedure, "RGBA"); - gimp_procedure_set_sensitivity_mask (procedure, - GIMP_PROCEDURE_SENSITIVE_DRAWABLE); - - gimp_procedure_set_menu_label (procedure, _("Decode YCoCg (scaled)")); - /* gimp_procedure_add_menu_path (procedure, "/Filters/Colors"); */ - - gimp_procedure_set_documentation (procedure, - _("Converts YCoCg (scaled) encoded " - "pixels to RGB"), - _("Converts YCoCg (scaled) encoded " - "pixels to RGB"), - name); - gimp_procedure_set_attribution (procedure, - "Shawn Kirst", - "Shawn Kirst", - "2008"); - } - else if (! strcmp (name, DECODE_ALPHA_EXP_PROC)) - { - procedure = gimp_image_procedure_new (plug_in, name, - GIMP_PDB_PROC_TYPE_PLUGIN, - dds_decode, NULL, NULL); - - gimp_procedure_set_image_types (procedure, "RGBA"); - gimp_procedure_set_sensitivity_mask (procedure, - GIMP_PROCEDURE_SENSITIVE_DRAWABLE); - - gimp_procedure_set_menu_label (procedure, _("Decode Alpha exponent")); - /* gimp_procedure_add_menu_path (procedure, "/Filters/Colors"); */ - - gimp_procedure_set_documentation (procedure, - _("Converts alpha exponent encoded " - "pixels to RGB", - _("Converts alpha exponent encoded " - "pixels to RGB"), - name); - gimp_procedure_set_attribution (procedure, - "Shawn Kirst", - "Shawn Kirst", - "2008"); - } -#endif return procedure; } @@ -535,53 +439,3 @@ dds_save (GimpProcedure *procedure, return gimp_procedure_new_return_values (procedure, status, error); } - -#if 0 -static GimpValueArray * -dds_decode (GimpProcedure *procedure, - GimpRunMode run_mode, - GimpImage *image, - gint n_drawables, - GimpDrawable **drawables, - GimpProcedureConfig *config, - gpointer run_data) -{ - const gchar *name = gimp_procedure_get_name (procedure); - GimpDrawable *drawable, - - if (n_drawables != 1) - { - GError *error = NULL; - - g_set_error (&error, GIMP_PLUG_IN_ERROR, 0, - _("Procedure '%s' only works with one drawable."), - name); - - return gimp_procedure_new_return_values (procedure, - GIMP_PDB_EXECUTION_ERROR, - error); - } - else - { - drawable = drawables[0]; - } - - if (! strcmp (name, DECODE_YCOCG_PROC)) - { - decode_ycocg_image (drawable, TRUE); - } - else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC)) - { - decode_ycocg_scaled_image (drawable, TRUE); - } - else if (! strcmp (name, DECODE_ALPHA_EXP_PROC)) - { - decode_alpha_exp_image (drawable, TRUE); - } - - if (run_mode != GIMP_RUN_NONINTERACTIVE) - gimp_displays_flush (); - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} -#endif diff --git a/plug-ins/file-dds/ddsread.c b/plug-ins/file-dds/ddsread.c index ecd04bfc1a..87dd4ee06b 100644 --- a/plug-ins/file-dds/ddsread.c +++ b/plug-ins/file-dds/ddsread.c @@ -65,19 +65,19 @@ typedef struct } dds_load_info_t; -static gboolean read_header (dds_header_t *hdr, - FILE *fp); -static gboolean read_header_dx10 (dds_header_dx10_t *hdr, - FILE *fp); -static gboolean validate_header (dds_header_t *hdr, - GError **error); -static gboolean setup_dxgi_format (dds_header_t *hdr, - const dds_header_dx10_t *dx10hdr, - dds_load_info_t *load_info, - GError **error); -static gboolean load_layer (FILE *fp, - const dds_header_t *hdr, - const dds_header_dx10_t *dx10hdr, +static gboolean read_header (dds_header_t *hdr, + FILE *fp); +static gboolean read_header_dx10 (dds_header_dx10_t *hdr, + FILE *fp); +static gboolean validate_header (dds_header_t *hdr, + GError **error); +static gboolean setup_dxgi_format (dds_header_t *hdr, + const dds_header_dx10_t *dx10hdr, + dds_load_info_t *load_info, + GError **error); +static gboolean load_layer (FILE *fp, + const dds_header_t *hdr, + const dds_header_dx10_t *dx10hdr, dds_load_info_t *load_info, GimpImage *image, guint level, @@ -85,7 +85,6 @@ static gboolean load_layer (FILE *fp, guint *layer_index, guchar *pixels, guchar *buf, - gboolean decode_images, GError **error); static gboolean load_mipmaps (FILE *fp, const dds_header_t *hdr, @@ -97,24 +96,22 @@ static gboolean load_mipmaps (FILE *fp, guchar *pixels, guchar *buf, gboolean read_mipmaps, - gboolean decode_images, GError **error); static gboolean load_face (FILE *fp, - const dds_header_t *hdr, - const dds_header_dx10_t *dx10hdr, - dds_load_info_t *load_info, - GimpImage *image, - gchar *prefix, - guint *layer_index, - guchar *pixels, - guchar *buf, - gboolean read_mipmaps, - gboolean decode_images, - GError **error); -static guchar color_bits (guint mask); -static guchar color_shift (guint mask); -static gboolean load_dialog (GimpProcedure *procedure, - GimpProcedureConfig *config); + const dds_header_t *hdr, + const dds_header_dx10_t *dx10hdr, + dds_load_info_t *load_info, + GimpImage *image, + gchar *prefix, + guint *layer_index, + guchar *pixels, + guchar *buf, + gboolean read_mipmaps, + GError **error); +static guchar color_bits (guint mask); +static guchar color_shift (guint mask); +static gboolean load_dialog (GimpProcedure *procedure, + GimpProcedureConfig *config); /* Read DDS file */ @@ -138,7 +135,6 @@ read_dds (GFile *file, GimpImageBaseType type; GimpPrecision precision; gboolean read_mipmaps; - gboolean decode_images; gint i, j; guint computed_pitch_or_linsize; gboolean flip_import; @@ -156,7 +152,6 @@ read_dds (GFile *file, "load-mipmaps", &read_mipmaps, "flip-image", &flip_import, "bc1-use-transparency", &bc1_use_transparency, - "decode-images", &decode_images, NULL); fp = g_fopen (g_file_peek_path (file), "rb"); @@ -629,7 +624,7 @@ read_dds (GFile *file, dx10hdr.arraySize <= 1) /* Standard image texture with mipmaps */ { if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, 0, "", &layer_index, - pixels, buf, decode_images, error)) + pixels, buf, error)) { fclose (fp); gimp_image_delete (image); @@ -637,7 +632,7 @@ read_dds (GFile *file, } if (! load_mipmaps (fp, &hdr, &dx10hdr, &load_info, image, "", &layer_index, - pixels, buf, read_mipmaps, decode_images, error)) + pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -648,7 +643,7 @@ read_dds (GFile *file, { if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) && ! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(positive x)", - &layer_index, pixels, buf, read_mipmaps, decode_images, error)) + &layer_index, pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -657,7 +652,7 @@ read_dds (GFile *file, if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) && ! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(negative x)", - &layer_index, pixels, buf, read_mipmaps, decode_images, error)) + &layer_index, pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -666,7 +661,7 @@ read_dds (GFile *file, if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) && ! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(positive y)", - &layer_index, pixels, buf, read_mipmaps, decode_images, error)) + &layer_index, pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -675,7 +670,7 @@ read_dds (GFile *file, if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) && ! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(negative y)", - &layer_index, pixels, buf, read_mipmaps, decode_images, error)) + &layer_index, pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -684,7 +679,7 @@ read_dds (GFile *file, if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) && ! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(positive z)", - &layer_index, pixels, buf, read_mipmaps, decode_images, error)) + &layer_index, pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -693,7 +688,7 @@ read_dds (GFile *file, if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) && ! load_face (fp, &hdr, &dx10hdr, &load_info, image, "(negative z)", - &layer_index, pixels, buf, read_mipmaps, decode_images, error)) + &layer_index, pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -711,7 +706,7 @@ read_dds (GFile *file, plane = g_strdup_printf ("(z = %d)", i); if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, 0, plane, - &layer_index, pixels, buf, decode_images, error)) + &layer_index, pixels, buf, error)) { g_free (plane); fclose (fp); @@ -738,7 +733,7 @@ read_dds (GFile *file, plane = g_strdup_printf ("(z = %d)", i); if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, level, plane, - &layer_index, pixels, buf, decode_images, error)) + &layer_index, pixels, buf, error)) { g_free (plane); fclose (fp); @@ -761,7 +756,7 @@ read_dds (GFile *file, elem = g_strdup_printf ("(array element %d)", i); if (! load_layer (fp, &hdr, &dx10hdr, &load_info, image, 0, elem, &layer_index, - pixels, buf, decode_images, error)) + pixels, buf, error)) { fclose (fp); gimp_image_delete (image); @@ -769,7 +764,7 @@ read_dds (GFile *file, } if (! load_mipmaps (fp, &hdr, &dx10hdr, &load_info, image, elem, &layer_index, - pixels, buf, read_mipmaps, decode_images, error)) + pixels, buf, read_mipmaps, error)) { fclose (fp); gimp_image_delete (image); @@ -1309,7 +1304,6 @@ load_layer (FILE *fp, guint *layer_index, guchar *pixels, guchar *buf, - gboolean decode_images, GError **error) { GeglBuffer *buffer; @@ -2025,21 +2019,20 @@ load_layer (FILE *fp, g_object_unref (buffer); - /* gimp dds specific. decode encoded images */ - if (decode_images && - hdr->reserved.gimp_dds_special.magic1 == FOURCC ('G','I','M','P') && + /* Decode files with GIMP-specific encodings */ + if (hdr->reserved.gimp_dds_special.magic1 == FOURCC ('G','I','M','P') && hdr->reserved.gimp_dds_special.magic2 == FOURCC ('-','D','D','S')) { switch (hdr->reserved.gimp_dds_special.extra_fourcc) { case FOURCC ('A','E','X','P'): - decode_alpha_exp_image (GIMP_DRAWABLE (layer), FALSE); + decode_alpha_exponent (GIMP_DRAWABLE (layer)); break; case FOURCC ('Y','C','G','1'): - decode_ycocg_image (GIMP_DRAWABLE (layer), FALSE); + decode_ycocg (GIMP_DRAWABLE (layer)); break; case FOURCC ('Y','C','G','2'): - decode_ycocg_scaled_image (GIMP_DRAWABLE (layer), FALSE); + decode_ycocg_scaled (GIMP_DRAWABLE (layer)); break; default: break; @@ -2060,7 +2053,6 @@ load_mipmaps (FILE *fp, guchar *pixels, guchar *buf, gboolean read_mipmaps, - gboolean decode_images, GError **error) { guint level; @@ -2072,7 +2064,7 @@ load_mipmaps (FILE *fp, for (level = 1; level < hdr->num_mipmaps; ++level) { if (! load_layer (fp, hdr, dx10hdr, load_info, image, level, prefix, layer_index, - pixels, buf, decode_images, error)) + pixels, buf, error)) return FALSE; } } @@ -2091,15 +2083,14 @@ load_face (FILE *fp, guchar *pixels, guchar *buf, gboolean read_mipmaps, - gboolean decode_images, GError **error) { if (! load_layer (fp, hdr, dx10hdr, load_info, image, 0, prefix, - layer_index, pixels, buf, decode_images, error)) + layer_index, pixels, buf, error)) return FALSE; return load_mipmaps (fp, hdr, dx10hdr, load_info, image, prefix, layer_index, - pixels, buf, read_mipmaps, decode_images, error); + pixels, buf, read_mipmaps, error); } static guchar @@ -2124,7 +2115,7 @@ color_shift (guint mask) if (! mask) return 0; - while (!((mask >> i) & 1)) + while (! ((mask >> i) & 1)) ++i; return i; @@ -2147,7 +2138,6 @@ load_dialog (GimpProcedure *procedure, "load-mipmaps", "flip-image", "bc1-use-transparency", - "decode-images", NULL); gtk_box_set_spacing (GTK_BOX (vbox), 8); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); diff --git a/plug-ins/file-dds/ddswrite.c b/plug-ins/file-dds/ddswrite.c index c29b07a632..4e376889bb 100644 --- a/plug-ins/file-dds/ddswrite.c +++ b/plug-ins/file-dds/ddswrite.c @@ -35,13 +35,13 @@ #include -#include "color.h" #include "dds.h" #include "ddswrite.h" #include "dxt.h" #include "endian_rw.h" #include "imath.h" #include "mipmap.h" +#include "misc.h" static gboolean write_image (FILE *fp, @@ -244,7 +244,7 @@ check_cubemap (GimpImage *image) (gimp_drawable_get_height (drawable) != h)) continue; - layer_name = (char *) gimp_item_get_name (GIMP_ITEM (drawable)); + layer_name = (gchar *) gimp_item_get_name (GIMP_ITEM (drawable)); for (j = 0; j < 6; ++j) { for (k = 0; k < 4; ++k) @@ -608,45 +608,6 @@ swap_rb (guchar *pixels, } } -static void -alpha_exp (guchar *dst, - gint r, - gint g, - gint b, - gint a) -{ - gfloat ar, ag, ab, aa; - - ar = (gfloat) r / 255.0f; - ag = (gfloat) g / 255.0f; - ab = (gfloat) b / 255.0f; - - aa = MAX (ar, MAX (ag, ab)); - - if (aa < 1e-04f) - { - dst[0] = b; - dst[1] = g; - dst[2] = r; - dst[3] = 255; - return; - } - - ar /= aa; - ag /= aa; - ab /= aa; - - r = (gint) floorf (255.0f * ar + 0.5f); - g = (gint) floorf (255.0f * ag + 0.5f); - b = (gint) floorf (255.0f * ab + 0.5f); - a = (gint) floorf (255.0f * aa + 0.5f); - - dst[0] = MAX (0, MIN (255, b)); - dst[1] = MAX (0, MIN (255, g)); - dst[2] = MAX (0, MIN (255, r)); - dst[3] = MAX (0, MIN (255, a)); -} - static void convert_pixels (guchar *dst, guchar *src, @@ -729,36 +690,56 @@ convert_pixels (guchar *dst, dst[4 * i + 3] = a; break; case DDS_FORMAT_R5G6B5: - PUTL16 (&dst[2 * i], pack_r5g6b5 (r, g, b)); + PUTL16 (&dst[2 * i], + (mul8bit (r, 31) << 11) | + (mul8bit (g, 63) << 5) | + (mul8bit (b, 31) )); break; case DDS_FORMAT_RGBA4: - PUTL16 (&dst[2 * i], pack_rgba4 (r, g, b, a)); + PUTL16 (&dst[2 * i], + (mul8bit (a, 15) << 12) | + (mul8bit (r, 15) << 8) | + (mul8bit (g, 15) << 4) | + (mul8bit (b, 15) )); break; case DDS_FORMAT_RGB5A1: - PUTL16 (&dst[2 * i], pack_rgb5a1 (r, g, b, a)); + PUTL16 (&dst[2 * i], + (((a >> 7) & 0x01) << 15) | + (mul8bit (r, 31) << 10) | + (mul8bit (g, 31) << 5) | + (mul8bit (b, 31) )); break; case DDS_FORMAT_RGB10A2: - PUTL32 (&dst[4 * i], pack_rgb10a2 (r, g, b, a)); + PUTL32 (&dst[4 * i], + ((guint) ((a >> 6) & 0x003) << 30) | + ((guint) ((b << 2) & 0x3ff) << 20) | + ((guint) ((g << 2) & 0x3ff) << 10) | + ((guint) ((r << 2) & 0x3ff) )); break; case DDS_FORMAT_R3G3B2: - dst[i] = pack_r3g3b2 (r, g, b); + dst[i] = + (mul8bit (r, 7) << 5) | + (mul8bit (g, 7) << 2) | + (mul8bit (b, 3) ); break; case DDS_FORMAT_A8: dst[i] = a; break; case DDS_FORMAT_L8: - dst[i] = rgb_to_luminance (r, g, b); + dst[i] = + ((r * 54 + g * 182 + b * 20) + 128) >> 8; break; case DDS_FORMAT_L8A8: - dst[2 * i + 0] = rgb_to_luminance (r, g, b); + dst[2 * i + 0] = + ((r * 54 + g * 182 + b * 20) + 128) >> 8; dst[2 * i + 1] = a; break; case DDS_FORMAT_YCOCG: dst[4 * i] = a; - RGB_to_YCoCg (&dst[4 * i], r, g, b); + encode_ycocg (&dst[4 * i], r, g, b); break; case DDS_FORMAT_AEXP: - alpha_exp (&dst[4 * i], r, g, b, a); + encode_alpha_exponent (&dst[4 * i], r, g, b, a); break; default: break; diff --git a/plug-ins/file-dds/dxt.c b/plug-ins/file-dds/dxt.c index e0c214336d..f992944be1 100644 --- a/plug-ins/file-dds/dxt.c +++ b/plug-ins/file-dds/dxt.c @@ -34,11 +34,14 @@ #include #include +#include + #include "dds.h" #include "dxt.h" #include "endian_rw.h" -#include "mipmap.h" #include "imath.h" +#include "mipmap.h" +#include "misc.h" #include "vec.h" #include "dxt_tables.h" @@ -757,181 +760,6 @@ encode_color_block (unsigned char *dst, PUTL32(dst + 4, indices); } -static void -get_min_max_YCoCg (const unsigned char *block, - unsigned char *mincolor, - unsigned char *maxcolor) -{ - int i; - - mincolor[2] = mincolor[1] = 255; - maxcolor[2] = maxcolor[1] = 0; - - for (i = 0; i < 16; ++i) - { - if (block[4 * i + 2] < mincolor[2]) mincolor[2] = block[4 * i + 2]; - if (block[4 * i + 1] < mincolor[1]) mincolor[1] = block[4 * i + 1]; - if (block[4 * i + 2] > maxcolor[2]) maxcolor[2] = block[4 * i + 2]; - if (block[4 * i + 1] > maxcolor[1]) maxcolor[1] = block[4 * i + 1]; - } -} - -static void -scale_YCoCg (unsigned char *block, - unsigned char *mincolor, - unsigned char *maxcolor) -{ - const int s0 = 128 / 2 - 1; - const int s1 = 128 / 4 - 1; - int m0, m1, m2, m3; - int mask0, mask1, scale; - int i; - - m0 = abs(mincolor[2] - 128); - m1 = abs(mincolor[1] - 128); - m2 = abs(maxcolor[2] - 128); - m3 = abs(maxcolor[1] - 128); - - if (m1 > m0) m0 = m1; - if (m3 > m2) m2 = m3; - if (m2 > m0) m0 = m2; - - mask0 = -(m0 <= s0); - mask1 = -(m0 <= s1); - scale = 1 + (1 & mask0) + (2 & mask1); - - mincolor[2] = (mincolor[2] - 128) * scale + 128; - mincolor[1] = (mincolor[1] - 128) * scale + 128; - mincolor[0] = (scale - 1) << 3; - - maxcolor[2] = (maxcolor[2] - 128) * scale + 128; - maxcolor[1] = (maxcolor[1] - 128) * scale + 128; - maxcolor[0] = (scale - 1) << 3; - - for (i = 0; i < 16; ++i) - { - block[i * 4 + 2] = (block[i * 4 + 2] - 128) * scale + 128; - block[i * 4 + 1] = (block[i * 4 + 1] - 128) * scale + 128; - } -} - -#define INSET_SHIFT 4 - -static void -inset_bbox_YCoCg (unsigned char *mincolor, - unsigned char *maxcolor) -{ - int inset[4], mini[4], maxi[4]; - - inset[2] = (maxcolor[2] - mincolor[2]) - ((1 << (INSET_SHIFT - 1)) - 1); - inset[1] = (maxcolor[1] - mincolor[1]) - ((1 << (INSET_SHIFT - 1)) - 1); - - mini[2] = ((mincolor[2] << INSET_SHIFT) + inset[2]) >> INSET_SHIFT; - mini[1] = ((mincolor[1] << INSET_SHIFT) + inset[1]) >> INSET_SHIFT; - - maxi[2] = ((maxcolor[2] << INSET_SHIFT) - inset[2]) >> INSET_SHIFT; - maxi[1] = ((maxcolor[1] << INSET_SHIFT) - inset[1]) >> INSET_SHIFT; - - mini[2] = (mini[2] >= 0) ? mini[2] : 0; - mini[1] = (mini[1] >= 0) ? mini[1] : 0; - - maxi[2] = (maxi[2] <= 255) ? maxi[2] : 255; - maxi[1] = (maxi[1] <= 255) ? maxi[1] : 255; - - mincolor[2] = (mini[2] & 0xf8) | (mini[2] >> 5); - mincolor[1] = (mini[1] & 0xfc) | (mini[1] >> 6); - - maxcolor[2] = (maxi[2] & 0xf8) | (maxi[2] >> 5); - maxcolor[1] = (maxi[1] & 0xfc) | (maxi[1] >> 6); -} - -static void -select_diagonal_YCoCg (const unsigned char *block, - unsigned char *mincolor, - unsigned char *maxcolor) -{ - unsigned char mid0, mid1, side, mask, b0, b1, c0, c1; - int i; - - mid0 = ((int)mincolor[2] + maxcolor[2] + 1) >> 1; - mid1 = ((int)mincolor[1] + maxcolor[1] + 1) >> 1; - - side = 0; - for (i = 0; i < 16; ++i) - { - b0 = block[i * 4 + 2] >= mid0; - b1 = block[i * 4 + 1] >= mid1; - side += (b0 ^ b1); - } - - mask = -(side > 8); - mask &= -(mincolor[2] != maxcolor[2]); - - c0 = mincolor[1]; - c1 = maxcolor[1]; - - c0 ^= c1; - c1 ^= c0 & mask; - c0 ^= c1; - - mincolor[1] = c0; - maxcolor[1] = c1; -} - -static void -encode_YCoCg_block (unsigned char *dst, - unsigned char *block) -{ - unsigned char colors[4][3], *maxcolor, *mincolor; - unsigned int mask; - int c0, c1, d0, d1, d2, d3; - int b0, b1, b2, b3, b4; - int x0, x1, x2; - int i, idx; - - maxcolor = &colors[0][0]; - mincolor = &colors[1][0]; - - get_min_max_YCoCg(block, mincolor, maxcolor); - scale_YCoCg(block, mincolor, maxcolor); - inset_bbox_YCoCg(mincolor, maxcolor); - select_diagonal_YCoCg(block, mincolor, maxcolor); - - lerp_rgb13(&colors[2][0], maxcolor, mincolor); - lerp_rgb13(&colors[3][0], mincolor, maxcolor); - - mask = 0; - - for (i = 0; i < 16; ++i) - { - c0 = block[4 * i + 2]; - c1 = block[4 * i + 1]; - - d0 = abs(colors[0][2] - c0) + abs(colors[0][1] - c1); - d1 = abs(colors[1][2] - c0) + abs(colors[1][1] - c1); - d2 = abs(colors[2][2] - c0) + abs(colors[2][1] - c1); - d3 = abs(colors[3][2] - c0) + abs(colors[3][1] - c1); - - b0 = d0 > d3; - b1 = d1 > d2; - b2 = d0 > d2; - b3 = d1 > d3; - b4 = d2 > d3; - - x0 = b1 & b2; - x1 = b0 & b3; - x2 = b0 & b4; - - idx = (x2 | ((x0 | x1) << 1)); - - mask |= idx << (2 * i); - } - - PUTL16(dst + 0, pack_rgb565(maxcolor)); - PUTL16(dst + 2, pack_rgb565(mincolor)); - PUTL32(dst + 4, mask); -} - /* write DXT3 alpha block */ static void encode_alpha_block_BC2 (unsigned char *dst, diff --git a/plug-ins/file-dds/meson.build b/plug-ins/file-dds/meson.build index 9a2dd8d27f..41ed7c9e7f 100644 --- a/plug-ins/file-dds/meson.build +++ b/plug-ins/file-dds/meson.build @@ -2,7 +2,6 @@ plugin_name = 'file-dds' plugin_sources = [ 'dds.c', - 'color.c', 'ddsread.c', 'ddswrite.c', 'dxt.c', diff --git a/plug-ins/file-dds/mipmap.c b/plug-ins/file-dds/mipmap.c index ec4c68e311..3a37589fe4 100644 --- a/plug-ins/file-dds/mipmap.c +++ b/plug-ins/file-dds/mipmap.c @@ -36,7 +36,6 @@ #include "dds.h" #include "mipmap.h" #include "imath.h" -#include "color.h" typedef gfloat (*filterfunc_t) (gfloat); @@ -217,6 +216,23 @@ wrap_clamp (gint x, * Gamma-correction */ +static gfloat +linear_to_sRGB (gfloat c) +{ + gfloat v = (gfloat) c; + + if (v < 0.0f) + v = 0.0f; + else if (v > 1.0f) + v = 1.0f; + else if (v <= 0.0031308f) + v = 12.92f * v; + else + v = 1.055f * powf (v, 0.41666f) - 0.055f; + + return v; +} + static gfloat linear_to_gamma (gint gc, gfloat v, @@ -236,6 +252,24 @@ linear_to_gamma (gint gc, return v; } + +static gfloat +sRGB_to_linear (gfloat c) +{ + gfloat v = (gfloat) c; + + if (v < 0.0f) + v = 0.0f; + else if (v > 1.0f) + v = 1.0f; + else if (v <= 0.04045f) + v /= 12.92f; + else + v = powf ((v + 0.055f) / 1.055f, 2.4f); + + return v; +} + static gfloat gamma_to_linear (gint gc, gfloat v, diff --git a/plug-ins/file-dds/misc.c b/plug-ins/file-dds/misc.c index 4b0db80f8d..320f2fb00c 100644 --- a/plug-ins/file-dds/misc.c +++ b/plug-ins/file-dds/misc.c @@ -4,56 +4,53 @@ * Copyright (C) 2004-2012 Shawn Kirst , * with parts (C) 2003 Arne Reuter where specified. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. + * along with this program. If not, see . */ #include + +#include "endian_rw.h" +#include "imath.h" #include "misc.h" -static inline float -saturate (float a) -{ - if(a < 0) a = 0; - if(a > 1) a = 1; +/* + * Decoding Functions + */ + +static inline gfloat +saturate (gfloat a) +{ + if (a < 0) a = 0; + if (a > 1) a = 1; return a; } void -decode_ycocg_image (GimpDrawable *drawable, - gboolean shadow) +decode_ycocg (GimpDrawable *drawable) { - GeglBuffer *buffer, *sbuffer; - const Babl *format; - unsigned char *data; - unsigned int i, w, h, num_pixels; - - const float offset = 0.5f * 256.0f / 255.0f; - float Y, Co, Cg, R, G, B; + GeglBuffer *buffer; + const Babl *format; + guchar *data; + guint num_pixels; + guint i, w, h; + const gfloat offset = 0.5f * 256.0f / 255.0f; + gfloat Y, Co, Cg; + gfloat R, G, B; buffer = gimp_drawable_get_buffer (drawable); - if (shadow) - { - sbuffer = gimp_drawable_get_shadow_buffer (drawable); - gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL); - g_object_unref (buffer); - buffer = sbuffer; - } - format = babl_format ("R'G'B'A u8"); w = gegl_buffer_get_width (buffer); @@ -62,46 +59,43 @@ decode_ycocg_image (GimpDrawable *drawable, data = g_malloc (num_pixels * 4); - gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data, + gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gimp_progress_init ("Decoding YCoCg pixels..."); for (i = 0; i < num_pixels; ++i) { - Y = (float)data[4 * i + 3] / 255.0f; - Co = (float)data[4 * i + 0] / 255.0f; - Cg = (float)data[4 * i + 1] / 255.0f; + Y = (gfloat) data[4 * i + 3] / 255.0f; + Co = (gfloat) data[4 * i + 0] / 255.0f; + Cg = (gfloat) data[4 * i + 1] / 255.0f; /* convert YCoCg to RGB */ Co -= offset; Cg -= offset; - R = saturate(Y + Co - Cg); - G = saturate(Y + Cg); - B = saturate(Y - Co - Cg); + R = saturate (Y + Co - Cg); + G = saturate (Y + Cg); + B = saturate (Y - Co - Cg); /* copy new alpha from blue */ data[4 * i + 3] = data[4 * i + 2]; - data[4 * i + 0] = (unsigned char)(R * 255.0f); - data[4 * i + 1] = (unsigned char)(G * 255.0f); - data[4 * i + 2] = (unsigned char)(B * 255.0f); + data[4 * i + 0] = (guchar) (R * 255.0f); + data[4 * i + 1] = (guchar) (G * 255.0f); + data[4 * i + 2] = (guchar) (B * 255.0f); if ((i & 0x7fff) == 0) - gimp_progress_update ((float)i / (float)num_pixels); + gimp_progress_update ((gdouble) i / (gdouble) num_pixels); } - gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data, + gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data, GEGL_AUTO_ROWSTRIDE); gimp_progress_update (1.0); gegl_buffer_flush (buffer); - if (shadow) - gimp_drawable_merge_shadow (drawable, TRUE); - gimp_drawable_update (drawable, 0, 0, w, h); g_free (data); @@ -110,27 +104,19 @@ decode_ycocg_image (GimpDrawable *drawable, } void -decode_ycocg_scaled_image (GimpDrawable *drawable, - gboolean shadow) +decode_ycocg_scaled (GimpDrawable *drawable) { - GeglBuffer *buffer, *sbuffer; - const Babl *format; - unsigned char *data; - unsigned int i, w, h, num_pixels; - - const float offset = 0.5f * 256.0f / 255.0f; - float Y, Co, Cg, R, G, B, s; + GeglBuffer *buffer; + const Babl *format; + guchar *data; + guint num_pixels; + guint i, w, h; + const gfloat offset = 0.5f * 256.0f / 255.0f; + gfloat Y, Co, Cg; + gfloat R, G, B, s; buffer = gimp_drawable_get_buffer (drawable); - if (shadow) - { - sbuffer = gimp_drawable_get_shadow_buffer (drawable); - gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL); - g_object_unref (buffer); - buffer = sbuffer; - } - format = babl_format ("R'G'B'A u8"); w = gegl_buffer_get_width (buffer); @@ -139,17 +125,17 @@ decode_ycocg_scaled_image (GimpDrawable *drawable, data = g_malloc (num_pixels * 4); - gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data, + gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gimp_progress_init ("Decoding YCoCg (scaled) pixels..."); for (i = 0; i < num_pixels; ++i) { - Y = (float)data[4 * i + 3] / 255.0f; - Co = (float)data[4 * i + 0] / 255.0f; - Cg = (float)data[4 * i + 1] / 255.0f; - s = (float)data[4 * i + 2] / 255.0f; + Y = (gfloat) data[4 * i + 3] / 255.0f; + Co = (gfloat) data[4 * i + 0] / 255.0f; + Cg = (gfloat) data[4 * i + 1] / 255.0f; + s = (gfloat) data[4 * i + 2] / 255.0f; /* convert YCoCg to RGB */ s = 1.0f / ((255.0f / 8.0f) * s + 1.0f); @@ -157,31 +143,28 @@ decode_ycocg_scaled_image (GimpDrawable *drawable, Co = (Co - offset) * s; Cg = (Cg - offset) * s; - R = saturate(Y + Co - Cg); - G = saturate(Y + Cg); - B = saturate(Y - Co - Cg); + R = saturate (Y + Co - Cg); + G = saturate (Y + Cg); + B = saturate (Y - Co - Cg); - data[4 * i + 0] = (unsigned char)(R * 255.0f); - data[4 * i + 1] = (unsigned char)(G * 255.0f); - data[4 * i + 2] = (unsigned char)(B * 255.0f); + data[4 * i + 0] = (guchar) (R * 255.0f); + data[4 * i + 1] = (guchar) (G * 255.0f); + data[4 * i + 2] = (guchar) (B * 255.0f); /* set alpha to 1 */ data[4 * i + 3] = 255; if ((i & 0x7fff) == 0) - gimp_progress_update ((float)i / (float)num_pixels); + gimp_progress_update ((gdouble) i / (gdouble) num_pixels); } - gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data, + gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data, GEGL_AUTO_ROWSTRIDE); gimp_progress_update (1.0); gegl_buffer_flush (buffer); - if (shadow) - gimp_drawable_merge_shadow (drawable, TRUE); - gimp_drawable_update (drawable, 0, 0, w, h); g_free (data); @@ -190,25 +173,17 @@ decode_ycocg_scaled_image (GimpDrawable *drawable, } void -decode_alpha_exp_image (GimpDrawable *drawable, - gboolean shadow) +decode_alpha_exponent (GimpDrawable *drawable) { - GeglBuffer *buffer, *sbuffer; + GeglBuffer *buffer; const Babl *format; - unsigned char *data; - unsigned int i, w, h, num_pixels; - int R, G, B, A; + guchar *data; + guint num_pixels; + guint i, w, h; + gint R, G, B, A; buffer = gimp_drawable_get_buffer (drawable); - if (shadow) - { - sbuffer = gimp_drawable_get_shadow_buffer (drawable); - gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL); - g_object_unref (buffer); - buffer = sbuffer; - } - format = babl_format ("R'G'B'A u8"); w = gegl_buffer_get_width (buffer); @@ -217,7 +192,7 @@ decode_alpha_exp_image (GimpDrawable *drawable, data = g_malloc (num_pixels * 4); - gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data, + gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gimp_progress_init ("Decoding Alpha-exponent pixels..."); @@ -240,22 +215,268 @@ decode_alpha_exp_image (GimpDrawable *drawable, data[4 * i + 3] = A; if ((i & 0x7fff) == 0) - gimp_progress_update ((float)i / (float)num_pixels); + gimp_progress_update ((gdouble) i / (gdouble) num_pixels); } - gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data, + gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data, GEGL_AUTO_ROWSTRIDE); gimp_progress_update (1.0); gegl_buffer_flush (buffer); - if (shadow) - gimp_drawable_merge_shadow (drawable, TRUE); - gimp_drawable_update (drawable, 0, 0, w, h); g_free (data); g_object_unref (buffer); } + + +/* + * Encoding Functions + */ + +void +encode_ycocg (guchar *dst, + gint r, + gint g, + gint b) +{ + gint y = ((r + (g << 1) + b) + 2) >> 2; + gint co = ((((r << 1) - (b << 1)) + 2) >> 2) + 128; + gint cg = (((-r + (g << 1) - b) + 2) >> 2) + 128; + + dst[0] = 255; + dst[1] = (cg > 255 ? 255 : (cg < 0 ? 0 : cg)); + dst[2] = (co > 255 ? 255 : (co < 0 ? 0 : co)); + dst[3] = (y > 255 ? 255 : (y < 0 ? 0 : y)); +} + +void +encode_alpha_exponent (guchar *dst, + gint r, + gint g, + gint b, + gint a) +{ + gfloat ar, ag, ab, aa; + + ar = (gfloat) r / 255.0f; + ag = (gfloat) g / 255.0f; + ab = (gfloat) b / 255.0f; + + aa = MAX (ar, MAX (ag, ab)); + + if (aa < 1e-04f) + { + dst[0] = b; + dst[1] = g; + dst[2] = r; + dst[3] = 255; + return; + } + + ar /= aa; + ag /= aa; + ab /= aa; + + r = (gint) floorf (255.0f * ar + 0.5f); + g = (gint) floorf (255.0f * ag + 0.5f); + b = (gint) floorf (255.0f * ab + 0.5f); + a = (gint) floorf (255.0f * aa + 0.5f); + + dst[0] = MAX (0, MIN (255, b)); + dst[1] = MAX (0, MIN (255, g)); + dst[2] = MAX (0, MIN (255, r)); + dst[3] = MAX (0, MIN (255, a)); +} + + +/* + * Compression Functions + */ + +static void +get_min_max_YCoCg (const guchar *block, + guchar *mincolor, + guchar *maxcolor) +{ + gint i; + + mincolor[2] = mincolor[1] = 255; + maxcolor[2] = maxcolor[1] = 0; + + for (i = 0; i < 16; ++i) + { + if (block[4 * i + 2] < mincolor[2]) mincolor[2] = block[4 * i + 2]; + if (block[4 * i + 1] < mincolor[1]) mincolor[1] = block[4 * i + 1]; + if (block[4 * i + 2] > maxcolor[2]) maxcolor[2] = block[4 * i + 2]; + if (block[4 * i + 1] > maxcolor[1]) maxcolor[1] = block[4 * i + 1]; + } +} + +static void +scale_YCoCg (guchar *block, + guchar *mincolor, + guchar *maxcolor) +{ + const gint s0 = 128 / 2 - 1; + const gint s1 = 128 / 4 - 1; + gint m0, m1, m2, m3; + gint mask0, mask1, scale; + gint i; + + m0 = abs (mincolor[2] - 128); + m1 = abs (mincolor[1] - 128); + m2 = abs (maxcolor[2] - 128); + m3 = abs (maxcolor[1] - 128); + + if (m1 > m0) m0 = m1; + if (m3 > m2) m2 = m3; + if (m2 > m0) m0 = m2; + + mask0 = -(m0 <= s0); + mask1 = -(m0 <= s1); + scale = 1 + (1 & mask0) + (2 & mask1); + + mincolor[2] = (mincolor[2] - 128) * scale + 128; + mincolor[1] = (mincolor[1] - 128) * scale + 128; + mincolor[0] = (scale - 1) << 3; + + maxcolor[2] = (maxcolor[2] - 128) * scale + 128; + maxcolor[1] = (maxcolor[1] - 128) * scale + 128; + maxcolor[0] = (scale - 1) << 3; + + for (i = 0; i < 16; ++i) + { + block[i * 4 + 2] = (block[i * 4 + 2] - 128) * scale + 128; + block[i * 4 + 1] = (block[i * 4 + 1] - 128) * scale + 128; + } +} + +#define INSET_SHIFT 4 + +static void +inset_bbox_YCoCg (guchar *mincolor, + guchar *maxcolor) +{ + gint inset[4], mini[4], maxi[4]; + + inset[2] = (maxcolor[2] - mincolor[2]) - ((1 << (INSET_SHIFT - 1)) - 1); + inset[1] = (maxcolor[1] - mincolor[1]) - ((1 << (INSET_SHIFT - 1)) - 1); + + mini[2] = ((mincolor[2] << INSET_SHIFT) + inset[2]) >> INSET_SHIFT; + mini[1] = ((mincolor[1] << INSET_SHIFT) + inset[1]) >> INSET_SHIFT; + + maxi[2] = ((maxcolor[2] << INSET_SHIFT) - inset[2]) >> INSET_SHIFT; + maxi[1] = ((maxcolor[1] << INSET_SHIFT) - inset[1]) >> INSET_SHIFT; + + mini[2] = (mini[2] >= 0) ? mini[2] : 0; + mini[1] = (mini[1] >= 0) ? mini[1] : 0; + + maxi[2] = (maxi[2] <= 255) ? maxi[2] : 255; + maxi[1] = (maxi[1] <= 255) ? maxi[1] : 255; + + mincolor[2] = (mini[2] & 0xf8) | (mini[2] >> 5); + mincolor[1] = (mini[1] & 0xfc) | (mini[1] >> 6); + + maxcolor[2] = (maxi[2] & 0xf8) | (maxi[2] >> 5); + maxcolor[1] = (maxi[1] & 0xfc) | (maxi[1] >> 6); +} + +static void +select_diagonal_YCoCg (const guchar *block, + guchar *mincolor, + guchar *maxcolor) +{ + guchar mid0, mid1, side, mask, b0, b1, c0, c1; + gint i; + + mid0 = ((gint) mincolor[2] + maxcolor[2] + 1) >> 1; + mid1 = ((gint) mincolor[1] + maxcolor[1] + 1) >> 1; + + side = 0; + for (i = 0; i < 16; ++i) + { + b0 = block[i * 4 + 2] >= mid0; + b1 = block[i * 4 + 1] >= mid1; + side += (b0 ^ b1); + } + + mask = -(side > 8); + mask &= -(mincolor[2] != maxcolor[2]); + + c0 = mincolor[1]; + c1 = maxcolor[1]; + + c0 ^= c1; + c1 ^= c0 & mask; + c0 ^= c1; + + mincolor[1] = c0; + maxcolor[1] = c1; +} + +void +encode_YCoCg_block (guchar *dst, + guchar *block) +{ + guchar colors[4][3], *maxcolor, *mincolor; + guint mask; + gint c0, c1, d0, d1, d2, d3; + gint b0, b1, b2, b3, b4; + gint x0, x1, x2; + gint i, idx; + + maxcolor = &colors[0][0]; + mincolor = &colors[1][0]; + + get_min_max_YCoCg (block, mincolor, maxcolor); + scale_YCoCg (block, mincolor, maxcolor); + inset_bbox_YCoCg (mincolor, maxcolor); + select_diagonal_YCoCg (block, mincolor, maxcolor); + + colors[2][0] = (2 * maxcolor[0] + mincolor[0]) / 3; + colors[2][1] = (2 * maxcolor[1] + mincolor[1]) / 3; + colors[2][2] = (2 * maxcolor[2] + mincolor[2]) / 3; + + colors[3][0] = (2 * mincolor[0] + maxcolor[0]) / 3; + colors[3][1] = (2 * mincolor[1] + maxcolor[1]) / 3; + colors[3][2] = (2 * mincolor[2] + maxcolor[2]) / 3; + + mask = 0; + + for (i = 0; i < 16; ++i) + { + c0 = block[4 * i + 2]; + c1 = block[4 * i + 1]; + + d0 = abs (colors[0][2] - c0) + abs (colors[0][1] - c1); + d1 = abs (colors[1][2] - c0) + abs (colors[1][1] - c1); + d2 = abs (colors[2][2] - c0) + abs (colors[2][1] - c1); + d3 = abs (colors[3][2] - c0) + abs (colors[3][1] - c1); + + b0 = d0 > d3; + b1 = d1 > d2; + b2 = d0 > d2; + b3 = d1 > d3; + b4 = d2 > d3; + + x0 = b1 & b2; + x1 = b0 & b3; + x2 = b0 & b4; + + idx = (x2 | ((x0 | x1) << 1)); + + mask |= idx << (2 * i); + } + + PUTL16 (dst + 0, (mul8bit (maxcolor[2], 31) << 11) | + (mul8bit (maxcolor[1], 63) << 5) | + (mul8bit (maxcolor[0], 31) )); + PUTL16 (dst + 2, (mul8bit (mincolor[2], 31) << 11) | + (mul8bit (mincolor[1], 63) << 5) | + (mul8bit (mincolor[0], 31) )); + PUTL32 (dst + 4, mask); +} diff --git a/plug-ins/file-dds/misc.h b/plug-ins/file-dds/misc.h index 02e6b7b7e0..1b4f5eb0e0 100644 --- a/plug-ins/file-dds/misc.h +++ b/plug-ins/file-dds/misc.h @@ -21,11 +21,26 @@ #ifndef __MISC_H__ #define __MISC_H__ -void decode_ycocg_image (GimpDrawable *drawable, - gboolean shadow); -void decode_ycocg_scaled_image (GimpDrawable *drawable, - gboolean shadow); -void decode_alpha_exp_image (GimpDrawable *drawable, - gboolean shadow); + +void decode_ycocg (GimpDrawable *drawable); + +void decode_ycocg_scaled (GimpDrawable *drawable); + +void decode_alpha_exponent (GimpDrawable *drawable); + +void encode_ycocg (guchar *dst, + gint r, + gint g, + gint b); + +void encode_alpha_exponent (guchar *dst, + gint r, + gint g, + gint b, + gint a); + +void encode_YCoCg_block (guchar *dst, + guchar *block); + #endif /* __MISC_H__ */