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 |
|
---|
32 | static int
|
---|
33 | dithmat[4][4] = { 0, 8, 2, 10,
|
---|
34 | 12, 4, 14, 6,
|
---|
35 | 3, 11, 1, 9,
|
---|
36 | 15, 7, 13, 5 };
|
---|
37 |
|
---|
38 | static 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 |
|
---|
45 | static 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 |
|
---|
82 | static 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 |
|
---|
127 | static 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 |
|
---|
169 | static 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 |
|
---|
253 | void
|
---|
254 | txMipNcc(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 | }
|
---|