|
|
1.1.1.3 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
1.1.1.3 root 3: *
1.1 root 4: * Common code needed by all the various graphics systems.
1.1.1.3 root 5: *
1.1 root 6: * (c) 1996 Bernd Schmidt, Ed Hanway, Samuel Devulder
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include "config.h"
13: #include "options.h"
1.1.1.6 root 14: #include "threaddep/thread.h"
1.1 root 15: #include "memory.h"
16: #include "custom.h"
17: #include "keyboard.h"
18: #include "xwin.h"
19:
20: #define RED 0
21: #define GRN 1
22: #define BLU 2
23:
24: /*
25: * dither matrix
26: */
1.1.1.3 root 27: static uae_u8 dither[4][4] =
1.1 root 28: {
1.1.1.4 root 29: { 0, 8, 2, 10 },
30: { 12, 4, 14, 6 },
31: { 3, 11, 1, 9 },
32: { 14 /* 15 */, 7, 13, 5 }
1.1 root 33: };
34:
1.1.1.4 root 35: unsigned long doMask (int p, int bits, int shift)
1.1 root 36: {
37: /* p is a value from 0 to 15 (Amiga color value)
38: * scale to 0..255, shift to align msb with mask, and apply mask */
39:
40: unsigned long val = p * 0x11111111UL;
41: val >>= (32 - bits);
42: val <<= shift;
43:
44: return val;
45: }
46:
1.1.1.4 root 47: int bits_in_mask (unsigned long mask)
48: {
49: int n = 0;
50: while (mask) {
51: n += mask & 1;
52: mask >>= 1;
53: }
54: return n;
55: }
56:
57: int mask_shift (unsigned long mask)
58: {
59: int n = 0;
60: while (!(mask & 1)) {
61: n++;
62: mask >>= 1;
63: }
64: return n;
65: }
66:
67: unsigned long doMask256 (int p, int bits, int shift)
68: {
69: /* p is a value from 0 to 255 (Amiga color value)
70: * shift to align msb with mask, and apply mask */
71:
72: unsigned long val = p * 0x01010101UL;
73: val >>= (32 - bits);
74: val <<= shift;
75:
76: return val;
77: }
78:
1.1.1.8 root 79: static unsigned int doColor (int i, int bits, int shift)
1.1.1.5 root 80: {
81: int shift2;
82: if(bits >= 8) shift2 = 0; else shift2 = 8 - bits;
83: return (i >> shift2) << shift;
84: }
85:
1.1.1.4 root 86: void alloc_colors64k (int rw, int gw, int bw, int rs, int gs, int bs)
1.1 root 87: {
88: int i;
1.1.1.4 root 89: for (i = 0; i < 4096; i++) {
1.1 root 90: int r = i >> 8;
91: int g = (i >> 4) & 0xF;
92: int b = i & 0xF;
93: xcolors[i] = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs);
94: }
1.1.1.5 root 95: /* create AGA color tables */
1.1.1.8 root 96: for(i = 0; i < 256; i++) {
1.1.1.5 root 97: xredcolors[i] = doColor(i, rw, rs);
98: xgreencolors[i] = doColor(i, gw, gs);
99: xbluecolors[i] = doColor(i, bw, bs);
100: }
1.1 root 101: }
102:
103: static int allocated[4096];
1.1.1.2 root 104: static int color_diff[4096];
105: static int newmaxcol = 0;
106:
1.1.1.4 root 107: void setup_maxcol (int max)
1.1.1.2 root 108: {
109: newmaxcol = max;
110: }
1.1 root 111:
1.1.1.4 root 112: void alloc_colors256 (allocfunc_type allocfunc)
1.1 root 113: {
114: int nb_cols[3]; /* r,g,b */
1.1.1.2 root 115: int maxcol = newmaxcol == 0 ? 256 : newmaxcol;
1.1.1.8 root 116: int i,j,k,l;
1.1 root 117:
118: xcolnr *map;
1.1.1.3 root 119:
1.1.1.4 root 120: map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol);
121: if (!map) {
122: write_log ("Not enough mem for colormap!\n");
123: abort ();
1.1.1.3 root 124: }
125:
1.1 root 126: /*
127: * compute #cols per components
128: */
1.1.1.4 root 129: for (i = 1; i*i*i <= maxcol; ++i)
1.1 root 130: ;
131: --i;
132:
133: nb_cols[RED] = i;
134: nb_cols[GRN] = i;
135: nb_cols[BLU] = i;
136:
137: /*
138: * set the colormap
139: */
1.1.1.4 root 140: l = 0;
141: for (i = 0; i < nb_cols[RED]; ++i) {
1.1.1.3 root 142: int r = (i * 15) / (nb_cols[RED] - 1);
1.1.1.4 root 143: for (j = 0; j < nb_cols[GRN]; ++j) {
1.1.1.3 root 144: int g = (j * 15) / (nb_cols[GRN] - 1);
1.1.1.4 root 145: for (k = 0; k < nb_cols[BLU]; ++k) {
1.1.1.3 root 146: int b = (k * 15) / (nb_cols[BLU] - 1);
1.1 root 147: int result;
1.1.1.4 root 148: result = allocfunc (r, g, b, map + l);
1.1 root 149: l++;
150: }
151: }
152: }
153: /* printf("%d color(s) lost\n",maxcol - l);*/
154:
155: /*
156: * for each component compute the mapping
157: */
158: {
159: int diffr, diffg, diffb, maxdiff = 0, won = 0, lost;
160: int r, d = 8;
1.1.1.4 root 161: for (r = 0; r < 16; ++r) {
1.1 root 162: int cr, g, q;
1.1.1.3 root 163:
1.1.1.4 root 164: k = nb_cols[RED]-1;
1.1 root 165: cr = (r * k) / 15;
1.1.1.4 root 166: q = (r * k) % 15;
167: if (q > d && cr < k) ++cr;
168: diffr = abs (cr*k - r);
169: for (g = 0; g < 16; ++g) {
1.1 root 170: int cg, b;
1.1.1.3 root 171:
1.1.1.4 root 172: k = nb_cols[GRN]-1;
1.1 root 173: cg = (g * k) / 15;
174: q = (g * k) % 15;
1.1.1.4 root 175: if (q > d && cg < k) ++cg;
176: diffg = abs (cg*k - g);
177: for (b = 0; b < 16; ++b) {
178: int cb, rgb = (r << 8) | (g << 4) | b;
1.1 root 179:
1.1.1.4 root 180: k = nb_cols[BLU]-1;
1.1 root 181: cb = (b * k) / 15;
1.1.1.4 root 182: q = (b * k) % 15;
183: if (q > d && cb < k) ++cb;
184: diffb = abs (cb*k - b);
185: xcolors[rgb] = map[(cr * nb_cols[GRN] + cg) * nb_cols[BLU] + cb];
186: color_diff[rgb] = diffr + diffg + diffb;
1.1.1.2 root 187: if (color_diff[rgb] > maxdiff)
188: maxdiff = color_diff[rgb];
1.1 root 189: }
190: }
191: }
192: while (maxdiff > 0 && l < maxcol) {
193: int newmaxdiff = 0;
194: lost = 0; won++;
1.1.1.4 root 195: for (r = 15; r >= 0; r--) {
196: int g;
1.1.1.3 root 197:
1.1.1.4 root 198: for (g = 15; g >= 0; g--) {
199: int b;
1.1.1.3 root 200:
1.1.1.4 root 201: for (b = 15; b >= 0; b--) {
202: int rgb = (r << 8) | (g << 4) | b;
1.1 root 203:
1.1.1.2 root 204: if (color_diff[rgb] == maxdiff) {
1.1 root 205: int result;
1.1.1.3 root 206:
1.1 root 207: if (l >= maxcol)
208: lost++;
209: else {
1.1.1.4 root 210: result = allocfunc (r, g, b, xcolors + rgb);
1.1 root 211: l++;
212: }
1.1.1.2 root 213: color_diff[rgb] = 0;
214: } else if (color_diff[rgb] > newmaxdiff)
215: newmaxdiff = color_diff[rgb];
1.1.1.3 root 216:
1.1 root 217: }
218: }
219: }
220: maxdiff = newmaxdiff;
221: }
222: /* printf("%d color(s) lost, %d stages won\n",lost, won);*/
223: }
224: free (map);
225: }
226:
227: /*
228: * This dithering process works by letting UAE run internaly in 12bit
229: * mode and doing the dithering on the fly when rendering to the display.
230: * The dithering algorithm is quite fast but uses lot of memory (4*8*2^12 =
1.1.1.3 root 231: * 128Kb). I don't think that is a trouble right now, but when UAE will
1.1 root 232: * emulate AGA and work internaly in 24bit mode, that dithering algorithm
233: * will need 4*8*2^24 = 512Mb. Obviously that fast algorithm will not be
1.1.1.3 root 234: * tractable. However, we could then use an other algorithm, slower, but
1.1 root 235: * far more reasonable (I am thinking about the one that is used in DJPEG).
236: */
237:
1.1.1.3 root 238: uae_u8 cidx[4][8*4096]; /* fast, but memory hungry =:-( */
1.1 root 239:
240: /*
241: * Compute dithering structures
242: */
1.1.1.4 root 243: void setup_greydither_maxcol (int maxcol, allocfunc_type allocfunc)
1.1 root 244: {
1.1.1.4 root 245: int i,j,k;
1.1 root 246: xcolnr *map;
1.1.1.3 root 247:
1.1 root 248: for (i = 0; i < 4096; i++)
249: xcolors[i] = i;
1.1.1.3 root 250:
1.1.1.4 root 251: map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol);
252: if (!map) {
253: write_log ("Not enough mem for colormap!\n");
1.1.1.3 root 254: abort();
255: }
1.1 root 256:
257: /*
258: * set the colormap
259: */
1.1.1.4 root 260: for (i = 0; i < maxcol; ++i) {
1.1 root 261: int c, result;
262: c = (15 * i + (maxcol-1)/2) / (maxcol - 1);
1.1.1.3 root 263: result = allocfunc(c, c, c, map + i);
1.1 root 264: /* @@@ check for errors */
265: }
266:
267: /*
268: * for each componant compute the mapping
269: */
1.1.1.4 root 270: for (i = 0; i < 4; ++i) {
271: for (j = 0; j < 4; ++j) {
1.1 root 272: int r, d = dither[i][j]*17;
1.1.1.4 root 273: for (r = 0; r<16; ++r) {
1.1 root 274: int g;
1.1.1.4 root 275: for (g = 0; g < 16; ++g) {
1.1 root 276: int b;
1.1.1.4 root 277: for (b = 0; b < 16; ++b) {
278: int rgb = (r << 8) | (g << 4) | b;
1.1 root 279: int c,p,q;
1.1.1.3 root 280:
281: c = (77 * r +
282: 151 * g +
1.1 root 283: 28 * b) / 15; /* c in 0..256 */
1.1.1.3 root 284:
285: k = maxcol-1;
1.1 root 286: p = (c * k) / 256;
287: q = (c * k) % 256;
1.1.1.4 root 288: if (q /*/ k*/> d /*/ k*/ && p < k) ++p;
1.1.1.2 root 289: /* sam: ^^^^^^^ */
290: /* It seems that produces better output */
1.1.1.3 root 291: cidx[i][rgb + (j+4)*4096] =
1.1 root 292: cidx[i][rgb + j*4096] = map[p];
293: }
294: }
295: }
296: }
297: }
298: free (map);
299: }
300:
1.1.1.4 root 301: void setup_greydither (int bits, allocfunc_type allocfunc)
1.1.1.2 root 302: {
303: setup_greydither_maxcol(1 << bits, allocfunc);
304: }
305:
1.1.1.4 root 306: void setup_dither (int bits, allocfunc_type allocfunc)
1.1 root 307: {
308: int nb_cols[3]; /* r,g,b */
309: int maxcol = 1 << bits;
1.1.1.4 root 310: int i,j,k,l;
1.1 root 311:
312: xcolnr *map;
313: int *redvals, *grnvals, *bluvals;
1.1.1.3 root 314:
1.1.1.4 root 315: map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol);
316: if (!map) {
317: write_log ("Not enough mem for colormap!\n");
1.1.1.3 root 318: abort();
319: }
1.1 root 320:
321: for (i = 0; i < 4096; i++)
322: xcolors[i] = i;
1.1.1.3 root 323:
1.1 root 324: /*
325: * compute #cols per components
326: */
1.1.1.4 root 327: for (i = 1; i*i*i <= maxcol; ++i)
1.1 root 328: ;
329: --i;
330:
331: nb_cols[RED] = i;
332: nb_cols[GRN] = i;
333: nb_cols[BLU] = i;
334:
1.1.1.4 root 335: if (nb_cols[RED]*(++i)*nb_cols[BLU] <= maxcol) {
1.1 root 336: nb_cols[GRN] = i;
1.1.1.4 root 337: if ((i)*nb_cols[GRN]*nb_cols[BLU] <= maxcol)
338: nb_cols[RED] = i;
1.1 root 339: }
340:
1.1.1.4 root 341: redvals = (int *)malloc (sizeof(int) * maxcol);
1.1 root 342: grnvals = redvals + nb_cols[RED];
1.1.1.3 root 343: bluvals = grnvals + nb_cols[GRN];
1.1 root 344: /*
345: * set the colormap
346: */
1.1.1.4 root 347: l = 0;
348: for (i = 0; i < nb_cols[RED]; ++i) {
1.1.1.3 root 349: int r = (i * 15) / (nb_cols[RED] - 1);
1.1 root 350: redvals[i] = r;
1.1.1.4 root 351: for (j = 0; j < nb_cols[GRN]; ++j) {
1.1.1.3 root 352: int g = (j * 15) / (nb_cols[GRN] - 1);
1.1 root 353: grnvals[j] = g;
1.1.1.4 root 354: for (k = 0; k < nb_cols[BLU]; ++k) {
1.1.1.3 root 355: int b = (k * 15) / (nb_cols[BLU] - 1);
1.1 root 356: int result;
357: bluvals[k] = b;
358: result = allocfunc(r, g, b, map + l);
359: l++;
360: }
361: }
362: }
1.1.1.7 root 363: /* write_log ("%d color(s) lost\n",maxcol - l);*/
1.1 root 364:
365: /*
366: * for each component compute the mapping
367: */
368: {
369: int r;
1.1.1.4 root 370: for (r = 0; r < 16; ++r) {
1.1 root 371: int g;
1.1.1.4 root 372: for (g = 0; g < 16; ++g) {
1.1 root 373: int b;
1.1.1.4 root 374: for (b = 0; b < 16; ++b) {
375: int rgb = (r << 8) | (g << 4) | b;
1.1 root 376:
1.1.1.4 root 377: for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) {
1.1 root 378: int d = dither[i][j];
379: int cr, cg, cb, k, q;
380: #if 0 /* Slightly different algorithm. Needs some tuning. */
1.1.1.4 root 381: int rederr = 0, grnerr = 0, bluerr = 0;
382:
1.1 root 383: k = nb_cols[RED]-1;
384: cr = r * k / 15;
385: q = r * k - 15*cr;
1.1.1.4 root 386: if (cr < 0)
387: cr = 0;
388: else if (q / k > d / k && rederr <= 0)
389: ++cr;
1.1 root 390: if (cr > k) cr = k;
391: rederr += redvals[cr]-r;
1.1.1.3 root 392:
1.1 root 393: k = nb_cols[GRN]-1;
394: cg = g * k / 15;
395: q = g * k - 15*cg;
1.1.1.4 root 396: if (cg < 0)
397: cg = 0;
398: else if (q / k > d / k && grnerr <= 0)
399: ++cg;
1.1 root 400: if (cg > k) cg = k;
401: grnerr += grnvals[cg]-g;
402:
403: k = nb_cols[BLU]-1;
404: cb = b * k / 15;
405: q = b * k - 15*cb;
1.1.1.4 root 406: if (cb < 0)
407: cb = 0;
408: else if (q / k > d / k && bluerr <= 0)
409: ++cb;
1.1 root 410: if (cb > k) cb = k;
411: bluerr += bluvals[cb]-b;
412: #else
413: k = nb_cols[RED]-1;
414: cr = r * k / 15;
415: q = r * k - 15*cr;
1.1.1.4 root 416: if (cr < 0)
417: cr = 0;
418: else if (q /*/ k*/ > d /*/ k*/)
419: ++cr;
1.1 root 420: if (cr > k) cr = k;
1.1.1.3 root 421:
1.1 root 422: k = nb_cols[GRN]-1;
423: cg = g * k / 15;
424: q = g * k - 15*cg;
1.1.1.4 root 425: if (cg < 0)
426: cg = 0;
427: else if (q /*/ k*/ > d /*/ k*/)
428: ++cg;
1.1 root 429: if (cg > k) cg = k;
430:
431: k = nb_cols[BLU]-1;
432: cb = b * k / 15;
433: q = b * k - 15*cb;
1.1.1.4 root 434: if (cb < 0)
435: cb = 0;
436: else if (q /*/ k*/ > d /*/ k*/)
437: ++cb;
1.1 root 438: if (cb > k) cb = k;
439: #endif
440: cidx[i][rgb + (j+4)*4096] = cidx[i][rgb + j*4096] = map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb];
441: }
442: }
443: }
444: }
445: }
1.1.1.4 root 446: free (redvals);
1.1 root 447: free (map);
448: }
449:
1.1.1.3 root 450: #if !defined X86_ASSEMBLY
1.1 root 451: /*
452: * Dither the line.
453: * Make sure you call this only with (len & 3) == 0, or you'll just make
454: * yourself unhappy.
455: */
456:
1.1.1.4 root 457: void DitherLine (uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits)
1.1 root 458: {
1.1.1.3 root 459: uae_u8 *dith = cidx[y&3]+(x&3)*4096;
460: uae_u8 d = 0;
1.1 root 461: int bitsleft = 8;
1.1.1.3 root 462:
1.1.1.4 root 463: if (bits == 8) {
464: while (len > 0) {
1.1.1.2 root 465: *l++ = dith[0*4096 + *r4g4b4++];
466: *l++ = dith[1*4096 + *r4g4b4++];
467: *l++ = dith[2*4096 + *r4g4b4++];
468: *l++ = dith[3*4096 + *r4g4b4++];
469: len -= 4;
470: }
471: return;
472: }
473:
1.1.1.4 root 474: while (len) {
1.1 root 475: int v;
476: v = dith[0*4096 + *r4g4b4++];
477: bitsleft -= bits;
478: d |= (v << bitsleft);
479: if (!bitsleft)
480: *l++ = d, bitsleft = 8, d = 0;
1.1.1.3 root 481:
1.1 root 482: v = dith[1*4096 + *r4g4b4++];
483: bitsleft -= bits;
484: d |= (v << bitsleft);
485: if (!bitsleft)
486: *l++ = d, bitsleft = 8, d = 0;
1.1.1.3 root 487:
1.1 root 488: v = dith[2*4096 + *r4g4b4++];
489: bitsleft -= bits;
490: d |= (v << bitsleft);
491: if (!bitsleft)
492: *l++ = d, bitsleft = 8, d = 0;
1.1.1.3 root 493:
1.1 root 494: v = dith[3*4096 + *r4g4b4++];
495: bitsleft -= bits;
496: d |= (v << bitsleft);
497: if (!bitsleft)
498: *l++ = d, bitsleft = 8, d = 0;
499: len -= 4;
500: }
501: }
502: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.