source: trunk/src/opengl/glide/cvg/texus/ncc.c

Last change on this file was 6653, checked in by bird, 24 years ago

Added $Id:$ keyword.

File size: 10.4 KB
Line 
1/* $Id: ncc.c,v 1.2 2001-09-05 14:30:45 bird Exp $ */
2/*
3** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
4** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
5** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
6** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
7** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
8** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
9** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
10** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
11**
12** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
13** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
14** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
15** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
16** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
17** THE UNITED STATES.
18**
19** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
20**
21** $Revision: 1.2 $
22** $Date: 2001-09-05 14:30:45 $
23*/
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <math.h>
29
30#include "texusint.h"
31
32static int
33dithmat[4][4] = { 0, 8, 2, 10,
34 12, 4, 14, 6,
35 3, 11, 1, 9,
36 15, 7, 13, 5 };
37
38static struct {
39 int yhist[256], ihist[256], qhist[256];
40 int ymin, ymax, imin, imax, qmin, qmax;
41 int npixels;
42 int y[16], a[3*4], b[3*4]; // please leave these contiguous
43} ncc;
44
45static int
46_txPixQuantize_YIQ422 (unsigned long argb, int x, int y, int w)
47{
48 int r, g, b;
49 int iy, ii, iq;
50
51 r = (argb >> 16) & 0xFF;
52 g = (argb >> 8) & 0xFF;
53 b = (argb ) & 0xFF;
54
55 iy = (int) (( 0.30F * r + 0.59F * g + 0.11F * b) + 0.5f);
56 ii = (int) (((0.60F * r - 0.28F * g - 0.32F * b) / 1.20F) + 127.5f + 0.5f);
57 iq = (int) (((0.21F * r - 0.52F * g + 0.31F * b) / 1.04F) + 127.5f + 0.5f);
58
59 // At this point, 0<=y,i,q<=255
60 // Convert to 4 bits of y, 2 of i and q.
61
62 if (iy <= ncc.ymin) iy = 0;
63 else if (iy >= ncc.ymax) iy = 15;
64 else iy = (int) ((iy - ncc.ymin) * 15.0f/(ncc.ymax - ncc.ymin) + 0.5f);
65
66 if (ii <= ncc.imin) ii = 0;
67 else if (ii >= ncc.imax) ii = 3;
68 else ii = (int) ((ii - ncc.imin) * 3.0f/(ncc.imax - ncc.imin) + 0.5f);
69
70 if (iq <= ncc.qmin) iq = 0;
71 else if (iq >= ncc.qmax) iq = 3;
72 else iq = (int) ((iq - ncc.qmin) * 3.0f/(ncc.qmax - ncc.qmin) + 0.5f);
73
74 if ((iy < 0) || (iy > 15) || (ii < 0) || (ii > 3) || (iq < 0) || (iq > 3)) {
75 printf("%d %d %d\n", iy, ii, iq);
76 txPanic("Bad YIQ\n");
77 }
78 return ( (iy << 4) | (ii << 2) | iq);
79}
80
81
82static int
83_txPixQuantize_YIQ422_D4x4 (unsigned long argb, int x, int y, int w)
84{
85 int r, g, b;
86 int iy, ii, iq;
87
88
89 r = (argb >> 16) & 0xFF;
90 g = (argb >> 8) & 0xFF;
91 b = (argb ) & 0xFF;
92
93 iy = (int) (( 0.30F * r + 0.59F * g + 0.11F * b) + 0.5f);
94 ii = (int) (((0.60F * r - 0.28F * g - 0.32F * b) / 1.20F) + 127.5f + 0.5f);
95 iq = (int) (((0.21F * r - 0.52F * g + 0.31F * b) / 1.04F) + 127.5f + 0.5f);
96
97 // At this point, 0<=y,i,q<=255
98 // Convert to 4 bits of y, 2 of i and q.
99
100 if (iy <= ncc.ymin) iy = 0;
101 else if (iy >= ncc.ymax) iy = 0xf0;
102 else iy = (int) ((iy - ncc.ymin) * 0xF0/(ncc.ymax - ncc.ymin));
103
104 if (ii <= ncc.imin) ii = 0;
105 else if (ii >= ncc.imax) ii = 0x30;
106 else ii = (int) ((ii - ncc.imin) * 0x30/(ncc.imax - ncc.imin));
107
108 if (iq <= ncc.qmin) iq = 0;
109 else if (iq >= ncc.qmax) iq = 0x30;
110 else iq = (int) ((iq - ncc.qmin) * 0x30/(ncc.qmax - ncc.qmin));
111
112 iy += dithmat[y&3][x&3];
113 ii += dithmat[y&3][x&3];
114 iq += dithmat[y&3][x&3];
115
116 iy >>= 4;
117 ii >>= 4;
118 iq >>= 4;
119
120 if ((iy < 0) || (iy > 15) || (ii < 0) || (ii > 3) || (iq < 0) || (iq > 3)) {
121 printf("%d %d %d\n", iy, ii, iq);
122 txPanic("Bad YIQ\n");
123 }
124 return ( (iy << 4) | (ii << 2) | iq);
125}
126
127static void
128_txImgNcc(char *odata, unsigned long *idata, int w, int h, int format,
129 int dither)
130{
131 int (*quantizer)(unsigned long argb, int x, int y, int w);
132 int x, y, pixsize;
133
134 quantizer = (dither) ? _txPixQuantize_YIQ422_D4x4 : _txPixQuantize_YIQ422;
135
136 pixsize = (format == GR_TEXFMT_YIQ_422) ? 1 : 2;
137
138 for (y=0; y<h; y++) {
139 for (x=0; x<w; x++) {
140 if (format == GR_TEXFMT_AYIQ_8422) {
141 *(FxU16 *)odata = (FxU16) ((*quantizer)(*idata,x,y,w) |
142 ((*idata >> 16) & 0xFF00));
143 } else {
144 *odata = (*quantizer)(*idata, x, y, w);
145 }
146 odata += pixsize;
147 idata ++;
148 }
149 }
150}
151
152/*
153 The basics are as follows:
154
155 RGB values can be converted to YIQ using the equation:
156
157 Y = 0.30F * R + 0.59F * G + 0.11F * B;
158 I = 0.60F * R - 0.28F * G - 0.32F * B;
159 Q = 0.21F * R - 0.52F * G + 0.31F * B;
160
161 Assuming that each of the RGB components are in the range 0..255,
162 Y ranges from (0 .. 255)
163 I ranges from (-0.60 * 255 .. 0.60 * 255) i.e, (-153 to 153)
164 Q ranges from (-0.52 * 255 .. 0.52 * 255) i.e, (-132 to 133)
165
166*/
167
168
169static void
170_txMipNccStatTable(TxMip *txMip)
171{
172 int i, w, h;
173
174 for (i=0; i<256; i++)
175 ncc.yhist[i] = ncc.ihist[i] = ncc.qhist[i] = 0;
176 ncc.npixels = 0;
177
178 /* First find out the relative frequencies of Y, I, Q */
179 w = txMip->width;
180 h = txMip->height;
181
182 for (i=0; i< txMip->depth; i++) {
183 FxU32* src;
184 int npixels;
185
186 src = txMip->data[i];
187 npixels = w * h;
188 ncc.npixels += npixels;
189
190 while (npixels--) {
191 float fy, fi, fq, r, g, b;
192 FxU32 argb;
193
194 argb = *src++;
195 r = (float)((argb >> 16) & 0xFF);
196 g = (float)((argb >> 8) & 0xFF);
197 b = (float)((argb ) & 0xFF);
198
199 fy = 0.30F * r + 0.59F * g + 0.11F * b;
200 fi = 0.60F * r - 0.28F * g - 0.32F * b;
201 fq = 0.21F * r - 0.52F * g + 0.31F * b;
202
203 // Y is now in the range [0,1] * 255, but I and Q need work
204 // I is in the range [-.60, +.60] * 255, convert to [0,1]*255
205 // Q is in the range [-.52, +.52] * 255, convert to [0,1]*255
206
207 fi = fi * 0.50f / 0.60f + 127.5f;
208 fq = fq * 0.50f / 0.52f + 127.5f;
209
210 ncc.yhist[ (int)(fy + 0.5f)]++;
211 ncc.ihist[ (int)(fi + 0.5f)]++;
212 ncc.qhist[ (int)(fq + 0.5f)]++;
213 }
214 if (w > 1) w >>= 1;
215 if (h > 1) h >>= 1;
216 }
217
218 /* Now discard the top 10%, bottom 10% of each channel */
219 {
220 int ysum, isum, qsum, threshold;
221
222 ncc.ymin = ncc.imin = ncc.qmin = 0;
223 ncc.ymax = ncc.imax = ncc.qmax = 255;
224 threshold = (int) (0.01f * ncc.npixels);
225
226 ysum = isum = qsum = 0;
227 for (i=0; i<256; i++) {
228 ysum += ncc.yhist[i];
229 isum += ncc.ihist[i];
230 qsum += ncc.qhist[i];
231 if (ysum < threshold) ncc.ymin = i;
232 if (isum < threshold) ncc.imin = i;
233 if (qsum < threshold) ncc.qmin = i;
234 }
235
236 ysum = isum = qsum = 0;
237 for (i=255; i>=0; i--) {
238 ysum += ncc.yhist[i];
239 isum += ncc.ihist[i];
240 qsum += ncc.qhist[i];
241 if (ysum < threshold) ncc.ymax = i;
242 if (isum < threshold) ncc.imax = i;
243 if (qsum < threshold) ncc.qmax = i;
244 }
245
246 if (ncc.ymin > ncc.ymax) ncc.ymin = ncc.ymax;
247 if (ncc.imin > ncc.imax) ncc.imin = ncc.imax;
248 if (ncc.qmin > ncc.qmax) ncc.qmin = ncc.qmax;
249 }
250}
251
252
253void
254txMipNcc(TxMip *pxMip, TxMip *txMip, int format, FxU32 dither, FxU32 compression)
255{
256 int i, w, h, pixsize;
257
258 switch (compression & TX_COMPRESSION_MASK) {
259 case TX_COMPRESSION_HEURISTIC:
260 _txMipNccStatTable(txMip);
261 for (i=0; i< 16; i++) pxMip->pal[ 0 + i] = ncc.y[i];
262 for (i=0; i< 12; i++) pxMip->pal[16 + i] = ncc.a[i];
263 for (i=0; i< 12; i++) pxMip->pal[28 + i] = ncc.b[i];
264 txMipNccNNet(pxMip, txMip, format, dither, compression);
265 return;
266
267 case TX_COMPRESSION_STATISTICAL:
268 if( txVerbose )
269 printf("Statistical tables\n");
270 _txMipNccStatTable(txMip);
271 break;
272
273#if 0
274 // This disabled, because it sucks.
275 case TX_COMPRESSION_YIQ:
276 if( txVerbose )
277 printf("YIQ tables\n");
278 ncc.ymin = ncc.imin = ncc.qmin = 0;
279 ncc.ymax = ncc.imax = ncc.qmax = 255;
280 break;
281#endif
282 }
283 pixsize = (format == GR_TEXFMT_YIQ_422) ? 1 : 2;
284
285 /* Generate the YAB tables */
286 for (i=0; i<16; i++) {
287 ncc.y[i] = (int) (ncc.ymin + (ncc.ymax - ncc.ymin)*i/15.0f + 0.5f);
288 }
289
290 for (i=0; i<4; i++) {
291 float a, b;
292
293 a = ncc.imin + (ncc.imax - ncc.imin)*i/3.0f;
294 a = (a / 255.0f) * 1.20f - 0.60f; // a is (-0.60, +0.60)
295 a *= 255.0f;
296
297 b = ncc.qmin + (ncc.qmax - ncc.qmin)*i/3.0f;
298 b = (b / 255.0f) * 1.04f - 0.52f; // b is (-0.52, +0.52)
299 b *= 255.0f;
300
301 ncc.a[3*i + 0] = (int) ( 0.95f * a + 0.5f);
302 ncc.a[3*i + 1] = (int) (-0.28f * a + 0.5f);
303 ncc.a[3*i + 2] = (int) (-1.11f * a + 0.5f);
304
305 ncc.b[3*i + 0] = (int) ( 0.62f * b + 0.5f);
306 ncc.b[3*i + 1] = (int) (-0.64f * b + 0.5f);
307 ncc.b[3*i + 2] = (int) ( 1.73f * b + 0.5f);
308 }
309
310
311 if ((dither & TX_DITHER_MASK) == TX_DITHER_ERR) {
312 txYABtoPal256((long *)pxMip->pal, (long *) &ncc.y[0]);
313 txDiffuseIndex(pxMip, txMip, pixsize, pxMip->pal, 256);
314 }
315 else {
316
317 /* For each mipmap, translate input RGB values to YIQ, and quantize */
318 /* Optionally, dither using 4x4 dither matrix */
319 /* Return the quantized YIQ values */
320
321 w = txMip->width;
322 h = txMip->height;
323
324 for (i=0; i<txMip->depth; i++) {
325 _txImgNcc(pxMip->data[i], txMip->data[i], w, h,format,dither);
326 if (w > 1) w >>= 1;
327 if (h > 1) h >>= 1;
328 }
329 }
330
331 // Copy decompression table.
332 for (i=0; i<16; i++) pxMip->pal[ i] = ncc.y[i];
333 for (i=0; i<12; i++) pxMip->pal[16+i] = ncc.a[i];
334 for (i=0; i<12; i++) pxMip->pal[28+i] = ncc.b[i];
335}
Note: See TracBrowser for help on using the repository browser.