[gimp-dds] / tags / release-2.0 / dxt.c Repository:
ViewVC logotype

View of /tags/release-2.0/dxt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 80 - (download) (as text) (annotate)
Fri Nov 2 23:28:56 2007 UTC (2 years ago) by cocidius
File size: 25782 byte(s)
I think i got it this time... Create release 2.0 tag.
    1 /*
    2    DDS GIMP plugin
    3 
    4    Copyright (C) 2004 Shawn Kirst <skirst@fuse.net>,
    5    with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
    6 
    7    This program is free software; you can redistribute it and/or
    8    modify it under the terms of the GNU General Public
    9    License as published by the Free Software Foundation; either
   10    version 2 of the License, or (at your option) any later version.
   11 
   12    This program is distributed in the hope that it will be useful,
   13    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15    General Public License for more details.
   16 
   17    You should have received a copy of the GNU General Public License
   18    along with this program; see the file COPYING.  If not, write to
   19    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   20    Boston, MA 02111-1307, USA.
   21 */
   22 
   23 #include <stdlib.h>
   24 #include <string.h>
   25 #include <math.h>
   26 #include <glib.h>
   27 
   28 #include "dds.h"
   29 #include "endian.h"
   30 #include "mipmap.h"
   31 
   32 #include "dxt_tables.h"
   33 
   34 #ifndef MIN
   35 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
   36 #endif
   37 #ifndef MAX
   38 #define MAX(a, b)  ((a) > (b) ? (a) : (b))
   39 #endif
   40 
   41 /* extract 4x4 BGRA block */
   42 static void extract_block(const unsigned char *src, int w,
   43                           unsigned char *block)
   44 {
   45    int i;
   46    for(i = 0; i < 4; ++i)
   47    {
   48       memcpy(&block[i * 4 * 4], src, 4 * 4);
   49       src += w * 4;
   50    }
   51 }
   52 
   53 static inline int mul8bit(int a, int b)
   54 {
   55    int t = a * b + 128;
   56    return((t + (t >> 8)) >> 8);
   57 }
   58 
   59 /* pack BGR8 to RGB565 */
   60 static inline unsigned short pack_rgb565(const unsigned char *c)
   61 {
   62    return(((c[2] >> 3) << 11) | ((c[1] >> 2) << 5) | (c[0] >> 3));
   63 }
   64 
   65 /* unpack RGB565 to BGR */
   66 static void unpack_rgb565(unsigned char *dst, unsigned short v)
   67 {
   68    int rv = (v & 0xf800) >> 11;
   69    int gv = (v & 0x07e0) >>  5;
   70    int bv = (v & 0x001f) >>  0;
   71 
   72    dst[0] = expand5[bv];
   73    dst[1] = expand6[gv];
   74    dst[2] = expand5[rv];
   75 }
   76 
   77 static void lerp_rgb(unsigned char *dst, unsigned char *a, unsigned char *b, int f)
   78 {
   79    dst[0] = a[0] + mul8bit(b[0] - a[0], f);
   80    dst[1] = a[1] + mul8bit(b[1] - a[1], f);
   81    dst[2] = a[2] + mul8bit(b[2] - a[2], f);
   82 }
   83 
   84 static void dither_block(unsigned char *dst, const unsigned char *block)
   85 {
   86    int err[8], *ep1 = err, *ep2 = err + 4, *tmp;
   87    int c, y;
   88    unsigned char *bp, *dp;
   89    const unsigned char *quant;
   90 
   91    for(c = 0; c < 3; ++c)
   92    {
   93       bp = (unsigned char *)block;
   94       dp = dst;
   95       quant = (c == 1) ? quantG + 8 : quantRB + 8;
   96 
   97       bp += c;
   98       dp += c;
   99 
  100       memset(err, 0, sizeof(err));
  101 
  102       for(y = 0; y < 4; ++y)
  103       {
  104          dp[ 0] = quant[bp[ 0] + ((3 * ep2[1] + 5 * ep2[0]) >> 4)];
  105          ep1[0] = bp[ 0] - dp[ 0];
  106 
  107          dp[ 4] = quant[bp[ 4] + ((7 * ep1[0] + 3 * ep2[2] + 5 * ep2[1] + ep2[0]) >> 4)];
  108          ep1[1] = bp[ 4] - dp[ 4];
  109 
  110          dp[ 8] = quant[bp[ 8] + ((7 * ep1[1] + 3 * ep2[3] + 5 * ep2[2] + ep2[1]) >> 4)];
  111          ep1[2] = bp[ 8] - dp[ 8];
  112 
  113          dp[12] = quant[bp[12] + ((7 * ep1[2] + 5 * ep2[3] + ep2[2]) >> 4)];
  114          ep1[3] = bp[12] - dp[12];
  115 
  116          tmp = ep1;
  117          ep1 = ep2;
  118          ep2 = tmp;
  119 
  120          bp += 16;
  121          dp += 16;
  122       }
  123    }
  124 }
  125 
  126 static unsigned int match_colors_block(const unsigned char *block,
  127                                        const unsigned char *color,
  128                                        int dither)
  129 {
  130    unsigned int mask = 0;
  131    int dirb = color[0] - color[4];
  132    int dirg = color[1] - color[5];
  133    int dirr = color[2] - color[6];
  134    int dots[16], stops[4];
  135    int c0pt, halfpt, c3pt, dot;
  136    int i;
  137 
  138    for(i = 0; i < 16; ++i)
  139       dots[i] = block[4 * i] * dirb + block[4 * i + 1] * dirg + block[4 * i + 2] * dirr;
  140 
  141    for(i = 0; i < 4; ++i)
  142       stops[i] = color[4 * i] * dirb + color[4 * i + 1] * dirg + color[4 * i + 2] * dirr;
  143 
  144    c0pt = (stops[1] + stops[3]) >> 1;
  145    halfpt = (stops[3] + stops[2]) >> 1;
  146    c3pt = (stops[2] + stops[0]) >> 1;
  147 
  148    if(!dither)
  149    {
  150       for(i = 15; i >= 0; --i)
  151       {
  152          mask <<= 2;
  153          dot = dots[i];
  154 
  155          if(dot < halfpt)
  156             mask |= (dot < c0pt) ? 1 : 3;
  157          else
  158             mask |= (dot < c3pt) ? 2 : 0;
  159       }
  160    }
  161    else
  162    {
  163       int err[8], *ep1 = err, *ep2 = err + 4, *tmp;
  164       int *dp = dots, y, lmask, step;
  165 
  166       c0pt <<= 4;
  167       halfpt <<= 4;
  168       c3pt <<= 4;
  169 
  170       memset(err, 0, sizeof(err));
  171 
  172       for(y = 0; y < 4; ++y)
  173       {
  174          dot = (dp[0] << 4) + (3 * ep2[1] + 5 * ep2[0]);
  175          if(dot < halfpt)
  176             step = (dot < c0pt) ? 1 : 3;
  177          else
  178             step = (dot < c3pt) ? 2 : 0;
  179 
  180          ep1[0] = dp[0] - stops[step];
  181          lmask = step;
  182 
  183          dot = (dp[1] << 4) + (7 * ep1[0] + 3 * ep2[2] + 5 * ep2[1] + ep2[0]);
  184          if(dot < halfpt)
  185             step = (dot < c0pt) ? 1 : 3;
  186          else
  187             step = (dot < c3pt) ? 2 : 0;
  188 
  189          ep1[1] = dp[1] - stops[step];
  190          lmask |= step << 2;
  191 
  192          dot = (dp[2] << 4) + (7 * ep1[1] + 3 * ep2[3] + 5 * ep2[2] + ep2[1]);
  193          if(dot < halfpt)
  194             step = (dot < c0pt) ? 1 : 3;
  195          else
  196             step = (dot < c3pt) ? 2 : 0;
  197 
  198          ep1[2] = dp[2] - stops[step];
  199          lmask |= step << 4;
  200 
  201          dot = (dp[3] << 4) + (7 * ep1[2] + 5 * ep2[3] + ep2[2]);
  202          if(dot < halfpt)
  203             step = (dot < c0pt) ? 1 : 3;
  204          else
  205             step = (dot < c3pt) ? 2 : 0;
  206 
  207          ep1[3] = dp[3] - stops[step];
  208          lmask |= step << 6;
  209 
  210          tmp = ep1;
  211          ep1 = ep2;
  212          ep2 = tmp;
  213 
  214          dp += 4;
  215          mask |= lmask << (y * 8);
  216       }
  217    }
  218 
  219    return(mask);
  220 }
  221 
  222 static void optimize_colors_block(const unsigned char *block,
  223                                   unsigned short *max16, unsigned short *min16)
  224 {
  225    static const int niterpow = 4;
  226 
  227    int mu[3], mn[3], mx[3];
  228    int i, c, r, g, b, dot, iter;
  229    int muv, mnv, mxv, mnd, mxd;
  230    int cov[6];
  231    unsigned char *bp, mnc[3], mxc[3];
  232    float covf[6], vfr, vfg, vfb, magn;
  233    float fr, fg, fb;
  234 
  235    for(c = 0; c < 3; ++c)
  236    {
  237       bp = (unsigned char *)block + c;
  238 
  239       muv = mnv = mxv = bp[0];
  240       for(i = 4; i < 64; i += 4)
  241       {
  242          muv += bp[i];
  243          if(mnv > bp[i]) mnv = bp[i];
  244          if(mxv < bp[i]) mxv = bp[i];
  245       }
  246 
  247       mu[c] = (muv + 8) >> 4;
  248       mn[c] = mnv;
  249       mx[c] = mxv;
  250    }
  251 
  252    memset(cov, 0, sizeof(cov));
  253 
  254    for(i = 0; i < 16; ++i)
  255    {
  256       b = block[4 * i + 0] - mu[0];
  257       g = block[4 * i + 1] - mu[1];
  258       r = block[4 * i + 2] - mu[3];
  259 
  260       cov[0] += r * r;
  261       cov[1] += r * g;
  262       cov[2] += r * b;
  263       cov[3] += g * g;
  264       cov[4] += g * b;
  265       cov[5] += b * b;
  266    }
  267 
  268    for(i = 0; i < 6; ++i)
  269       covf[i] = cov[i] / 255.0f;
  270 
  271    vfb = mx[0] - mn[0];
  272    vfg = mx[1] - mn[1];
  273    vfr = mx[2] - mn[2];
  274 
  275    for(iter = 0; iter < niterpow; ++iter)
  276    {
  277       fr = vfr * covf[0] + vfg * covf[1] + vfb * covf[2];
  278       fg = vfr * covf[1] + vfg * covf[3] + vfb * covf[4];
  279       fb = vfr * covf[2] + vfg * covf[4] + vfb * covf[5];
  280 
  281       vfr = fr;
  282       vfg = fg;
  283       vfb = fb;
  284    }
  285 
  286    vfr = fabsf(vfr);
  287    vfg = fabsf(vfg);
  288    vfb = fabsf(vfb);
  289 
  290    magn = MAX(MAX(vfr, vfg), vfb);
  291 
  292    if(magn < 4.0)
  293    {
  294       r = 148;
  295       g = 300;
  296       b = 58;
  297    }
  298    else
  299    {
  300       magn = 512.0f / magn;
  301       r = (int)(vfr * magn);
  302       g = (int)(vfg * magn);
  303       b = (int)(vfb * magn);
  304    }
  305 
  306    mnd =  0x7fffffff;
  307    mxd = -0x7fffffff;
  308 
  309    for(i = 0; i < 16; ++i)
  310    {
  311       dot = block[4 * i] * b + block[4 * i + 1] * g + block[4 * i + 2] * r;
  312 
  313       if(dot < mnd)
  314       {
  315          mnd = dot;
  316          memcpy(mnc, &block[4 * i], 3);
  317       }
  318       if(dot > mxd)
  319       {
  320          mxd = dot;
  321          memcpy(mxc, &block[4 * i], 3);
  322       }
  323    }
  324 
  325    *max16 = pack_rgb565(mxc);
  326    *min16 = pack_rgb565(mnc);
  327 }
  328 
  329 static int refine_block(const unsigned char *block,
  330                         unsigned short *max16, unsigned short *min16,
  331                         unsigned int mask)
  332 {
  333    static const int w1tab[4] = {3, 0, 2, 1};
  334    static const int prods[4] = {0x090000, 0x000900, 0x040102, 0x010402};
  335    int akku = 0;
  336    int At1_r, At1_g, At1_b;
  337    int At2_r, At2_g, At2_b;
  338    unsigned int cm = mask;
  339    int i, step, w1, r, g, b;
  340    int xx, yy, xy;
  341    float frb, fg;
  342    unsigned short v, oldmin, oldmax;
  343    int s;
  344 
  345    At1_r = At1_g = At1_b = 0;
  346    At2_r = At2_g = At2_b = 0;
  347 
  348    for(i = 0; i < 16; ++i, cm >>= 2)
  349    {
  350       step = cm & 3;
  351       w1 = w1tab[step];
  352       r = block[4 * i + 2];
  353       g = block[4 * i + 1];
  354       b = block[4 * i + 0];
  355 
  356       akku  += prods[step];
  357       At1_r += w1 * r;
  358       At1_g += w1 * g;
  359       At1_b += w1 * b;
  360       At2_r += r;
  361       At2_g += g;
  362       At2_b += b;
  363    }
  364 
  365    At2_r = 3 * At2_r - At1_r;
  366    At2_g = 3 * At2_g - At1_g;
  367    At2_b = 3 * At2_b - At1_b;
  368 
  369    xx = akku >> 16;
  370    yy = (akku >> 8) & 0xff;
  371    xy = (akku >> 0) & 0xff;
  372 
  373    if(!yy || !xx || xx * yy == xy * xy)
  374       return(0);
  375 
  376    frb = 3.0f * 31.0f / 255.0f / (xx * yy - xy * xy);
  377    fg = frb * 63.0f / 31.0f;
  378 
  379    oldmin = *min16;
  380    oldmax = *max16;
  381 
  382    s = (int)((At1_r * yy - At2_r * xy) * frb + 0.5f);
  383    if(s < 0) s = 0;
  384    if(s > 31) s = 31;
  385    v = s << 11;
  386    s = (int)((At1_g * yy - At2_g * xy) * fg + 0.5f);
  387    if(s < 0) s = 0;
  388    if(s > 63) s = 63;
  389    v |= s << 5;
  390    s = (int)((At1_b * yy - At2_b * xy) * frb + 0.5f);
  391    if(s < 0) s = 0;
  392    if(s > 31) s = 31;
  393    v |= s;
  394    *max16 = v;
  395 
  396    s = (int)((At2_r * xx - At1_r * xy) * frb + 0.5f);
  397    if(s < 0) s = 0;
  398    if(s > 31) s = 31;
  399    v = s << 11;
  400    s = (int)((At2_g * xx - At1_g * xy) * fg + 0.5f);
  401    if(s < 0) s = 0;
  402    if(s > 63) s = 63;
  403    v |= s << 5;
  404    s = (int)((At2_b * xx - At1_b * xy) * frb + 0.5f);
  405    if(s < 0) s = 0;
  406    if(s > 31) s = 31;
  407    v |= s;
  408    *min16 = v;
  409 
  410    return(oldmin != *min16 || oldmax != *max16);
  411 }
  412 
  413 static int color_distance(const unsigned char *c0,
  414                           const unsigned char *c1)
  415 {
  416    return(((c0[0] - c1[0]) * (c0[0] - c1[0])) +
  417           ((c0[1] - c1[1]) * (c0[1] - c1[1])) +
  418           ((c0[2] - c1[2]) * (c0[2] - c1[2])));
  419 }
  420 
  421 static int luminance(const unsigned char *c)
  422 {
  423    return((c[2] * 54 + c[1] * 182 + c[0] * 20) >> 8);
  424 }
  425 
  426 static void get_min_max_colors_distance(const unsigned char *block,
  427                                         unsigned short *max16,
  428                                         unsigned short *min16)
  429 {
  430    int i, j, dist, maxdist = -1;
  431    unsigned short c0 = 0, c1 = 0;
  432 
  433    for(i = 0; i < 64 - 4; i += 4)
  434    {
  435       for(j = i + 4; j < 64; j += 4)
  436       {
  437          dist = color_distance(&block[i], &block[j]);
  438          if(dist > maxdist)
  439          {
  440             maxdist = dist;
  441             c0 = pack_rgb565(block + i);
  442             c1 = pack_rgb565(block + j);
  443          }
  444       }
  445    }
  446 
  447    *max16 = MAX(c0, c1);
  448    *min16 = MIN(c0, c1);
  449 }
  450 
  451 static void get_min_max_colors_luminance(const unsigned char *block,
  452                                          unsigned short *max16,
  453                                          unsigned short *min16)
  454 {
  455    int i, lum, minlum = 0x7fffffff, maxlum = -0x7fffffff;
  456    unsigned char mn[3], mx[3];
  457 
  458    for(i = 0; i < 16; ++i)
  459    {
  460       lum = luminance(&block[4 * i]);
  461       if(lum > maxlum)
  462       {
  463          maxlum = lum;
  464          memcpy(mx, &block[4 * i], 3);
  465       }
  466       if(lum < minlum)
  467       {
  468          minlum = lum;
  469          memcpy(mn, &block[4 * i], 3);
  470       }
  471    }
  472 
  473    *max16 = pack_rgb565(mx);
  474    *min16 = pack_rgb565(mn);
  475 }
  476 
  477 #define INSET_SHIFT  4
  478 
  479 static void get_min_max_colors_inset_bbox(const unsigned char *block,
  480                                           unsigned short *max16,
  481                                           unsigned short *min16)
  482 {
  483    int i;
  484    unsigned char inset[3], mx[3], mn[3];
  485 
  486    mn[0] = mn[1] = mn[2] = 255;
  487    mx[0] = mx[1] = mx[2] = 3;
  488 
  489    for(i = 0; i < 16; ++i)
  490    {
  491       if(block[4 * i + 0] < mn[0]) mn[0] = block[4 * i + 0];
  492       if(block[4 * i + 1] < mn[1]) mn[1] = block[4 * i + 1];
  493       if(block[4 * i + 2] < mn[2]) mn[2] = block[4 * i + 2];
  494       if(block[4 * i + 0] > mx[0]) mx[0] = block[4 * i + 0];
  495       if(block[4 * i + 1] > mx[1]) mx[1] = block[4 * i + 1];
  496       if(block[4 * i + 2] > mx[2]) mx[2] = block[4 * i + 2];
  497    }
  498 
  499    inset[0] = (mx[0] - mn[0]) >> INSET_SHIFT;
  500    inset[1] = (mx[1] - mn[1]) >> INSET_SHIFT;
  501    inset[2] = (mx[2] - mn[2]) >> INSET_SHIFT;
  502 
  503    mn[0] = (mn[0] + inset[0] <= 255) ? mn[0] + inset[0] : 255;
  504    mn[1] = (mn[1] + inset[1] <= 255) ? mn[1] + inset[1] : 255;
  505    mn[2] = (mn[2] + inset[2] <= 255) ? mn[2] + inset[2] : 255;
  506 
  507    mx[0] = (mx[0] >= inset[0]) ? mx[0] - inset[0] : 0;
  508    mx[1] = (mx[1] >= inset[1]) ? mx[1] - inset[1] : 0;
  509    mx[2] = (mx[2] >= inset[2]) ? mx[2] - inset[2] : 0;
  510 
  511    *min16 = pack_rgb565(mn);
  512    *max16 = pack_rgb565(mx);
  513 }
  514 
  515 static void eval_colors(unsigned char *color,
  516                         unsigned short c0, unsigned short c1)
  517 {
  518    unpack_rgb565(&color[0], c0);
  519    unpack_rgb565(&color[4], c1);
  520    if(c0 > c1)
  521    {
  522       lerp_rgb(&color[ 8], &color[0], &color[4], 0x55);
  523       lerp_rgb(&color[12], &color[0], &color[4], 0xaa);
  524    }
  525    else
  526    {
  527       color[ 8] = (color[0] + color[4]) >> 1;
  528       color[ 9] = (color[1] + color[5]) >> 1;
  529       color[10] = (color[3] + color[8]) >> 1;
  530 
  531       color[12] = color[13] = color[14] = 0;
  532    }
  533 }
  534 
  535 static void encode_color_block(unsigned char *dst,
  536                                const unsigned char *block,
  537                                int type, int dither)
  538 {
  539    unsigned char dblock[64], color[16];
  540    unsigned short min16, max16;
  541    unsigned int v, mn, mx, mask;
  542    int i;
  543 
  544    mn = mx = GETL32(block);
  545    for(i = 0; i < 16; ++i)
  546    {
  547       v = GETL32(&block[4 * i]);
  548       if(v > mx) mx = v;
  549       if(v < mn) mn = v;
  550    }
  551 
  552    if(mn != mx)
  553    {
  554       if(dither)
  555          dither_block(dblock, block);
  556 
  557       switch(type)
  558       {
  559          case DDS_COLOR_DISTANCE:
  560             get_min_max_colors_distance(dither ? dblock : block, &max16, &min16);
  561             break;
  562          case DDS_COLOR_LUMINANCE:
  563             get_min_max_colors_luminance(dither ? dblock : block, &max16, &min16);
  564             break;
  565          case DDS_COLOR_INSET_BBOX:
  566             get_min_max_colors_inset_bbox(dither ? dblock : block, &max16, &min16);
  567             break;
  568          default:
  569             optimize_colors_block(dither ? dblock : block, &max16, &min16);
  570             if(max16 != min16)
  571             {
  572                eval_colors(color, max16, min16);
  573                mask = match_colors_block(block, color, dither != 0);
  574             }
  575             else
  576                mask = 0;
  577 
  578             refine_block(dither ? dblock : block, &max16, &min16, mask);
  579             break;
  580       }
  581 
  582       if(max16 != min16)
  583       {
  584          eval_colors(color, max16, min16);
  585          mask = match_colors_block(block, color, dither != 0);
  586       }
  587       else
  588          mask = 0;
  589    }
  590    else
  591    {
  592       mask = 0xaaaaaaaa;
  593       max16 = (omatch5[block[2]][0] << 11) |
  594               (omatch6[block[1]][0] <<  5) |
  595               (omatch5[block[0]][0]      );
  596       min16 = (omatch5[block[2]][1] << 11) |
  597               (omatch6[block[1]][1] <<  5) |
  598               (omatch5[block[0]][1]      );
  599    }
  600 
  601    if(max16 < min16)
  602    {
  603       max16 ^= min16 ^= max16 ^= min16;
  604       mask ^= 0x55555555;
  605    }
  606 
  607    PUTL16(&dst[0], max16);
  608    PUTL16(&dst[2], min16);
  609    PUTL32(&dst[4], mask);
  610 }
  611 
  612 static void encode_alpha_block_DXT3(unsigned char *dst,
  613                                     const unsigned char *block)
  614 {
  615    int i, a1, a2;
  616 
  617    block += 3;
  618 
  619    for(i = 0; i < 8; ++i)
  620    {
  621       a1 = block[8 * i + 0];
  622       a2 = block[8 * i + 4];
  623       *dst++ = ((a2 >> 4) << 4) | (a1 >> 4);
  624    }
  625 }
  626 
  627 static void encode_alpha_block_DXT5(unsigned char *dst,
  628                                     const unsigned char *block)
  629 {
  630    int i, v, mn, mx;
  631    int dist, bias, dist2, dist4, bits, mask;
  632    int a, idx, t;
  633 
  634    block += 3;
  635 
  636    mn = mx = block[0];
  637    for(i = 0; i < 16; ++i)
  638    {
  639       v = block[4 * i];
  640       if(v > mx) mx = v;
  641       if(v < mn) mn = v;
  642    }
  643 
  644    *dst++ = mx;
  645    *dst++ = mn;
  646 
  647    dist = mx - mn;
  648    bias = mn * 7 - (dist >> 1);
  649    dist4 = dist * 4;
  650    dist2 = dist * 2;
  651    bits = 0;
  652    mask = 0;
  653 
  654    for(i = 0; i < 16; ++i)
  655    {
  656       a = block[4 * i] * 7 - bias;
  657 
  658       t = (dist4 - a) >> 31; idx =  t & 4; a -= dist4 & t;
  659       t = (dist2 - a) >> 31; idx += t & 2; a -= dist2 & t;
  660       t = (dist  - a) >> 31; idx += t & 1;
  661 
  662       idx = -idx & 7;
  663       idx ^= (2 > idx);
  664 
  665       mask |= idx << bits;
  666       if((bits += 3) >= 8)
  667       {
  668          *dst++ = mask;
  669          mask >>= 8;
  670          bits -= 8;
  671       }
  672    }
  673 }
  674 
  675 static void compress_DXT1(unsigned char *dst, const unsigned char *src,
  676                           int w, int h, int type, int dither)
  677 {
  678    unsigned char block[64];
  679    int x, y;
  680 
  681    for(y = 0; y < h; y += 4, src += w * 4 * 4)
  682    {
  683       for(x = 0; x < w; x += 4)
  684       {
  685          extract_block(src + x * 4, w, block);
  686          encode_color_block(dst, block, type, dither);
  687          dst += 8;
  688       }
  689    }
  690 }
  691 
  692 static void compress_DXT3(unsigned char *dst, const unsigned char *src,
  693                           int w, int h, int type, int dither)
  694 {
  695    unsigned char block[64];
  696    int x, y;
  697 
  698    for(y = 0; y < h; y += 4, src += w * 4 * 4)
  699    {
  700       for(x = 0; x < w; x += 4)
  701       {
  702          extract_block(src + x * 4, w, block);
  703          encode_alpha_block_DXT3(dst, block);
  704          encode_color_block(dst + 8, block, type, dither);
  705          dst += 16;
  706       }
  707    }
  708 }
  709 
  710 static void compress_DXT5(unsigned char *dst, const unsigned char *src,
  711                           int w, int h, int type, int dither)
  712 {
  713    unsigned char block[64];
  714    int x, y;
  715 
  716    for(y = 0; y < h; y += 4, src += w * 4 * 4)
  717    {
  718       for(x = 0; x < w; x += 4)
  719       {
  720          extract_block(src + x * 4, w, block);
  721          encode_alpha_block_DXT5(dst, block);
  722          encode_color_block(dst + 8, block, type, dither);
  723          dst += 16;
  724       }
  725    }
  726 }
  727 
  728 static void compress_BC4(unsigned char *dst, const unsigned char *src,
  729                          int w, int h)
  730 {
  731    unsigned char block[64];
  732    int x, y;
  733 
  734    for(y = 0; y < h; y += 4, src += w * 4 * 4)
  735    {
  736       for(x = 0; x < w; x += 4)
  737       {
  738          extract_block(src + x * 4, w, block);
  739          encode_alpha_block_DXT5(dst, block - 1);
  740          dst += 8;
  741       }
  742    }
  743 }
  744 
  745 static void compress_BC5(unsigned char *dst, const unsigned char *src,
  746                          int w, int h)
  747 {
  748    unsigned char block[64];
  749    int x, y;
  750 
  751    for(y = 0; y < h; y += 4, src += w * 4 * 4)
  752    {
  753       for(x = 0; x < w; x += 4)
  754       {
  755          extract_block(src + x * 4, w, block);
  756          encode_alpha_block_DXT5(dst, block - 2);
  757          encode_alpha_block_DXT5(dst + 8, block - 1);
  758          dst += 16;
  759       }
  760    }
  761 }
  762 
  763 int dxt_compress(unsigned char *dst, unsigned char *src, int format,
  764                  unsigned int width, unsigned int height, int bpp,
  765                  int mipmaps, int type, int dither)
  766 {
  767    int i, size, w, h;
  768    unsigned int offset;
  769    unsigned char *tmp;
  770    int j;
  771    unsigned char *tmp2, *s;
  772 
  773    if(!(IS_POT(width) && IS_POT(height)))
  774       return(0);
  775 
  776    size = get_mipmapped_size(width, height, bpp, 0, mipmaps,
  777                              DDS_COMPRESS_NONE);
  778    tmp = g_malloc(size);
  779    generate_mipmaps(tmp, src, width, height, bpp, 0, mipmaps);
  780 
  781    if(bpp == 1)
  782    {
  783       /* grayscale promoted to BGRA */
  784 
  785       size = get_mipmapped_size(width, height, 4, 0, mipmaps,
  786                                 DDS_COMPRESS_NONE);
  787       tmp2 = g_malloc(size);
  788 
  789       for(i = j = 0; j < size; ++i, j += 4)
  790       {
  791          tmp2[j + 0] = tmp[i];
  792          tmp2[j + 1] = tmp[i];
  793          tmp2[j + 2] = tmp[i];
  794          tmp2[j + 3] = 255;
  795       }
  796 
  797       g_free(tmp);
  798       tmp = tmp2;
  799       bpp = 4;
  800    }
  801    else if(bpp == 2)
  802    {
  803       /* gray-alpha promoted to BGRA */
  804 
  805       size = get_mipmapped_size(width, height, 4, 0, mipmaps,
  806                                 DDS_COMPRESS_NONE);
  807       tmp2 = g_malloc(size);
  808 
  809       for(i = j = 0; j < size; i += 2, j += 4)
  810       {
  811          tmp2[j + 0] = tmp[i];
  812          tmp2[j + 1] = tmp[i];
  813          tmp2[j + 2] = tmp[i];
  814          tmp2[j + 3] = tmp[i + 1];
  815       }
  816 
  817       g_free(tmp);
  818       tmp = tmp2;
  819       bpp = 4;
  820    }
  821    else if(bpp == 3)
  822    {
  823       size = get_mipmapped_size(width, height, 4, 0, mipmaps,
  824                                 DDS_COMPRESS_NONE);
  825       tmp2 = g_malloc(size);
  826 
  827       for(i = j = 0; j < size; i += 3, j += 4)
  828       {
  829          tmp2[j + 0] = tmp[i + 0];
  830          tmp2[j + 1] = tmp[i + 1];
  831          tmp2[j + 2] = tmp[i + 2];
  832          tmp2[j + 3] = 255;
  833       }
  834 
  835       g_free(tmp);
  836       tmp = tmp2;
  837       bpp = 4;
  838    }
  839 
  840    offset = 0;
  841    w = width;
  842    h = height;
  843    s = tmp;
  844 
  845    for(i = 0; i < mipmaps; ++i)
  846    {
  847       switch(format)
  848       {
  849          case DDS_COMPRESS_BC1:
  850             compress_DXT1(dst + offset, s, w, h, type, dither);
  851             break;
  852          case DDS_COMPRESS_BC2:
  853             compress_DXT3(dst + offset, s, w, h, type, dither);
  854             break;
  855          case DDS_COMPRESS_BC3:
  856             compress_DXT5(dst + offset, s, w, h, type, dither);
  857             break;
  858          case DDS_COMPRESS_BC4:
  859             compress_BC4(dst + offset, s, w, h);
  860             break;
  861          case DDS_COMPRESS_BC5:
  862             compress_BC5(dst + offset, s, w, h);
  863             break;
  864       }
  865       s += (w * h * bpp);
  866       offset += get_mipmapped_size(w, h, 0, 0, 1, format);
  867       if(w > 1) w >>= 1;
  868       if(h > 1) h >>= 1;
  869    }
  870 
  871    g_free(tmp);
  872 
  873    return(1);
  874 }
  875 
  876 static void decode_color_block(unsigned char *dst, unsigned char *src,
  877                                int w, int h, int rowbytes, int format)
  878 {
  879    int i, x, y;
  880    unsigned int indexes, idx;
  881    unsigned char *d;
  882    unsigned char colors[4][3];
  883    unsigned short c0, c1;
  884 
  885    c0 = GETL16(&src[0]);
  886    c1 = GETL16(&src[2]);
  887 
  888    unpack_rgb565(colors[0], c0);
  889    unpack_rgb565(colors[1], c1);
  890 
  891    if((c0 > c1) || (format == DDS_COMPRESS_BC3))
  892    {
  893       for(i = 0; i < 3; ++i)
  894       {
  895          colors[2][i] = (2 * colors[0][i] + colors[1][i] + 1) / 3;
  896          colors[3][i] = (2 * colors[1][i] + colors[0][i] + 1) / 3;
  897       }
  898    }
  899    else
  900    {
  901       for(i = 0; i < 3; ++i)
  902       {
  903          colors[2][i] = (colors[0][i] + colors[1][i] + 1) >> 1;
  904          colors[3][i] = 255;
  905       }
  906    }
  907 
  908    src += 4;
  909    for(y = 0; y < h; ++y)
  910    {
  911       d = dst + (y * rowbytes);
  912       indexes = src[y];
  913       for(x = 0; x < w; ++x)
  914       {
  915          idx = indexes & 0x03;
  916          d[0] = colors[idx][2];
  917          d[1] = colors[idx][1];
  918          d[2] = colors[idx][0];
  919          if(format == DDS_COMPRESS_BC1)
  920             d[3] = ((c0 <= c1) && idx == 3) ? 0 : 255;
  921          indexes >>= 2;
  922          d += 4;
  923       }
  924    }
  925 }
  926 
  927 static void decode_alpha_block_DXT3(unsigned char *dst, unsigned char *src,
  928                                     int w, int h, int rowbytes)
  929 {
  930    int x, y;
  931    unsigned char *d;
  932    unsigned int bits;
  933 
  934    for(y = 0; y < h; ++y)
  935    {
  936       d = dst + (y * rowbytes);
  937       bits = GETL16(&src[2 * y]);
  938       for(x = 0; x < w; ++x)
  939       {
  940          d[0] = (bits & 0x0f) * 17;
  941          bits >>= 4;
  942          d += 4;
  943       }
  944    }
  945 }
  946 
  947 static void decode_alpha_block_DXT5(unsigned char *dst, unsigned char *src,
  948                                     int w, int h, int bpp, int rowbytes)
  949 {
  950    int x, y, code;
  951    unsigned char *d;
  952    unsigned char a0 = src[0];
  953    unsigned char a1 = src[1];
  954    unsigned long long bits = GETL64(src) >> 16;
  955 
  956    for(y = 0; y < h; ++y)
  957    {
  958       d = dst + (y * rowbytes);
  959       for(x = 0; x < w; ++x)
  960       {
  961          code = ((unsigned int)bits) & 0x07;
  962          if(code == 0)
  963             d[0] = a0;
  964          else if(code == 1)
  965             d[0] = a1;
  966          else if(a0 > a1)
  967             d[0] = ((8 - code) * a0 + (code - 1) * a1) / 7;
  968          else if(code >= 6)
  969             d[0] = (code == 6) ? 0 : 255;
  970          else
  971             d[0] = ((6 - code) * a0 + (code - 1) * a1) / 5;
  972          bits >>= 3;
  973          d += bpp;
  974       }
  975       if(w < 4) bits >>= (3 * (4 - w));
  976    }
  977 }
  978 
  979 int dxt_decompress(unsigned char *dst, unsigned char *src, int format,
  980                    unsigned int size, unsigned int width, unsigned int height,
  981                    int bpp)
  982 {
  983    unsigned char *d, *s;
  984    unsigned int x, y, sx, sy;
  985 
  986    if(!(IS_POT(width) && IS_POT(height)))
  987       return(0);
  988 
  989    sx = (width  < 4) ? width  : 4;
  990    sy = (height < 4) ? height : 4;
  991 
  992    s = src;
  993 
  994    for(y = 0; y < height; y += 4)
  995    {
  996       for(x = 0; x < width; x += 4)
  997       {
  998          d = dst + (y * width + x) * bpp;
  999          if(format == DDS_COMPRESS_BC1)
 1000          {
 1001             decode_color_block(d, s, sx, sy, width * bpp, format);
 1002             s += 8;
 1003          }
 1004          else if(format == DDS_COMPRESS_BC2)
 1005          {
 1006             decode_alpha_block_DXT3(d + 3, s, sx, sy, width * bpp);
 1007             s += 8;
 1008             decode_color_block(d, s, sx, sy, width * bpp, format);
 1009             s += 8;
 1010          }
 1011          else if(format == DDS_COMPRESS_BC3)
 1012          {
 1013             decode_alpha_block_DXT5(d + 3, s, sx, sy, bpp, width * bpp);
 1014             s += 8;
 1015             decode_color_block(d, s, sx, sy, width * bpp, format);
 1016             s += 8;
 1017          }
 1018          else if(format == DDS_COMPRESS_BC4)
 1019          {
 1020             decode_alpha_block_DXT5(d, s, sx, sy, bpp, width * bpp);
 1021             s += 8;
 1022          }
 1023          else if(format == DDS_COMPRESS_BC5)
 1024          {
 1025             decode_alpha_block_DXT5(d, s + 8, sx, sy, bpp, width * bpp);
 1026             decode_alpha_block_DXT5(d + 1, s, sx, sy, bpp, width * bpp);
 1027             s += 16;
 1028          }
 1029       }
 1030    }
 1031 
 1032    return(1);
 1033 }

ViewVC Help
Powered by ViewVC 1.0.4