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