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