2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * \file texcompress_fxt1.c
28 * GL_3DFX_texture_compression_FXT1 support.
38 #include "texcompress.h"
39 #include "texcompress_fxt1.h"
43 #if FEATURE_texture_fxt1
47 fxt1_encode (GLuint width
, GLuint height
, GLint comps
,
48 const void *source
, GLint srcRowStride
,
49 void *dest
, GLint destRowStride
);
52 fxt1_decode_1 (const void *texture
, GLint stride
,
53 GLint i
, GLint j
, GLchan
*rgba
);
57 * Store user's image in rgb_fxt1 format.
60 _mesa_texstore_rgb_fxt1(TEXSTORE_PARAMS
)
65 const GLint texWidth
= dstRowStride
* 8 / 16; /* a bit of a hack */
66 const GLchan
*tempImage
= NULL
;
68 ASSERT(dstFormat
== MESA_FORMAT_RGB_FXT1
);
69 ASSERT(dstXoffset
% 8 == 0);
70 ASSERT(dstYoffset
% 4 == 0);
71 ASSERT(dstZoffset
== 0);
73 (void) dstImageOffsets
;
75 if (srcFormat
!= GL_RGB
||
76 srcType
!= CHAN_TYPE
||
77 ctx
->_ImageTransferState
||
78 srcPacking
->SwapBytes
) {
79 /* convert image to RGB/GLchan */
80 tempImage
= _mesa_make_temp_chan_image(ctx
, dims
,
82 _mesa_get_format_base_format(dstFormat
),
83 srcWidth
, srcHeight
, srcDepth
,
84 srcFormat
, srcType
, srcAddr
,
87 return GL_FALSE
; /* out of memory */
89 srcRowStride
= 3 * srcWidth
;
93 pixels
= (const GLchan
*) srcAddr
;
94 srcRowStride
= _mesa_image_row_stride(srcPacking
, srcWidth
, srcFormat
,
95 srcType
) / sizeof(GLchan
);
98 dst
= _mesa_compressed_image_address(dstXoffset
, dstYoffset
, 0,
100 texWidth
, (GLubyte
*) dstAddr
);
102 fxt1_encode(srcWidth
, srcHeight
, 3, pixels
, srcRowStride
,
106 free((void*) tempImage
);
113 * Store user's image in rgba_fxt1 format.
116 _mesa_texstore_rgba_fxt1(TEXSTORE_PARAMS
)
118 const GLchan
*pixels
;
121 GLint texWidth
= dstRowStride
* 8 / 16; /* a bit of a hack */
122 const GLchan
*tempImage
= NULL
;
124 ASSERT(dstFormat
== MESA_FORMAT_RGBA_FXT1
);
125 ASSERT(dstXoffset
% 8 == 0);
126 ASSERT(dstYoffset
% 4 == 0);
127 ASSERT(dstZoffset
== 0);
129 (void) dstImageOffsets
;
131 if (srcFormat
!= GL_RGBA
||
132 srcType
!= CHAN_TYPE
||
133 ctx
->_ImageTransferState
||
134 srcPacking
->SwapBytes
) {
135 /* convert image to RGBA/GLchan */
136 tempImage
= _mesa_make_temp_chan_image(ctx
, dims
,
138 _mesa_get_format_base_format(dstFormat
),
139 srcWidth
, srcHeight
, srcDepth
,
140 srcFormat
, srcType
, srcAddr
,
143 return GL_FALSE
; /* out of memory */
145 srcRowStride
= 4 * srcWidth
;
149 pixels
= (const GLchan
*) srcAddr
;
150 srcRowStride
= _mesa_image_row_stride(srcPacking
, srcWidth
, srcFormat
,
151 srcType
) / sizeof(GLchan
);
154 dst
= _mesa_compressed_image_address(dstXoffset
, dstYoffset
, 0,
156 texWidth
, (GLubyte
*) dstAddr
);
158 fxt1_encode(srcWidth
, srcHeight
, 4, pixels
, srcRowStride
,
162 free((void*) tempImage
);
169 _mesa_fetch_texel_2d_f_rgba_fxt1( const struct gl_texture_image
*texImage
,
170 GLint i
, GLint j
, GLint k
, GLfloat
*texel
)
172 /* just sample as GLchan and convert to float here */
175 fxt1_decode_1(texImage
->Data
, texImage
->RowStride
, i
, j
, rgba
);
176 texel
[RCOMP
] = CHAN_TO_FLOAT(rgba
[RCOMP
]);
177 texel
[GCOMP
] = CHAN_TO_FLOAT(rgba
[GCOMP
]);
178 texel
[BCOMP
] = CHAN_TO_FLOAT(rgba
[BCOMP
]);
179 texel
[ACOMP
] = CHAN_TO_FLOAT(rgba
[ACOMP
]);
184 _mesa_fetch_texel_2d_f_rgb_fxt1( const struct gl_texture_image
*texImage
,
185 GLint i
, GLint j
, GLint k
, GLfloat
*texel
)
187 /* just sample as GLchan and convert to float here */
190 fxt1_decode_1(texImage
->Data
, texImage
->RowStride
, i
, j
, rgba
);
191 texel
[RCOMP
] = CHAN_TO_FLOAT(rgba
[RCOMP
]);
192 texel
[GCOMP
] = CHAN_TO_FLOAT(rgba
[GCOMP
]);
193 texel
[BCOMP
] = CHAN_TO_FLOAT(rgba
[BCOMP
]);
199 /***************************************************************************\
202 * The encoder was built by reversing the decoder,
203 * and is vaguely based on Texus2 by 3dfx. Note that this code
204 * is merely a proof of concept, since it is highly UNoptimized;
205 * moreover, it is sub-optimal due to initial conditions passed
206 * to Lloyd's algorithm (the interpolation modes are even worse).
207 \***************************************************************************/
210 #define MAX_COMP 4 /* ever needed maximum number of components in texel */
211 #define MAX_VECT 4 /* ever needed maximum number of base vectors to find */
212 #define N_TEXELS 32 /* number of texels in a block (always 32) */
213 #define LL_N_REP 50 /* number of iterations in lloyd's vq */
214 #define LL_RMS_D 10 /* fault tolerance (maximum delta) */
215 #define LL_RMS_E 255 /* fault tolerance (maximum error) */
216 #define ALPHA_TS 2 /* alpha threshold: (255 - ALPHA_TS) deemed opaque */
217 #define ISTBLACK(v) (*((GLuint *)(v)) == 0)
221 * Define a 64-bit unsigned integer type and macros
225 #define FX64_NATIVE 1
227 typedef uint64_t Fx64
;
229 #define FX64_MOV32(a, b) a = b
230 #define FX64_OR32(a, b) a |= b
231 #define FX64_SHL(a, c) a <<= c
235 #define FX64_NATIVE 0
241 #define FX64_MOV32(a, b) a.lo = b
242 #define FX64_OR32(a, b) a.lo |= b
244 #define FX64_SHL(a, c) \
247 a.hi = a.lo << ((c) - 32); \
250 a.hi = (a.hi << (c)) | (a.lo >> (32 - (c))); \
258 #define F(i) (GLfloat)1 /* can be used to obtain an oblong metric: 0.30 / 0.59 / 0.11 */
259 #define SAFECDOT 1 /* for paranoids */
261 #define MAKEIVEC(NV, NC, IV, B, V0, V1) \
263 /* compute interpolation vector */ \
267 for (i = 0; i < NC; i++) { \
268 IV[i] = (V1[i] - V0[i]) * F(i); \
269 d2 += IV[i] * IV[i]; \
271 rd2 = (GLfloat)NV / d2; \
273 for (i = 0; i < NC; i++) { \
275 B -= IV[i] * V0[i]; \
278 B = B * rd2 + 0.5f; \
281 #define CALCCDOT(TEXEL, NV, NC, IV, B, V)\
283 GLfloat dot = 0.0F; \
284 for (i = 0; i < NC; i++) { \
285 dot += V[i] * IV[i]; \
287 TEXEL = (GLint)(dot + B); \
291 } else if (TEXEL > NV) { \
299 fxt1_bestcol (GLfloat vec
[][MAX_COMP
], GLint nv
,
300 GLubyte input
[MAX_COMP
], GLint nc
)
302 GLint i
, j
, best
= -1;
303 GLfloat err
= 1e9
; /* big enough */
305 for (j
= 0; j
< nv
; j
++) {
307 for (i
= 0; i
< nc
; i
++) {
308 e
+= (vec
[j
][i
] - input
[i
]) * (vec
[j
][i
] - input
[i
]);
321 fxt1_worst (GLfloat vec
[MAX_COMP
],
322 GLubyte input
[N_TEXELS
][MAX_COMP
], GLint nc
, GLint n
)
324 GLint i
, k
, worst
= -1;
325 GLfloat err
= -1.0F
; /* small enough */
327 for (k
= 0; k
< n
; k
++) {
329 for (i
= 0; i
< nc
; i
++) {
330 e
+= (vec
[i
] - input
[k
][i
]) * (vec
[i
] - input
[k
][i
]);
343 fxt1_variance (GLdouble variance
[MAX_COMP
],
344 GLubyte input
[N_TEXELS
][MAX_COMP
], GLint nc
, GLint n
)
346 GLint i
, k
, best
= 0;
348 GLdouble var
, maxvar
= -1; /* small enough */
349 GLdouble teenth
= 1.0 / n
;
351 for (i
= 0; i
< nc
; i
++) {
353 for (k
= 0; k
< n
; k
++) {
354 GLint t
= input
[k
][i
];
358 var
= sx2
* teenth
- sx
* sx
* teenth
* teenth
;
373 fxt1_choose (GLfloat vec
[][MAX_COMP
], GLint nv
,
374 GLubyte input
[N_TEXELS
][MAX_COMP
], GLint nc
, GLint n
)
377 /* Choose colors from a grid.
381 for (j
= 0; j
< nv
; j
++) {
382 GLint m
= j
* (n
- 1) / (nv
- 1);
383 for (i
= 0; i
< nc
; i
++) {
384 vec
[j
][i
] = input
[m
][i
];
388 /* Our solution here is to find the darkest and brightest colors in
389 * the 8x4 tile and use those as the two representative colors.
390 * There are probably better algorithms to use (histogram-based).
393 GLint minSum
= 2000; /* big enough */
394 GLint maxSum
= -1; /* small enough */
395 GLint minCol
= 0; /* phoudoin: silent compiler! */
396 GLint maxCol
= 0; /* phoudoin: silent compiler! */
406 memset(hist
, 0, sizeof(hist
));
408 for (k
= 0; k
< n
; k
++) {
412 for (i
= 0; i
< nc
; i
++) {
417 for (l
= 0; l
< n
; l
++) {
426 } else if (hist
[l
].key
== key
) {
442 for (j
= 0; j
< lenh
; j
++) {
443 for (i
= 0; i
< nc
; i
++) {
444 vec
[j
][i
] = (GLfloat
)input
[hist
[j
].idx
][i
];
447 for (; j
< nv
; j
++) {
448 for (i
= 0; i
< nc
; i
++) {
449 vec
[j
][i
] = vec
[0][i
];
455 for (j
= 0; j
< nv
; j
++) {
456 for (i
= 0; i
< nc
; i
++) {
457 vec
[j
][i
] = ((nv
- 1 - j
) * input
[minCol
][i
] + j
* input
[maxCol
][i
] + (nv
- 1) / 2) / (GLfloat
)(nv
- 1);
467 fxt1_lloyd (GLfloat vec
[][MAX_COMP
], GLint nv
,
468 GLubyte input
[N_TEXELS
][MAX_COMP
], GLint nc
, GLint n
)
470 /* Use the generalized lloyd's algorithm for VQ:
471 * find 4 color vectors.
473 * for each sample color
474 * sort to nearest vector.
476 * replace each vector with the centroid of its matching colors.
478 * repeat until RMS doesn't improve.
480 * if a color vector has no samples, or becomes the same as another
481 * vector, replace it with the color which is farthest from a sample.
483 * vec[][MAX_COMP] initial vectors and resulting colors
484 * nv number of resulting colors required
485 * input[N_TEXELS][MAX_COMP] input texels
486 * nc number of components in input / vec
487 * n number of input samples
490 GLint sum
[MAX_VECT
][MAX_COMP
]; /* used to accumulate closest texels */
491 GLint cnt
[MAX_VECT
]; /* how many times a certain vector was chosen */
492 GLfloat error
, lasterror
= 1e9
;
497 for (rep
= 0; rep
< LL_N_REP
; rep
++) {
498 /* reset sums & counters */
499 for (j
= 0; j
< nv
; j
++) {
500 for (i
= 0; i
< nc
; i
++) {
507 /* scan whole block */
508 for (k
= 0; k
< n
; k
++) {
511 GLfloat err
= 1e9
; /* big enough */
512 /* determine best vector */
513 for (j
= 0; j
< nv
; j
++) {
514 GLfloat e
= (vec
[j
][0] - input
[k
][0]) * (vec
[j
][0] - input
[k
][0]) +
515 (vec
[j
][1] - input
[k
][1]) * (vec
[j
][1] - input
[k
][1]) +
516 (vec
[j
][2] - input
[k
][2]) * (vec
[j
][2] - input
[k
][2]);
518 e
+= (vec
[j
][3] - input
[k
][3]) * (vec
[j
][3] - input
[k
][3]);
526 GLint best
= fxt1_bestcol(vec
, nv
, input
[k
], nc
, &err
);
529 /* add in closest color */
530 for (i
= 0; i
< nc
; i
++) {
531 sum
[best
][i
] += input
[k
][i
];
533 /* mark this vector as used */
535 /* accumulate error */
540 if ((error
< LL_RMS_E
) ||
541 ((error
< lasterror
) && ((lasterror
- error
) < LL_RMS_D
))) {
542 return !0; /* good match */
546 /* move each vector to the barycenter of its closest colors */
547 for (j
= 0; j
< nv
; j
++) {
549 GLfloat div
= 1.0F
/ cnt
[j
];
550 for (i
= 0; i
< nc
; i
++) {
551 vec
[j
][i
] = div
* sum
[j
][i
];
554 /* this vec has no samples or is identical with a previous vec */
555 GLint worst
= fxt1_worst(vec
[j
], input
, nc
, n
);
556 for (i
= 0; i
< nc
; i
++) {
557 vec
[j
][i
] = input
[worst
][i
];
563 return 0; /* could not converge fast enough */
568 fxt1_quantize_CHROMA (GLuint
*cc
,
569 GLubyte input
[N_TEXELS
][MAX_COMP
])
571 const GLint n_vect
= 4; /* 4 base vectors to find */
572 const GLint n_comp
= 3; /* 3 components: R, G, B */
573 GLfloat vec
[MAX_VECT
][MAX_COMP
];
575 Fx64 hi
; /* high quadword */
576 GLuint lohi
, lolo
; /* low quadword: hi dword, lo dword */
578 if (fxt1_choose(vec
, n_vect
, input
, n_comp
, N_TEXELS
) != 0) {
579 fxt1_lloyd(vec
, n_vect
, input
, n_comp
, N_TEXELS
);
582 FX64_MOV32(hi
, 4); /* cc-chroma = "010" + unused bit */
583 for (j
= n_vect
- 1; j
>= 0; j
--) {
584 for (i
= 0; i
< n_comp
; i
++) {
587 FX64_OR32(hi
, (GLuint
)(vec
[j
][i
] / 8.0F
));
590 ((Fx64
*)cc
)[1] = hi
;
593 /* right microtile */
594 for (k
= N_TEXELS
- 1; k
>= N_TEXELS
/2; k
--) {
596 lohi
|= fxt1_bestcol(vec
, n_vect
, input
[k
], n_comp
);
599 for (; k
>= 0; k
--) {
601 lolo
|= fxt1_bestcol(vec
, n_vect
, input
[k
], n_comp
);
609 fxt1_quantize_ALPHA0 (GLuint
*cc
,
610 GLubyte input
[N_TEXELS
][MAX_COMP
],
611 GLubyte reord
[N_TEXELS
][MAX_COMP
], GLint n
)
613 const GLint n_vect
= 3; /* 3 base vectors to find */
614 const GLint n_comp
= 4; /* 4 components: R, G, B, A */
615 GLfloat vec
[MAX_VECT
][MAX_COMP
];
617 Fx64 hi
; /* high quadword */
618 GLuint lohi
, lolo
; /* low quadword: hi dword, lo dword */
620 /* the last vector indicates zero */
621 for (i
= 0; i
< n_comp
; i
++) {
625 /* the first n texels in reord are guaranteed to be non-zero */
626 if (fxt1_choose(vec
, n_vect
, reord
, n_comp
, n
) != 0) {
627 fxt1_lloyd(vec
, n_vect
, reord
, n_comp
, n
);
630 FX64_MOV32(hi
, 6); /* alpha = "011" + lerp = 0 */
631 for (j
= n_vect
- 1; j
>= 0; j
--) {
634 FX64_OR32(hi
, (GLuint
)(vec
[j
][ACOMP
] / 8.0F
));
636 for (j
= n_vect
- 1; j
>= 0; j
--) {
637 for (i
= 0; i
< n_comp
- 1; i
++) {
640 FX64_OR32(hi
, (GLuint
)(vec
[j
][i
] / 8.0F
));
643 ((Fx64
*)cc
)[1] = hi
;
646 /* right microtile */
647 for (k
= N_TEXELS
- 1; k
>= N_TEXELS
/2; k
--) {
649 lohi
|= fxt1_bestcol(vec
, n_vect
+ 1, input
[k
], n_comp
);
652 for (; k
>= 0; k
--) {
654 lolo
|= fxt1_bestcol(vec
, n_vect
+ 1, input
[k
], n_comp
);
662 fxt1_quantize_ALPHA1 (GLuint
*cc
,
663 GLubyte input
[N_TEXELS
][MAX_COMP
])
665 const GLint n_vect
= 3; /* highest vector number in each microtile */
666 const GLint n_comp
= 4; /* 4 components: R, G, B, A */
667 GLfloat vec
[1 + 1 + 1][MAX_COMP
]; /* 1.5 extrema for each sub-block */
668 GLfloat b
, iv
[MAX_COMP
]; /* interpolation vector */
670 Fx64 hi
; /* high quadword */
671 GLuint lohi
, lolo
; /* low quadword: hi dword, lo dword */
675 GLint minColL
= 0, maxColL
= 0;
676 GLint minColR
= 0, maxColR
= 0;
677 GLint sumL
= 0, sumR
= 0;
679 /* Our solution here is to find the darkest and brightest colors in
680 * the 4x4 tile and use those as the two representative colors.
681 * There are probably better algorithms to use (histogram-based).
684 while ((minColL
== maxColL
) && nn_comp
) {
685 minSum
= 2000; /* big enough */
686 maxSum
= -1; /* small enough */
687 for (k
= 0; k
< N_TEXELS
/ 2; k
++) {
689 for (i
= 0; i
< nn_comp
; i
++) {
707 while ((minColR
== maxColR
) && nn_comp
) {
708 minSum
= 2000; /* big enough */
709 maxSum
= -1; /* small enough */
710 for (k
= N_TEXELS
/ 2; k
< N_TEXELS
; k
++) {
712 for (i
= 0; i
< nn_comp
; i
++) {
729 /* choose the common vector (yuck!) */
732 GLint v1
= 0, v2
= 0;
733 GLfloat err
= 1e9
; /* big enough */
734 GLfloat tv
[2 * 2][MAX_COMP
]; /* 2 extrema for each sub-block */
735 for (i
= 0; i
< n_comp
; i
++) {
736 tv
[0][i
] = input
[minColL
][i
];
737 tv
[1][i
] = input
[maxColL
][i
];
738 tv
[2][i
] = input
[minColR
][i
];
739 tv
[3][i
] = input
[maxColR
][i
];
741 for (j1
= 0; j1
< 2; j1
++) {
742 for (j2
= 2; j2
< 4; j2
++) {
744 for (i
= 0; i
< n_comp
; i
++) {
745 e
+= (tv
[j1
][i
] - tv
[j2
][i
]) * (tv
[j1
][i
] - tv
[j2
][i
]);
754 for (i
= 0; i
< n_comp
; i
++) {
755 vec
[0][i
] = tv
[1 - v1
][i
];
756 vec
[1][i
] = (tv
[v1
][i
] * sumL
+ tv
[v2
][i
] * sumR
) / (sumL
+ sumR
);
757 vec
[2][i
] = tv
[5 - v2
][i
];
763 if (minColL
!= maxColL
) {
764 /* compute interpolation vector */
765 MAKEIVEC(n_vect
, n_comp
, iv
, b
, vec
[0], vec
[1]);
769 for (k
= N_TEXELS
/ 2 - 1; k
>= 0; k
--) {
771 /* interpolate color */
772 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
781 /* right microtile */
783 if (minColR
!= maxColR
) {
784 /* compute interpolation vector */
785 MAKEIVEC(n_vect
, n_comp
, iv
, b
, vec
[2], vec
[1]);
789 for (k
= N_TEXELS
- 1; k
>= N_TEXELS
/ 2; k
--) {
791 /* interpolate color */
792 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
801 FX64_MOV32(hi
, 7); /* alpha = "011" + lerp = 1 */
802 for (j
= n_vect
- 1; j
>= 0; j
--) {
805 FX64_OR32(hi
, (GLuint
)(vec
[j
][ACOMP
] / 8.0F
));
807 for (j
= n_vect
- 1; j
>= 0; j
--) {
808 for (i
= 0; i
< n_comp
- 1; i
++) {
811 FX64_OR32(hi
, (GLuint
)(vec
[j
][i
] / 8.0F
));
814 ((Fx64
*)cc
)[1] = hi
;
819 fxt1_quantize_HI (GLuint
*cc
,
820 GLubyte input
[N_TEXELS
][MAX_COMP
],
821 GLubyte reord
[N_TEXELS
][MAX_COMP
], GLint n
)
823 const GLint n_vect
= 6; /* highest vector number */
824 const GLint n_comp
= 3; /* 3 components: R, G, B */
825 GLfloat b
= 0.0F
; /* phoudoin: silent compiler! */
826 GLfloat iv
[MAX_COMP
]; /* interpolation vector */
828 GLuint hihi
; /* high quadword: hi dword */
830 GLint minSum
= 2000; /* big enough */
831 GLint maxSum
= -1; /* small enough */
832 GLint minCol
= 0; /* phoudoin: silent compiler! */
833 GLint maxCol
= 0; /* phoudoin: silent compiler! */
835 /* Our solution here is to find the darkest and brightest colors in
836 * the 8x4 tile and use those as the two representative colors.
837 * There are probably better algorithms to use (histogram-based).
839 for (k
= 0; k
< n
; k
++) {
841 for (i
= 0; i
< n_comp
; i
++) {
854 hihi
= 0; /* cc-hi = "00" */
855 for (i
= 0; i
< n_comp
; i
++) {
858 hihi
|= reord
[maxCol
][i
] >> 3;
860 for (i
= 0; i
< n_comp
; i
++) {
863 hihi
|= reord
[minCol
][i
] >> 3;
866 cc
[0] = cc
[1] = cc
[2] = 0;
868 /* compute interpolation vector */
869 if (minCol
!= maxCol
) {
870 MAKEIVEC(n_vect
, n_comp
, iv
, b
, reord
[minCol
], reord
[maxCol
]);
874 for (k
= N_TEXELS
- 1; k
>= 0; k
--) {
876 GLuint
*kk
= (GLuint
*)((char *)cc
+ t
/ 8);
877 GLint texel
= n_vect
+ 1; /* transparent black */
879 if (!ISTBLACK(input
[k
])) {
880 if (minCol
!= maxCol
) {
881 /* interpolate color */
882 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
884 kk
[0] |= texel
<< (t
& 7);
888 kk
[0] |= texel
<< (t
& 7);
895 fxt1_quantize_MIXED1 (GLuint
*cc
,
896 GLubyte input
[N_TEXELS
][MAX_COMP
])
898 const GLint n_vect
= 2; /* highest vector number in each microtile */
899 const GLint n_comp
= 3; /* 3 components: R, G, B */
900 GLubyte vec
[2 * 2][MAX_COMP
]; /* 2 extrema for each sub-block */
901 GLfloat b
, iv
[MAX_COMP
]; /* interpolation vector */
903 Fx64 hi
; /* high quadword */
904 GLuint lohi
, lolo
; /* low quadword: hi dword, lo dword */
908 GLint minColL
= 0, maxColL
= -1;
909 GLint minColR
= 0, maxColR
= -1;
911 /* Our solution here is to find the darkest and brightest colors in
912 * the 4x4 tile and use those as the two representative colors.
913 * There are probably better algorithms to use (histogram-based).
915 minSum
= 2000; /* big enough */
916 maxSum
= -1; /* small enough */
917 for (k
= 0; k
< N_TEXELS
/ 2; k
++) {
918 if (!ISTBLACK(input
[k
])) {
920 for (i
= 0; i
< n_comp
; i
++) {
933 minSum
= 2000; /* big enough */
934 maxSum
= -1; /* small enough */
935 for (; k
< N_TEXELS
; k
++) {
936 if (!ISTBLACK(input
[k
])) {
938 for (i
= 0; i
< n_comp
; i
++) {
954 /* all transparent black */
956 for (i
= 0; i
< n_comp
; i
++) {
962 for (i
= 0; i
< n_comp
; i
++) {
963 vec
[0][i
] = input
[minColL
][i
];
964 vec
[1][i
] = input
[maxColL
][i
];
966 if (minColL
!= maxColL
) {
967 /* compute interpolation vector */
968 MAKEIVEC(n_vect
, n_comp
, iv
, b
, vec
[0], vec
[1]);
972 for (k
= N_TEXELS
/ 2 - 1; k
>= 0; k
--) {
973 GLint texel
= n_vect
+ 1; /* transparent black */
974 if (!ISTBLACK(input
[k
])) {
975 /* interpolate color */
976 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
986 /* right microtile */
988 /* all transparent black */
990 for (i
= 0; i
< n_comp
; i
++) {
996 for (i
= 0; i
< n_comp
; i
++) {
997 vec
[2][i
] = input
[minColR
][i
];
998 vec
[3][i
] = input
[maxColR
][i
];
1000 if (minColR
!= maxColR
) {
1001 /* compute interpolation vector */
1002 MAKEIVEC(n_vect
, n_comp
, iv
, b
, vec
[2], vec
[3]);
1006 for (k
= N_TEXELS
- 1; k
>= N_TEXELS
/ 2; k
--) {
1007 GLint texel
= n_vect
+ 1; /* transparent black */
1008 if (!ISTBLACK(input
[k
])) {
1009 /* interpolate color */
1010 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
1020 FX64_MOV32(hi
, 9 | (vec
[3][GCOMP
] & 4) | ((vec
[1][GCOMP
] >> 1) & 2)); /* chroma = "1" */
1021 for (j
= 2 * 2 - 1; j
>= 0; j
--) {
1022 for (i
= 0; i
< n_comp
; i
++) {
1025 FX64_OR32(hi
, vec
[j
][i
] >> 3);
1028 ((Fx64
*)cc
)[1] = hi
;
1033 fxt1_quantize_MIXED0 (GLuint
*cc
,
1034 GLubyte input
[N_TEXELS
][MAX_COMP
])
1036 const GLint n_vect
= 3; /* highest vector number in each microtile */
1037 const GLint n_comp
= 3; /* 3 components: R, G, B */
1038 GLubyte vec
[2 * 2][MAX_COMP
]; /* 2 extrema for each sub-block */
1039 GLfloat b
, iv
[MAX_COMP
]; /* interpolation vector */
1041 Fx64 hi
; /* high quadword */
1042 GLuint lohi
, lolo
; /* low quadword: hi dword, lo dword */
1044 GLint minColL
= 0, maxColL
= 0;
1045 GLint minColR
= 0, maxColR
= 0;
1050 /* Our solution here is to find the darkest and brightest colors in
1051 * the 4x4 tile and use those as the two representative colors.
1052 * There are probably better algorithms to use (histogram-based).
1054 minSum
= 2000; /* big enough */
1055 maxSum
= -1; /* small enough */
1056 for (k
= 0; k
< N_TEXELS
/ 2; k
++) {
1058 for (i
= 0; i
< n_comp
; i
++) {
1070 minSum
= 2000; /* big enough */
1071 maxSum
= -1; /* small enough */
1072 for (; k
< N_TEXELS
; k
++) {
1074 for (i
= 0; i
< n_comp
; i
++) {
1089 GLint maxVarL
= fxt1_variance(NULL
, input
, n_comp
, N_TEXELS
/ 2);
1090 GLint maxVarR
= fxt1_variance(NULL
, &input
[N_TEXELS
/ 2], n_comp
, N_TEXELS
/ 2);
1092 /* Scan the channel with max variance for lo & hi
1093 * and use those as the two representative colors.
1095 minVal
= 2000; /* big enough */
1096 maxVal
= -1; /* small enough */
1097 for (k
= 0; k
< N_TEXELS
/ 2; k
++) {
1098 GLint t
= input
[k
][maxVarL
];
1108 minVal
= 2000; /* big enough */
1109 maxVal
= -1; /* small enough */
1110 for (; k
< N_TEXELS
; k
++) {
1111 GLint t
= input
[k
][maxVarR
];
1123 /* left microtile */
1125 for (i
= 0; i
< n_comp
; i
++) {
1126 vec
[0][i
] = input
[minColL
][i
];
1127 vec
[1][i
] = input
[maxColL
][i
];
1129 if (minColL
!= maxColL
) {
1130 /* compute interpolation vector */
1131 MAKEIVEC(n_vect
, n_comp
, iv
, b
, vec
[0], vec
[1]);
1135 for (k
= N_TEXELS
/ 2 - 1; k
>= 0; k
--) {
1137 /* interpolate color */
1138 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
1144 /* funky encoding for LSB of green */
1145 if ((GLint
)((lolo
>> 1) & 1) != (((vec
[1][GCOMP
] ^ vec
[0][GCOMP
]) >> 2) & 1)) {
1146 for (i
= 0; i
< n_comp
; i
++) {
1147 vec
[1][i
] = input
[minColL
][i
];
1148 vec
[0][i
] = input
[maxColL
][i
];
1156 /* right microtile */
1158 for (i
= 0; i
< n_comp
; i
++) {
1159 vec
[2][i
] = input
[minColR
][i
];
1160 vec
[3][i
] = input
[maxColR
][i
];
1162 if (minColR
!= maxColR
) {
1163 /* compute interpolation vector */
1164 MAKEIVEC(n_vect
, n_comp
, iv
, b
, vec
[2], vec
[3]);
1168 for (k
= N_TEXELS
- 1; k
>= N_TEXELS
/ 2; k
--) {
1170 /* interpolate color */
1171 CALCCDOT(texel
, n_vect
, n_comp
, iv
, b
, input
[k
]);
1177 /* funky encoding for LSB of green */
1178 if ((GLint
)((lohi
>> 1) & 1) != (((vec
[3][GCOMP
] ^ vec
[2][GCOMP
]) >> 2) & 1)) {
1179 for (i
= 0; i
< n_comp
; i
++) {
1180 vec
[3][i
] = input
[minColR
][i
];
1181 vec
[2][i
] = input
[maxColR
][i
];
1189 FX64_MOV32(hi
, 8 | (vec
[3][GCOMP
] & 4) | ((vec
[1][GCOMP
] >> 1) & 2)); /* chroma = "1" */
1190 for (j
= 2 * 2 - 1; j
>= 0; j
--) {
1191 for (i
= 0; i
< n_comp
; i
++) {
1194 FX64_OR32(hi
, vec
[j
][i
] >> 3);
1197 ((Fx64
*)cc
)[1] = hi
;
1202 fxt1_quantize (GLuint
*cc
, const GLubyte
*lines
[], GLint comps
)
1205 GLubyte reord
[N_TEXELS
][MAX_COMP
];
1207 GLubyte input
[N_TEXELS
][MAX_COMP
];
1211 /* make the whole block opaque */
1212 memset(input
, -1, sizeof(input
));
1215 /* 8 texels each line */
1216 for (l
= 0; l
< 4; l
++) {
1217 for (k
= 0; k
< 4; k
++) {
1218 for (i
= 0; i
< comps
; i
++) {
1219 input
[k
+ l
* 4][i
] = *lines
[l
]++;
1222 for (; k
< 8; k
++) {
1223 for (i
= 0; i
< comps
; i
++) {
1224 input
[k
+ l
* 4 + 12][i
] = *lines
[l
]++;
1230 * 00, 01, 02, 03, 08, 09, 0a, 0b
1231 * 10, 11, 12, 13, 18, 19, 1a, 1b
1232 * 04, 05, 06, 07, 0c, 0d, 0e, 0f
1233 * 14, 15, 16, 17, 1c, 1d, 1e, 1f
1237 * stupidity flows forth from this
1242 /* skip all transparent black texels */
1244 for (k
= 0; k
< N_TEXELS
; k
++) {
1245 /* test all components against 0 */
1246 if (!ISTBLACK(input
[k
])) {
1247 /* texel is not transparent black */
1248 COPY_4UBV(reord
[l
], input
[k
]);
1249 if (reord
[l
][ACOMP
] < (255 - ALPHA_TS
)) {
1250 /* non-opaque texel */
1260 fxt1_quantize_ALPHA0(cc
, input
, reord
, l
);
1261 } else if (l
== 0) {
1262 cc
[0] = cc
[1] = cc
[2] = -1;
1264 } else if (l
< N_TEXELS
) {
1265 fxt1_quantize_HI(cc
, input
, reord
, l
);
1267 fxt1_quantize_CHROMA(cc
, input
);
1269 (void)fxt1_quantize_ALPHA1
;
1270 (void)fxt1_quantize_MIXED1
;
1271 (void)fxt1_quantize_MIXED0
;
1274 fxt1_quantize_ALPHA1(cc
, input
);
1275 } else if (l
== 0) {
1276 cc
[0] = cc
[1] = cc
[2] = ~0u;
1278 } else if (l
< N_TEXELS
) {
1279 fxt1_quantize_MIXED1(cc
, input
);
1281 fxt1_quantize_MIXED0(cc
, input
);
1283 (void)fxt1_quantize_ALPHA0
;
1284 (void)fxt1_quantize_HI
;
1285 (void)fxt1_quantize_CHROMA
;
1291 fxt1_encode (GLuint width
, GLuint height
, GLint comps
,
1292 const void *source
, GLint srcRowStride
,
1293 void *dest
, GLint destRowStride
)
1296 const GLubyte
*data
;
1297 GLuint
*encoded
= (GLuint
*)dest
;
1298 void *newSource
= NULL
;
1300 assert(comps
== 3 || comps
== 4);
1302 /* Replicate image if width is not M8 or height is not M4 */
1303 if ((width
& 7) | (height
& 3)) {
1304 GLint newWidth
= (width
+ 7) & ~7;
1305 GLint newHeight
= (height
+ 3) & ~3;
1306 newSource
= malloc(comps
* newWidth
* newHeight
* sizeof(GLchan
));
1308 GET_CURRENT_CONTEXT(ctx
);
1309 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "texture compression");
1312 _mesa_upscale_teximage2d(width
, height
, newWidth
, newHeight
,
1313 comps
, (const GLchan
*) source
,
1314 srcRowStride
, (GLchan
*) newSource
);
1318 srcRowStride
= comps
* newWidth
;
1321 /* convert from 16/32-bit channels to GLubyte if needed */
1322 if (CHAN_TYPE
!= GL_UNSIGNED_BYTE
) {
1323 const GLuint n
= width
* height
* comps
;
1324 const GLchan
*src
= (const GLchan
*) source
;
1325 GLubyte
*dest
= (GLubyte
*) malloc(n
* sizeof(GLubyte
));
1328 GET_CURRENT_CONTEXT(ctx
);
1329 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "texture compression");
1332 for (i
= 0; i
< n
; i
++) {
1333 dest
[i
] = CHAN_TO_UBYTE(src
[i
]);
1335 if (newSource
!= NULL
) {
1338 newSource
= dest
; /* we'll free this buffer before returning */
1339 source
= dest
; /* the new, GLubyte incoming image */
1342 data
= (const GLubyte
*) source
;
1343 destRowStride
= (destRowStride
- width
* 2) / 4;
1344 for (y
= 0; y
< height
; y
+= 4) {
1345 GLuint offs
= 0 + (y
+ 0) * srcRowStride
;
1346 for (x
= 0; x
< width
; x
+= 8) {
1347 const GLubyte
*lines
[4];
1348 lines
[0] = &data
[offs
];
1349 lines
[1] = lines
[0] + srcRowStride
;
1350 lines
[2] = lines
[1] + srcRowStride
;
1351 lines
[3] = lines
[2] + srcRowStride
;
1353 fxt1_quantize(encoded
, lines
, comps
);
1354 /* 128 bits per 8x4 block */
1357 encoded
+= destRowStride
;
1361 if (newSource
!= NULL
) {
1367 /***************************************************************************\
1370 * The decoder is based on GL_3DFX_texture_compression_FXT1
1371 * specification and serves as a concept for the encoder.
1372 \***************************************************************************/
1375 /* lookup table for scaling 5 bit colors up to 8 bits */
1376 static const GLubyte _rgb_scale_5
[] = {
1377 0, 8, 16, 25, 33, 41, 49, 58,
1378 66, 74, 82, 90, 99, 107, 115, 123,
1379 132, 140, 148, 156, 165, 173, 181, 189,
1380 197, 206, 214, 222, 230, 239, 247, 255
1383 /* lookup table for scaling 6 bit colors up to 8 bits */
1384 static const GLubyte _rgb_scale_6
[] = {
1385 0, 4, 8, 12, 16, 20, 24, 28,
1386 32, 36, 40, 45, 49, 53, 57, 61,
1387 65, 69, 73, 77, 81, 85, 89, 93,
1388 97, 101, 105, 109, 113, 117, 121, 125,
1389 130, 134, 138, 142, 146, 150, 154, 158,
1390 162, 166, 170, 174, 178, 182, 186, 190,
1391 194, 198, 202, 206, 210, 215, 219, 223,
1392 227, 231, 235, 239, 243, 247, 251, 255
1396 #define CC_SEL(cc, which) (((GLuint *)(cc))[(which) / 32] >> ((which) & 31))
1397 #define UP5(c) _rgb_scale_5[(c) & 31]
1398 #define UP6(c, b) _rgb_scale_6[(((c) & 31) << 1) | ((b) & 1)]
1399 #define LERP(n, t, c0, c1) (((n) - (t)) * (c0) + (t) * (c1) + (n) / 2) / (n)
1403 fxt1_decode_1HI (const GLubyte
*code
, GLint t
, GLchan
*rgba
)
1408 cc
= (const GLuint
*)(code
+ t
/ 8);
1409 t
= (cc
[0] >> (t
& 7)) & 7;
1412 rgba
[RCOMP
] = rgba
[GCOMP
] = rgba
[BCOMP
] = rgba
[ACOMP
] = 0;
1415 cc
= (const GLuint
*)(code
+ 12);
1417 b
= UP5(CC_SEL(cc
, 0));
1418 g
= UP5(CC_SEL(cc
, 5));
1419 r
= UP5(CC_SEL(cc
, 10));
1420 } else if (t
== 6) {
1421 b
= UP5(CC_SEL(cc
, 15));
1422 g
= UP5(CC_SEL(cc
, 20));
1423 r
= UP5(CC_SEL(cc
, 25));
1425 b
= LERP(6, t
, UP5(CC_SEL(cc
, 0)), UP5(CC_SEL(cc
, 15)));
1426 g
= LERP(6, t
, UP5(CC_SEL(cc
, 5)), UP5(CC_SEL(cc
, 20)));
1427 r
= LERP(6, t
, UP5(CC_SEL(cc
, 10)), UP5(CC_SEL(cc
, 25)));
1429 rgba
[RCOMP
] = UBYTE_TO_CHAN(r
);
1430 rgba
[GCOMP
] = UBYTE_TO_CHAN(g
);
1431 rgba
[BCOMP
] = UBYTE_TO_CHAN(b
);
1432 rgba
[ACOMP
] = CHAN_MAX
;
1438 fxt1_decode_1CHROMA (const GLubyte
*code
, GLint t
, GLchan
*rgba
)
1443 cc
= (const GLuint
*)code
;
1448 t
= (cc
[0] >> (t
* 2)) & 3;
1451 cc
= (const GLuint
*)(code
+ 8 + t
/ 8);
1452 kk
= cc
[0] >> (t
& 7);
1453 rgba
[BCOMP
] = UBYTE_TO_CHAN( UP5(kk
) );
1454 rgba
[GCOMP
] = UBYTE_TO_CHAN( UP5(kk
>> 5) );
1455 rgba
[RCOMP
] = UBYTE_TO_CHAN( UP5(kk
>> 10) );
1456 rgba
[ACOMP
] = CHAN_MAX
;
1461 fxt1_decode_1MIXED (const GLubyte
*code
, GLint t
, GLchan
*rgba
)
1467 cc
= (const GLuint
*)code
;
1470 t
= (cc
[1] >> (t
* 2)) & 3;
1472 col
[0][BCOMP
] = (*(const GLuint
*)(code
+ 11)) >> 6;
1473 col
[0][GCOMP
] = CC_SEL(cc
, 99);
1474 col
[0][RCOMP
] = CC_SEL(cc
, 104);
1476 col
[1][BCOMP
] = CC_SEL(cc
, 109);
1477 col
[1][GCOMP
] = CC_SEL(cc
, 114);
1478 col
[1][RCOMP
] = CC_SEL(cc
, 119);
1479 glsb
= CC_SEL(cc
, 126);
1480 selb
= CC_SEL(cc
, 33);
1482 t
= (cc
[0] >> (t
* 2)) & 3;
1484 col
[0][BCOMP
] = CC_SEL(cc
, 64);
1485 col
[0][GCOMP
] = CC_SEL(cc
, 69);
1486 col
[0][RCOMP
] = CC_SEL(cc
, 74);
1488 col
[1][BCOMP
] = CC_SEL(cc
, 79);
1489 col
[1][GCOMP
] = CC_SEL(cc
, 84);
1490 col
[1][RCOMP
] = CC_SEL(cc
, 89);
1491 glsb
= CC_SEL(cc
, 125);
1492 selb
= CC_SEL(cc
, 1);
1495 if (CC_SEL(cc
, 124) & 1) {
1500 rgba
[RCOMP
] = rgba
[BCOMP
] = rgba
[GCOMP
] = rgba
[ACOMP
] = 0;
1504 b
= UP5(col
[0][BCOMP
]);
1505 g
= UP5(col
[0][GCOMP
]);
1506 r
= UP5(col
[0][RCOMP
]);
1507 } else if (t
== 2) {
1508 b
= UP5(col
[1][BCOMP
]);
1509 g
= UP6(col
[1][GCOMP
], glsb
);
1510 r
= UP5(col
[1][RCOMP
]);
1512 b
= (UP5(col
[0][BCOMP
]) + UP5(col
[1][BCOMP
])) / 2;
1513 g
= (UP5(col
[0][GCOMP
]) + UP6(col
[1][GCOMP
], glsb
)) / 2;
1514 r
= (UP5(col
[0][RCOMP
]) + UP5(col
[1][RCOMP
])) / 2;
1516 rgba
[RCOMP
] = UBYTE_TO_CHAN(r
);
1517 rgba
[GCOMP
] = UBYTE_TO_CHAN(g
);
1518 rgba
[BCOMP
] = UBYTE_TO_CHAN(b
);
1519 rgba
[ACOMP
] = CHAN_MAX
;
1525 b
= UP5(col
[0][BCOMP
]);
1526 g
= UP6(col
[0][GCOMP
], glsb
^ selb
);
1527 r
= UP5(col
[0][RCOMP
]);
1528 } else if (t
== 3) {
1529 b
= UP5(col
[1][BCOMP
]);
1530 g
= UP6(col
[1][GCOMP
], glsb
);
1531 r
= UP5(col
[1][RCOMP
]);
1533 b
= LERP(3, t
, UP5(col
[0][BCOMP
]), UP5(col
[1][BCOMP
]));
1534 g
= LERP(3, t
, UP6(col
[0][GCOMP
], glsb
^ selb
),
1535 UP6(col
[1][GCOMP
], glsb
));
1536 r
= LERP(3, t
, UP5(col
[0][RCOMP
]), UP5(col
[1][RCOMP
]));
1538 rgba
[RCOMP
] = UBYTE_TO_CHAN(r
);
1539 rgba
[GCOMP
] = UBYTE_TO_CHAN(g
);
1540 rgba
[BCOMP
] = UBYTE_TO_CHAN(b
);
1541 rgba
[ACOMP
] = CHAN_MAX
;
1547 fxt1_decode_1ALPHA (const GLubyte
*code
, GLint t
, GLchan
*rgba
)
1552 cc
= (const GLuint
*)code
;
1553 if (CC_SEL(cc
, 124) & 1) {
1559 t
= (cc
[1] >> (t
* 2)) & 3;
1561 col0
[BCOMP
] = (*(const GLuint
*)(code
+ 11)) >> 6;
1562 col0
[GCOMP
] = CC_SEL(cc
, 99);
1563 col0
[RCOMP
] = CC_SEL(cc
, 104);
1564 col0
[ACOMP
] = CC_SEL(cc
, 119);
1566 t
= (cc
[0] >> (t
* 2)) & 3;
1568 col0
[BCOMP
] = CC_SEL(cc
, 64);
1569 col0
[GCOMP
] = CC_SEL(cc
, 69);
1570 col0
[RCOMP
] = CC_SEL(cc
, 74);
1571 col0
[ACOMP
] = CC_SEL(cc
, 109);
1575 b
= UP5(col0
[BCOMP
]);
1576 g
= UP5(col0
[GCOMP
]);
1577 r
= UP5(col0
[RCOMP
]);
1578 a
= UP5(col0
[ACOMP
]);
1579 } else if (t
== 3) {
1580 b
= UP5(CC_SEL(cc
, 79));
1581 g
= UP5(CC_SEL(cc
, 84));
1582 r
= UP5(CC_SEL(cc
, 89));
1583 a
= UP5(CC_SEL(cc
, 114));
1585 b
= LERP(3, t
, UP5(col0
[BCOMP
]), UP5(CC_SEL(cc
, 79)));
1586 g
= LERP(3, t
, UP5(col0
[GCOMP
]), UP5(CC_SEL(cc
, 84)));
1587 r
= LERP(3, t
, UP5(col0
[RCOMP
]), UP5(CC_SEL(cc
, 89)));
1588 a
= LERP(3, t
, UP5(col0
[ACOMP
]), UP5(CC_SEL(cc
, 114)));
1597 t
= (cc
[0] >> (t
* 2)) & 3;
1604 cc
= (const GLuint
*)code
;
1605 a
= UP5(cc
[3] >> (t
* 5 + 13));
1607 cc
= (const GLuint
*)(code
+ 8 + t
/ 8);
1608 kk
= cc
[0] >> (t
& 7);
1614 rgba
[RCOMP
] = UBYTE_TO_CHAN(r
);
1615 rgba
[GCOMP
] = UBYTE_TO_CHAN(g
);
1616 rgba
[BCOMP
] = UBYTE_TO_CHAN(b
);
1617 rgba
[ACOMP
] = UBYTE_TO_CHAN(a
);
1622 fxt1_decode_1 (const void *texture
, GLint stride
, /* in pixels */
1623 GLint i
, GLint j
, GLchan
*rgba
)
1625 static void (*decode_1
[]) (const GLubyte
*, GLint
, GLchan
*) = {
1626 fxt1_decode_1HI
, /* cc-high = "00?" */
1627 fxt1_decode_1HI
, /* cc-high = "00?" */
1628 fxt1_decode_1CHROMA
, /* cc-chroma = "010" */
1629 fxt1_decode_1ALPHA
, /* alpha = "011" */
1630 fxt1_decode_1MIXED
, /* mixed = "1??" */
1631 fxt1_decode_1MIXED
, /* mixed = "1??" */
1632 fxt1_decode_1MIXED
, /* mixed = "1??" */
1633 fxt1_decode_1MIXED
/* mixed = "1??" */
1636 const GLubyte
*code
= (const GLubyte
*)texture
+
1637 ((j
/ 4) * (stride
/ 8) + (i
/ 8)) * 16;
1638 GLint mode
= CC_SEL(code
, 125);
1646 decode_1
[mode
](code
, t
, rgba
);
1650 #endif /* FEATURE_texture_fxt1 */