1  /*
2   * UAE - The Un*x Amiga Emulator
3   *
4   * Screen drawing functions
5   *
6   * Copyright 1995-2000 Bernd Schmidt
7   * Copyright 1995 Alessandro Bissacco
8   * Copyright 2000,2001 Toni Wilen
9   */
10 
11 /* There are a couple of concepts of "coordinates" in this file.
12    - DIW coordinates
13    - DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2)
14    - Pixel coordinates
15      * in the Amiga's resolution as determined by BPLCON0 ("Amiga coordinates")
16      * in the window resolution as determined by the preferences ("window coordinates").
17      * in the window resolution, and with the origin being the topmost left corner of
18        the window ("native coordinates")
19    One note about window coordinates.  The visible area depends on the width of the
20    window, and the centering code.  The first visible horizontal window coordinate is
21    often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead.
22 
23    One important thing to remember: DIW coordinates are in the lowest possible
24    resolution.
25 
26    To prevent extremely bad things (think pixels cut in half by window borders) from
27    happening, all ports should restrict window widths to be multiples of 16 pixels.  */
28 
29 #include "sysconfig.h"
30 #include "sysdeps.h"
31 
32 #include <ctype.h>
33 #include <assert.h>
34 
35 #include "options.h"
36 #include "threaddep/thread.h"
37 #include "uae.h"
38 #include "memory.h"
39 #include "custom.h"
40 #include "newcpu.h"
41 #include "xwin.h"
42 #include "autoconf.h"
43 #include "gui.h"
44 #include "picasso96.h"
45 #include "drawing.h"
46 #include "savestate.h"
47 
48 int lores_factor, lores_shift;
49 
50 /* The shift factor to apply when converting between Amiga coordinates and window
51    coordinates.  Zero if the resolution is the same, positive if window coordinates
52    have a higher resolution (i.e. we're stretching the image), negative if window
53    coordinates have a lower resolution (i.e. we're shrinking the image).  */
54 static int res_shift;
55 
56 static int interlace_seen = 0;
57 
58 /* Lookup tables for dual playfields.  The dblpf_*1 versions are for the case
59    that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has
60    priority.  If we need an array for non-dual playfield mode, it has no number.  */
61 /* The dbplpf_ms? arrays contain a shift value.  plf_spritemask is initialized
62    to contain two 16 bit words, with the appropriate mask if pf1 is in the
63    foreground being at bit offset 0, the one used if pf2 is in front being at
64    offset 16.  */
65 
66 static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256];
67 static int dblpf_ind1[256], dblpf_ind2[256];
68 
69 static int dblpf_2nd1[256], dblpf_2nd2[256];
70 static int dblpf_ind1_aga[256], dblpf_ind2_aga[256];
71 
72 static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 };
73 
74 static int sprite_offs[256];
75 
76 static uae_u32 clxtab[256];
77 
78 /* Video buffer description structure. Filled in by the graphics system
79  * dependent code. */
80 
81 struct vidbuf_description gfxvidinfo;
82 
83 /* OCS/ECS color lookup table. */
84 xcolnr xcolors[4096];
85 /* AGA mode color lookup tables */
86 unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256];
87 
88 struct color_entry colors_for_drawing;
89 
90 /* The size of these arrays is pretty arbitrary; it was chosen to be "more
91    than enough".  The coordinates used for indexing into these arrays are
92    almost, but not quite, Amiga coordinates (there's a constant offset).  */
93 union {
94     /* Let's try to align this thing. */
95     double uupzuq;
96     long int cruxmedo;
97     uae_u8 apixels[MAX_PIXELS_PER_LINE * 2];
98     uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / 2];
99     uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / 4];
100 } pixdata;
101 
102 uae_u16 spixels[2 * MAX_SPR_PIXELS];
103 /* Eight bits for every pixel.  */
104 union sps_union spixstate;
105 
106 static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2];
107 static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE * 2]; /* AGA dualplayfield sprite */
108 
109 char *xlinebuffer;
110 
111 static int *amiga2aspect_line_map, *native2amiga_line_map;
112 static char *row_map[2049];
113 static int max_drawn_amiga_line;
114 
115 /* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */
116 typedef void (*line_draw_func)(int, int);
117 
118 #define LINE_UNDECIDED 1
119 #define LINE_DECIDED 2
120 #define LINE_DECIDED_DOUBLE 3
121 #define LINE_AS_PREVIOUS 4
122 #define LINE_BLACK 5
123 #define LINE_REMEMBERED_AS_BLACK 6
124 #define LINE_DONE 7
125 #define LINE_DONE_AS_PREVIOUS 8
126 #define LINE_REMEMBERED_AS_PREVIOUS 9
127 
128 static char *line_drawn;
129 static char linestate[(MAXVPOS + 1)*2 + 1];
130 
131 uae_u8 line_data[(MAXVPOS + 1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
132 
133 /* Centering variables.  */
134 static int min_diwstart, max_diwstop;
135 /* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible
136    area, VISIBLE_RIGHT_BORDER the right border.  These are in window coordinates.  */
137 static int visible_left_border, visible_right_border;
138 static int linetoscr_x_adjust_bytes;
139 static int thisframe_y_adjust;
140 static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen;
141 static int extra_y_adjust;
142 int thisframe_first_drawn_line, thisframe_last_drawn_line;
143 
144 /* A frame counter that forces a redraw after at least one skipped frame in
145    interlace mode.  */
146 static int last_redraw_point;
147 
148 static int first_drawn_line, last_drawn_line;
149 static int first_block_line, last_block_line;
150 
151 #define NO_BLOCK -3
152 
153 /* These are generated by the drawing code from the line_decisions array for
154    each line that needs to be drawn.  These are basically extracted out of
155    bit fields in the hardware registers.  */
156 static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt;
157 static int bplres, adjusted_bplres;
158 static uae_u32 plf_sprite_mask;
159 static int sbasecol[2];
160 
161 int picasso_requested_on;
162 int picasso_on;
163 
164 int inhibit_frame;
165 
166 int framecnt = 0;
167 static int frame_redraw_necessary;
168 static int picasso_redraw_necessary;
169 
count_frame(void)170 STATIC_INLINE void count_frame (void)
171 {
172     framecnt++;
173     if (framecnt >= currprefs.gfx_framerate)
174 	framecnt = 0;
175 }
176 
coord_native_to_amiga_x(int x)177 int coord_native_to_amiga_x (int x)
178 {
179     x += visible_left_border;
180     x <<= (1 - lores_shift);
181     return x + 2*DISPLAY_LEFT_SHIFT - 2*DIW_DDF_OFFSET;
182 }
183 
coord_native_to_amiga_y(int y)184 int coord_native_to_amiga_y (int y)
185 {
186     return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline;
187 }
188 
res_shift_from_window(int x)189 STATIC_INLINE int res_shift_from_window (int x)
190 {
191     if (res_shift >= 0)
192 	return x >> res_shift;
193     return x << -res_shift;
194 }
195 
res_shift_from_amiga(int x)196 STATIC_INLINE int res_shift_from_amiga (int x)
197 {
198     if (res_shift >= 0)
199 	return x >> res_shift;
200     return x << -res_shift;
201 }
202 
notice_screen_contents_lost(void)203 void notice_screen_contents_lost (void)
204 {
205     picasso_redraw_necessary = 1;
206     frame_redraw_necessary = 2;
207 }
208 
209 static struct decision *dp_for_drawing;
210 static struct draw_info *dip_for_drawing;
211 
212 /* Record DIW of the current line for use by centering code.  */
record_diw_line(int first,int last)213 void record_diw_line (int first, int last)
214 {
215     if (last > max_diwstop)
216 	max_diwstop = last;
217     if (first < min_diwstart)
218 	min_diwstart = first;
219 }
220 
221 /*
222  * Screen update macros/functions
223  */
224 
225 /* The important positions in the line: where do we start drawing the left border,
226    where do we start drawing the playfield, where do we start drawing the right border.
227    All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER).
228    PLAYFIELD_START and PLAYFIELD_END are in window coordinates.  */
229 static int playfield_start, playfield_end;
230 
231 static int pixels_offset;
232 static int src_pixel;
233 /* How many pixels in window coordinates which are to the left of the left border.  */
234 static int unpainted;
235 
236 /* Initialize the variables necessary for drawing a line.
237  * This involves setting up start/stop positions and display window
238  * borders.  */
pfield_init_linetoscr(void)239 static void pfield_init_linetoscr (void)
240 {
241     /* First, get data fetch start/stop in DIW coordinates.  */
242     int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET;
243     int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET;
244     /* Compute datafetch start/stop in pixels; native display coordinates.  */
245     int native_ddf_left = coord_hw_to_window_x (ddf_left);
246     int native_ddf_right = coord_hw_to_window_x (ddf_right);
247 
248     int linetoscr_diw_start = dp_for_drawing->diwfirstword;
249     int linetoscr_diw_end = dp_for_drawing->diwlastword;
250 
251     if (dip_for_drawing->nr_sprites == 0) {
252 	if (linetoscr_diw_start < native_ddf_left)
253 	    linetoscr_diw_start = native_ddf_left;
254 	if (linetoscr_diw_end > native_ddf_right)
255 	    linetoscr_diw_end = native_ddf_right;
256     }
257 
258     /* Perverse cases happen. */
259     if (linetoscr_diw_end < linetoscr_diw_start)
260 	linetoscr_diw_end = linetoscr_diw_start;
261 
262     playfield_start = linetoscr_diw_start;
263     playfield_end = linetoscr_diw_end;
264 
265     if (playfield_start < visible_left_border)
266 	playfield_start = visible_left_border;
267     if (playfield_start > visible_right_border)
268 	playfield_start = visible_right_border;
269     if (playfield_end < visible_left_border)
270 	playfield_end = visible_left_border;
271     if (playfield_end > visible_right_border)
272 	playfield_end = visible_right_border;
273 
274     /* Now, compute some offsets.  */
275 
276     res_shift = lores_shift - bplres;
277     ddf_left -= DISPLAY_LEFT_SHIFT;
278     ddf_left <<= bplres;
279     pixels_offset = MAX_PIXELS_PER_LINE - ddf_left;
280 
281     unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start;
282     src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left + unpainted);
283 
284     if (dip_for_drawing->nr_sprites == 0)
285 	return;
286     /* Must clear parts of apixels.  */
287     if (linetoscr_diw_start < native_ddf_left) {
288 	int size = res_shift_from_window (native_ddf_left - linetoscr_diw_start);
289 	linetoscr_diw_start = native_ddf_left;
290 	memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size);
291     }
292     if (linetoscr_diw_end > native_ddf_right) {
293 	int pos = res_shift_from_window (native_ddf_right - native_ddf_left);
294 	int size = res_shift_from_window (linetoscr_diw_end - native_ddf_right);
295 	linetoscr_diw_start = native_ddf_left;
296 	memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size);
297     }
298 }
299 
300 /* If C++ compilers didn't suck, we'd use templates.  */
301 
302 #define TYPE uae_u8
303 #define LNAME linetoscr_8
304 #define SRC_INC 1
305 #define HDOUBLE 0
306 #define AGAC 0
307 #include "linetoscr.c"
308 #define LNAME linetoscr_8_stretch1
309 #define SRC_INC 1
310 #define HDOUBLE 1
311 #define AGAC 0
312 #include "linetoscr.c"
313 #define LNAME linetoscr_8_shrink1
314 #define SRC_INC 2
315 #define HDOUBLE 0
316 #define AGAC 0
317 #include "linetoscr.c"
318 
319 #define LNAME linetoscr_8_aga
320 #define SRC_INC 1
321 #define HDOUBLE 0
322 #define AGAC 1
323 #include "linetoscr.c"
324 #define LNAME linetoscr_8_stretch1_aga
325 #define SRC_INC 1
326 #define HDOUBLE 1
327 #define AGAC 1
328 #include "linetoscr.c"
329 #define LNAME linetoscr_8_shrink1_aga
330 #define SRC_INC 2
331 #define HDOUBLE 0
332 #define AGAC 1
333 #include "linetoscr.c"
334 
335 #undef TYPE
336 
337 #define TYPE uae_u16
338 #define LNAME linetoscr_16
339 #define SRC_INC 1
340 #define HDOUBLE 0
341 #define AGAC 0
342 #include "linetoscr.c"
343 #define LNAME linetoscr_16_stretch1
344 #define SRC_INC 1
345 #define HDOUBLE 1
346 #define AGAC 0
347 #include "linetoscr.c"
348 #define LNAME linetoscr_16_shrink1
349 #define SRC_INC 2
350 #define HDOUBLE 0
351 #define AGAC 0
352 #include "linetoscr.c"
353 
354 #define LNAME linetoscr_16_aga
355 #define SRC_INC 1
356 #define HDOUBLE 0
357 #define AGAC 1
358 #include "linetoscr.c"
359 #define LNAME linetoscr_16_stretch1_aga
360 #define SRC_INC 1
361 #define HDOUBLE 1
362 #define AGAC 1
363 #include "linetoscr.c"
364 #define LNAME linetoscr_16_shrink1_aga
365 #define SRC_INC 2
366 #define HDOUBLE 0
367 #define AGAC 1
368 #include "linetoscr.c"
369 
370 #undef TYPE
371 
372 #define TYPE uae_u32
373 #define LNAME linetoscr_32
374 #define SRC_INC 1
375 #define HDOUBLE 0
376 #define AGAC 0
377 #include "linetoscr.c"
378 #define LNAME linetoscr_32_stretch1
379 #define SRC_INC 1
380 #define HDOUBLE 1
381 #define AGAC 0
382 #include "linetoscr.c"
383 #define LNAME linetoscr_32_shrink1
384 #define SRC_INC 2
385 #define HDOUBLE 0
386 #define AGAC 0
387 #include "linetoscr.c"
388 
389 #define LNAME linetoscr_32_aga
390 #define SRC_INC 1
391 #define HDOUBLE 0
392 #define AGAC 1
393 #include "linetoscr.c"
394 #define LNAME linetoscr_32_stretch1_aga
395 #define SRC_INC 1
396 #define HDOUBLE 1
397 #define AGAC 1
398 #include "linetoscr.c"
399 #define LNAME linetoscr_32_shrink1_aga
400 #define SRC_INC 2
401 #define HDOUBLE 0
402 #define AGAC 1
403 #include "linetoscr.c"
404 
405 #undef TYPE
406 
fill_line_8(char * buf,int start,int stop)407 static void fill_line_8 (char *buf, int start, int stop)
408 {
409     uae_u8 *b = (uae_u8 *)buf;
410     int i;
411     xcolnr col = colors_for_drawing.acolors[0];
412     for (i = start; i < stop; i++)
413 	b[i] = col;
414 }
fill_line_16(char * buf,int start,int stop)415 static void fill_line_16 (char *buf, int start, int stop)
416 {
417     uae_u16 *b = (uae_u16 *)buf;
418     int i;
419     xcolnr col = colors_for_drawing.acolors[0];
420     for (i = start; i < stop; i++)
421 	b[i] = col;
422 }
fill_line_32(char * buf,int start,int stop)423 static void fill_line_32 (char *buf, int start, int stop)
424 {
425     uae_u32 *b = (uae_u32 *)buf;
426     int i;
427     xcolnr col = colors_for_drawing.acolors[0];
428     for (i = start; i < stop; i++)
429 	b[i] = col;
430 }
431 
fill_line(void)432 STATIC_INLINE void fill_line (void)
433 {
434     int shift;
435     int nints, nrem;
436     int *start;
437     xcolnr val;
438 
439     shift = 0;
440     if (gfxvidinfo.pixbytes == 2)
441 	shift = 1;
442     if (gfxvidinfo.pixbytes == 4)
443 	shift = 2;
444 
445     nints = gfxvidinfo.width >> (2-shift);
446     nrem = nints & 7;
447     nints &= ~7;
448     start = (int *)(((char *)xlinebuffer) + (visible_left_border << shift));
449     val = colors_for_drawing.acolors[0];
450     if (gfxvidinfo.pixbytes == 2)
451 	val |= val << 16;
452     for (; nints > 0; nints -= 8, start += 8) {
453 	*start = val;
454 	*(start+1) = val;
455 	*(start+2) = val;
456 	*(start+3) = val;
457 	*(start+4) = val;
458 	*(start+5) = val;
459 	*(start+6) = val;
460 	*(start+7) = val;
461     }
462 
463     switch (nrem) {
464      case 7:
465 	*start++ = val;
466      case 6:
467 	*start++ = val;
468      case 5:
469 	*start++ = val;
470      case 4:
471 	*start++ = val;
472      case 3:
473 	*start++ = val;
474      case 2:
475 	*start++ = val;
476      case 1:
477 	*start = val;
478     }
479 }
480 
481 static int linetoscr_double_offset;
482 
pfield_do_linetoscr(int start,int stop)483 static void pfield_do_linetoscr (int start, int stop)
484 {
485     if (currprefs.chipset_mask & CSMASK_AGA) {
486 	if (res_shift == 0)
487 	    switch (gfxvidinfo.pixbytes) {
488 	    case 1: src_pixel = linetoscr_8_aga (src_pixel, start, stop); break;
489 	    case 2: src_pixel = linetoscr_16_aga (src_pixel, start, stop); break;
490 	    case 4: src_pixel = linetoscr_32_aga (src_pixel, start, stop); break;
491 	    }
492 	else if (res_shift > 0)
493 	    switch (gfxvidinfo.pixbytes) {
494 	    case 1: src_pixel = linetoscr_8_stretch1_aga (src_pixel, start, stop); break;
495 	    case 2: src_pixel = linetoscr_16_stretch1_aga (src_pixel, start, stop); break;
496 	    case 4: src_pixel = linetoscr_32_stretch1_aga (src_pixel, start, stop); break;
497 	    }
498 	else if (res_shift < 0)
499 	    switch (gfxvidinfo.pixbytes) {
500 	    case 1: src_pixel = linetoscr_8_shrink1_aga (src_pixel, start, stop); break;
501 	    case 2: src_pixel = linetoscr_16_shrink1_aga (src_pixel, start, stop); break;
502 	    case 4: src_pixel = linetoscr_32_shrink1_aga (src_pixel, start, stop); break;
503 	    }
504 	else
505 	    abort ();
506     } else {
507 	if (res_shift == 0)
508 	    switch (gfxvidinfo.pixbytes) {
509 	    case 1: src_pixel = linetoscr_8 (src_pixel, start, stop); break;
510 	    case 2: src_pixel = linetoscr_16 (src_pixel, start, stop); break;
511 	    case 4: src_pixel = linetoscr_32 (src_pixel, start, stop); break;
512 	    }
513 	else if (res_shift == 1)
514 	    switch (gfxvidinfo.pixbytes) {
515 	    case 1: src_pixel = linetoscr_8_stretch1 (src_pixel, start, stop); break;
516 	    case 2: src_pixel = linetoscr_16_stretch1 (src_pixel, start, stop); break;
517 	    case 4: src_pixel = linetoscr_32_stretch1 (src_pixel, start, stop); break;
518 	    }
519 	else if (res_shift == -1)
520 	    switch (gfxvidinfo.pixbytes) {
521 	    case 1: src_pixel = linetoscr_8_shrink1 (src_pixel, start, stop); break;
522 	    case 2: src_pixel = linetoscr_16_shrink1 (src_pixel, start, stop); break;
523 	    case 4: src_pixel = linetoscr_32_shrink1 (src_pixel, start, stop); break;
524 	    }
525 	else
526 	    abort ();
527     }
528 }
529 
pfield_do_fill_line(int start,int stop)530 static void pfield_do_fill_line (int start, int stop)
531 {
532     switch (gfxvidinfo.pixbytes) {
533     case 1: fill_line_8 (xlinebuffer, start, stop); break;
534     case 2: fill_line_16 (xlinebuffer, start, stop); break;
535     case 4: fill_line_32 (xlinebuffer, start, stop); break;
536     }
537 }
538 
pfield_do_linetoscr_full(int double_line)539 static void pfield_do_linetoscr_full (int double_line)
540 {
541     char *oldxlb = (char *)xlinebuffer;
542     int old_src_pixel = src_pixel;
543 
544     pfield_do_linetoscr (playfield_start, playfield_end);
545     xlinebuffer = oldxlb + linetoscr_double_offset;
546     src_pixel = old_src_pixel;
547     pfield_do_linetoscr (playfield_start, playfield_end);
548 }
549 
dummy_worker(int start,int stop)550 static void dummy_worker (int start, int stop)
551 {
552 }
553 
554 static unsigned int ham_lastcolor;
555 
556 static int ham_decode_pixel;
557 
558 /* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER),
559    but don't draw anything in.  This is done to prepare HAM_LASTCOLOR for later,
560    when decode_ham runs.  */
init_ham_decoding(void)561 static void init_ham_decoding (void)
562 {
563     int unpainted_amiga = res_shift_from_window (unpainted);
564     ham_decode_pixel = src_pixel;
565     ham_lastcolor = color_reg_get (&colors_for_drawing, 0);
566 
567     if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) {
568 	if (unpainted_amiga > 0) {
569 	    int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1];
570 	    if (currprefs.chipset_mask & CSMASK_AGA)
571 		ham_lastcolor = colors_for_drawing.color_regs_aga[pv];
572 	    else
573 		ham_lastcolor = colors_for_drawing.color_regs_ecs[pv];
574 	}
575     } else if (currprefs.chipset_mask & CSMASK_AGA) {
576 	if (bplplanecnt == 8) { /* AGA mode HAM8 */
577 	    while (unpainted_amiga-- > 0) {
578 		int pv = pixdata.apixels[ham_decode_pixel++];
579 		switch (pv & 0x3) {
580 		case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break;
581 		case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
582 		case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
583 		case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
584 		}
585 	    }
586 	} else if (bplplanecnt == 6) { /* AGA mode HAM6 */
587 	    while (unpainted_amiga-- > 0) {
588 		int pv = pixdata.apixels[ham_decode_pixel++];
589 		switch (pv & 0x30) {
590 		case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break;
591 		case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break;
592 		case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break;
593 		case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break;
594 		}
595 	    }
596 	}
597     } else {
598 	if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */
599 	    while (unpainted_amiga-- > 0) {
600 		int pv = pixdata.apixels[ham_decode_pixel++];
601 		switch (pv & 0x30) {
602 		case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break;
603 		case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
604 		case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
605 		case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
606 		}
607 	    }
608 	}
609     }
610 }
611 
decode_ham(int pix,int stoppos)612 static void decode_ham (int pix, int stoppos)
613 {
614     int todraw_amiga = res_shift_from_window (stoppos - pix);
615 
616     if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) {
617 	while (todraw_amiga-- > 0) {
618 	    int pv = pixdata.apixels[ham_decode_pixel];
619 	    if (currprefs.chipset_mask & CSMASK_AGA)
620 		ham_lastcolor = colors_for_drawing.color_regs_aga[pv];
621 	    else
622 		ham_lastcolor = colors_for_drawing.color_regs_ecs[pv];
623 
624 	    ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
625 	}
626     } else if (currprefs.chipset_mask & CSMASK_AGA) {
627 	if (bplplanecnt == 8) { /* AGA mode HAM8 */
628 	    while (todraw_amiga-- > 0) {
629 		int pv = pixdata.apixels[ham_decode_pixel];
630 		switch (pv & 0x3) {
631 		case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break;
632 		case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
633 		case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
634 		case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
635 		}
636 		ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
637 	    }
638 	} else if (bplplanecnt == 6) { /* AGA mode HAM6 */
639 	    while (todraw_amiga-- > 0) {
640 		int pv = pixdata.apixels[ham_decode_pixel];
641 		switch (pv & 0x30) {
642 		case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break;
643 		case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break;
644 		case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break;
645 		case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break;
646 		}
647 		ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
648 	    }
649 	}
650     } else {
651 	if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */
652 	    while (todraw_amiga-- > 0) {
653 		int pv = pixdata.apixels[ham_decode_pixel];
654 		switch (pv & 0x30) {
655 		case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break;
656 		case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
657 		case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
658 		case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
659 		}
660 		ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
661 	    }
662 	}
663     }
664 }
665 
gen_pfield_tables(void)666 static void gen_pfield_tables (void)
667 {
668     int i;
669 
670     /* For now, the AGA stuff is broken in the dual playfield case. We encode
671      * sprites in dpf mode by ORing the pixel value with 0x80. To make dual
672      * playfield rendering easy, the lookup tables contain are made linear for
673      * values >= 128. That only works for OCS/ECS, though. */
674 
675     for (i = 0; i < 256; i++) {
676 	int plane1 = (i & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8);
677 	int plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8);
678 
679 	dblpf_2nd1[i] = plane1 == 0 ? (plane2 == 0 ? 0 : 2) : 1;
680 	dblpf_2nd2[i] = plane2 == 0 ? (plane1 == 0 ? 0 : 1) : 2;
681 	dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1;
682 	dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2;
683 
684 	dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0;
685 	dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8;
686 	dblpf_ms[i] = i == 0 ? 16 : 8;
687 	if (plane2 > 0)
688 	    plane2 += 8;
689 	dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1);
690 	dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2);
691 
692 	sprite_offs[i] = (i & 15) ? 0 : 2;
693 
694 	clxtab[i] = ((((i & 3) && (i & 12)) << 9)
695 		     | (((i & 3) && (i & 48)) << 10)
696 		     | (((i & 3) && (i & 192)) << 11)
697 		     | (((i & 12) && (i & 48)) << 12)
698 		     | (((i & 12) && (i & 192)) << 13)
699 		     | (((i & 48) && (i & 192)) << 14));
700     }
701 }
702 
703 /* When looking at this function and the ones that inline it, bear in mind
704    what an optimizing compiler will do with this code.  All callers of this
705    function only pass in constant arguments (except for E).  This means
706    that many of the if statements will go away completely after inlining.  */
draw_sprites_1(struct sprite_entry * e,int ham,int dualpf,int doubling,int skip,int has_attach,int aga)707 STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int ham, int dualpf,
708 				   int doubling, int skip, int has_attach, int aga)
709 {
710     int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms;
711     uae_u16 *buf = spixels + e->first_pixel;
712     uae_u8 *stbuf = spixstate.bytes + e->first_pixel;
713     int pos, window_pos;
714     uae_u8 xor_val = (uae_u8)(dp_for_drawing->bplcon4 >> 8);
715 
716     buf -= e->pos;
717     stbuf -= e->pos;
718 
719     window_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (aga ? 1 : 0));
720     if (skip)
721 	window_pos >>= 1;
722     else if (doubling)
723 	window_pos <<= 1;
724     window_pos += pixels_offset;
725     for (pos = e->pos; pos < e->max; pos += 1 << skip) {
726 	int maskshift, plfmask;
727 	unsigned int v = buf[pos];
728 
729 	/* The value in the shift lookup table is _half_ the shift count we
730 	   need.  This is because we can't shift 32 bits at once (undefined
731 	   behaviour in C).  */
732 	maskshift = shift_lookup[pixdata.apixels[window_pos]];
733 	plfmask = (plf_sprite_mask >> maskshift) >> maskshift;
734 	v &= ~plfmask;
735 	if (v != 0) {
736 	    unsigned int vlo, vhi, col;
737 	    unsigned int v1 = v & 255;
738 	    /* OFFS determines the sprite pair with the highest priority that has
739 	       any bits set.  E.g. if we have 0xFF00 in the buffer, we have sprite
740 	       pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will
741 	       have a value of 4.
742 	       2 * OFFS is the bit number in V of the sprite pair, and it also
743 	       happens to be the color offset for that pair.  */
744 	    int offs;
745 	    if (v1 == 0)
746 		offs = 4 + sprite_offs[v >> 8];
747 	    else
748 		offs = sprite_offs[v1];
749 
750 	    /* Shift highest priority sprite pair down to bit zero.  */
751 	    v >>= offs * 2;
752 	    v &= 15;
753 
754 	    if (has_attach && (stbuf[pos] & (1 << offs))) {
755 		col = v;
756 		if (aga)
757 		    col += sbasecol[1];
758 		else
759 		    col += 16;
760 	    } else {
761 		/* This sequence computes the correct color value.  We have to select
762 		   either the lower-numbered or the higher-numbered sprite in the pair.
763 		   We have to select the high one if the low one has all bits zero.
764 		   If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in
765 		   the range of 0..2, and with the mask and shift, VHI will be zero.
766 		   If the lower-numbered sprite is zero, (VLO - 1) is a mask of
767 		   0xFFFFFFFF, and we select the bits of the higher numbered sprite
768 		   in VHI.
769 		   This is _probably_ more efficient than doing it with branches.  */
770 		vlo = v & 3;
771 		vhi = (v & (vlo - 1)) >> 2;
772 		col = (vlo | vhi);
773 		if (aga) {
774 		    if (vhi > 0)
775 			col += sbasecol[1];
776 		    else
777 			col += sbasecol[0];
778 		} else {
779 		    col += 16;
780 		}
781 		col += (offs * 2);
782 	    }
783 	    if (dualpf) {
784 		if (aga) {
785 		    spriteagadpfpixels[window_pos] = col;
786 		    if (doubling)
787 			spriteagadpfpixels[window_pos + 1] = col;
788 		} else {
789 		    col += 128;
790 		    if (doubling)
791 			pixdata.apixels_w[window_pos >> 1] = col | (col << 8);
792 		    else
793 			pixdata.apixels[window_pos] = col;
794 		}
795 	    } else if (ham) {
796 		col = color_reg_get (&colors_for_drawing, col);
797 		if (aga)
798 		    col ^= xor_val;
799 		ham_linebuf[window_pos] = col;
800 		if (doubling)
801 		    ham_linebuf[window_pos + 1] = col;
802 	    } else {
803 		if (aga)
804 		    col ^= xor_val;
805 		if (doubling)
806 		    pixdata.apixels_w[window_pos >> 1] = col | (col << 8);
807 		else
808 		    pixdata.apixels[window_pos] = col;
809 	    }
810 	}
811 	window_pos += 1 << doubling;
812     }
813 }
814 
815 /* See comments above.  Do not touch if you don't know what's going on.
816  * (We do _not_ want the following to be inlined themselves).  */
817 /* lores bitplane, lores sprites */
draw_sprites_normal_sp_lo_nat(struct sprite_entry * e)818 static void NOINLINE draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1	(e, 0, 0, 0, 0, 0, 0); }
draw_sprites_normal_dp_lo_nat(struct sprite_entry * e)819 static void NOINLINE draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1	(e, 0, 1, 0, 0, 0, 0); }
draw_sprites_ham_sp_lo_nat(struct sprite_entry * e)820 static void NOINLINE draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1	(e, 1, 0, 0, 0, 0, 0); }
draw_sprites_normal_sp_lo_at(struct sprite_entry * e)821 static void NOINLINE draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1	(e, 0, 0, 0, 0, 1, 0); }
draw_sprites_normal_dp_lo_at(struct sprite_entry * e)822 static void NOINLINE draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1	(e, 0, 1, 0, 0, 1, 0); }
draw_sprites_ham_sp_lo_at(struct sprite_entry * e)823 static void NOINLINE draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1		(e, 1, 0, 0, 0, 1, 0); }
824 /* hires bitplane, lores sprites */
draw_sprites_normal_sp_hi_nat(struct sprite_entry * e)825 static void NOINLINE draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1	(e, 0, 0, 1, 0, 0, 0); }
draw_sprites_normal_dp_hi_nat(struct sprite_entry * e)826 static void NOINLINE draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1	(e, 0, 1, 1, 0, 0, 0); }
draw_sprites_ham_sp_hi_nat(struct sprite_entry * e)827 static void NOINLINE draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1	(e, 1, 0, 1, 0, 0, 0); }
draw_sprites_normal_sp_hi_at(struct sprite_entry * e)828 static void NOINLINE draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1	(e, 0, 0, 1, 0, 1, 0); }
draw_sprites_normal_dp_hi_at(struct sprite_entry * e)829 static void NOINLINE draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1	(e, 0, 1, 1, 0, 1, 0); }
draw_sprites_ham_sp_hi_at(struct sprite_entry * e)830 static void NOINLINE draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1		(e, 1, 0, 1, 0, 1, 0); }
831 
832 /* not very optimized */
draw_sprites_aga(struct sprite_entry * e)833 STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e)
834 {
835     int diff = RES_HIRES - bplres;
836     if (diff > 0)
837 	draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, 0, diff, e->has_attached, 1);
838     else
839 	draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, -diff, 0, e->has_attached, 1);
840 }
841 
842 
draw_sprites_ecs(struct sprite_entry * e)843 STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e)
844 {
845     if (e->has_attached)
846 	if (bplres == 1)
847 	    if (dp_for_drawing->ham_seen)
848 		draw_sprites_ham_sp_hi_at (e);
849 	    else
850 		if (bpldualpf)
851 		    draw_sprites_normal_dp_hi_at (e);
852 		else
853 		    draw_sprites_normal_sp_hi_at (e);
854 	else
855 	    if (dp_for_drawing->ham_seen)
856 		draw_sprites_ham_sp_lo_at (e);
857 	    else
858 		if (bpldualpf)
859 		    draw_sprites_normal_dp_lo_at (e);
860 		else
861 		    draw_sprites_normal_sp_lo_at (e);
862     else
863 	if (bplres == 1)
864 	    if (dp_for_drawing->ham_seen)
865 		draw_sprites_ham_sp_hi_nat (e);
866 	    else
867 		if (bpldualpf)
868 		    draw_sprites_normal_dp_hi_nat (e);
869 		else
870 		    draw_sprites_normal_sp_hi_nat (e);
871 	else
872 	    if (dp_for_drawing->ham_seen)
873 		draw_sprites_ham_sp_lo_nat (e);
874 	    else
875 		if (bpldualpf)
876 		    draw_sprites_normal_dp_lo_nat (e);
877 		else
878 		    draw_sprites_normal_sp_lo_nat (e);
879 }
880 
881 
882 #define MERGE(a,b,mask,shift) do {\
883     uae_u32 tmp = mask & (a ^ (b >> shift)); \
884     a ^= tmp; \
885     b ^= (tmp << shift); \
886 } while (0)
887 
888 #define GETLONG(P) (*(uae_u32 *)P)
889 
890 /* We use the compiler's inlining ability to ensure that PLANES is in effect a compile time
891    constant.  That will cause some unnecessary code to be optimized away.
892    Don't touch this if you don't know what you are doing.  */
pfield_doline_1(uae_u32 * pixels,int wordcount,int planes)893 STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes)
894 {
895     while (wordcount-- > 0) {
896 	uae_u32 b0, b1, b2, b3, b4, b5, b6, b7;
897 
898 	b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
899 	switch (planes) {
900 	case 8: b0 = GETLONG ((uae_u32 *)real_bplpt[7]); real_bplpt[7] += 4;
901 	case 7: b1 = GETLONG ((uae_u32 *)real_bplpt[6]); real_bplpt[6] += 4;
902 	case 6: b2 = GETLONG ((uae_u32 *)real_bplpt[5]); real_bplpt[5] += 4;
903 	case 5: b3 = GETLONG ((uae_u32 *)real_bplpt[4]); real_bplpt[4] += 4;
904 	case 4: b4 = GETLONG ((uae_u32 *)real_bplpt[3]); real_bplpt[3] += 4;
905 	case 3: b5 = GETLONG ((uae_u32 *)real_bplpt[2]); real_bplpt[2] += 4;
906 	case 2: b6 = GETLONG ((uae_u32 *)real_bplpt[1]); real_bplpt[1] += 4;
907 	case 1: b7 = GETLONG ((uae_u32 *)real_bplpt[0]); real_bplpt[0] += 4;
908 	}
909 
910 	MERGE (b0, b1, 0x55555555, 1);
911 	MERGE (b2, b3, 0x55555555, 1);
912 	MERGE (b4, b5, 0x55555555, 1);
913 	MERGE (b6, b7, 0x55555555, 1);
914 
915 	MERGE (b0, b2, 0x33333333, 2);
916 	MERGE (b1, b3, 0x33333333, 2);
917 	MERGE (b4, b6, 0x33333333, 2);
918 	MERGE (b5, b7, 0x33333333, 2);
919 
920 	MERGE (b0, b4, 0x0f0f0f0f, 4);
921 	MERGE (b1, b5, 0x0f0f0f0f, 4);
922 	MERGE (b2, b6, 0x0f0f0f0f, 4);
923 	MERGE (b3, b7, 0x0f0f0f0f, 4);
924 
925 	MERGE (b0, b1, 0x00ff00ff, 8);
926 	MERGE (b2, b3, 0x00ff00ff, 8);
927 	MERGE (b4, b5, 0x00ff00ff, 8);
928 	MERGE (b6, b7, 0x00ff00ff, 8);
929 
930 	MERGE (b0, b2, 0x0000ffff, 16);
931 	do_put_mem_long (pixels, b0);
932 	do_put_mem_long (pixels + 4, b2);
933 	MERGE (b1, b3, 0x0000ffff, 16);
934 	do_put_mem_long (pixels + 2, b1);
935 	do_put_mem_long (pixels + 6, b3);
936 	MERGE (b4, b6, 0x0000ffff, 16);
937 	do_put_mem_long (pixels + 1, b4);
938 	do_put_mem_long (pixels + 5, b6);
939 	MERGE (b5, b7, 0x0000ffff, 16);
940 	do_put_mem_long (pixels + 3, b5);
941 	do_put_mem_long (pixels + 7, b7);
942 	pixels += 8;
943     }
944 }
945 
946 /* See above for comments on inlining.  These functions should _not_
947    be inlined themselves.  */
pfield_doline_n1(uae_u32 * data,int count)948 static void NOINLINE pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); }
pfield_doline_n2(uae_u32 * data,int count)949 static void NOINLINE pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); }
pfield_doline_n3(uae_u32 * data,int count)950 static void NOINLINE pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); }
pfield_doline_n4(uae_u32 * data,int count)951 static void NOINLINE pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); }
pfield_doline_n5(uae_u32 * data,int count)952 static void NOINLINE pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); }
pfield_doline_n6(uae_u32 * data,int count)953 static void NOINLINE pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); }
pfield_doline_n7(uae_u32 * data,int count)954 static void NOINLINE pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); }
pfield_doline_n8(uae_u32 * data,int count)955 static void NOINLINE pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); }
956 
pfield_doline(int lineno)957 static void pfield_doline (int lineno)
958 {
959     int wordcount = dp_for_drawing->plflinelen;
960     uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / 4;
961 
962 #ifdef SMART_UPDATE
963 #define DATA_POINTER(n) (line_data[lineno] + (n)*MAX_WORDS_PER_LINE*2)
964     real_bplpt[0] = DATA_POINTER (0);
965     real_bplpt[1] = DATA_POINTER (1);
966     real_bplpt[2] = DATA_POINTER (2);
967     real_bplpt[3] = DATA_POINTER (3);
968     real_bplpt[4] = DATA_POINTER (4);
969     real_bplpt[5] = DATA_POINTER (5);
970     real_bplpt[6] = DATA_POINTER (6);
971     real_bplpt[7] = DATA_POINTER (7);
972 #endif
973 
974     switch (bplplanecnt) {
975     default: break;
976     case 0: memset (data, 0, wordcount * 32); break;
977     case 1: pfield_doline_n1 (data, wordcount); break;
978     case 2: pfield_doline_n2 (data, wordcount); break;
979     case 3: pfield_doline_n3 (data, wordcount); break;
980     case 4: pfield_doline_n4 (data, wordcount); break;
981     case 5: pfield_doline_n5 (data, wordcount); break;
982     case 6: pfield_doline_n6 (data, wordcount); break;
983     case 7: pfield_doline_n7 (data, wordcount); break;
984     case 8: pfield_doline_n8 (data, wordcount); break;
985     }
986 }
987 
init_row_map(void)988 void init_row_map (void)
989 {
990     int i;
991     if (gfxvidinfo.height > 2048) {
992 	write_log ("Resolution too high, aborting\n");
993 	abort ();
994     }
995     for (i = 0; i < gfxvidinfo.height + 1; i++)
996 	row_map[i] = gfxvidinfo.bufmem + gfxvidinfo.rowbytes * i;
997 }
998 
init_aspect_maps(void)999 static void init_aspect_maps (void)
1000 {
1001     int i, maxl;
1002     double native_lines_per_amiga_line;
1003 
1004     if (native2amiga_line_map)
1005 	free (native2amiga_line_map);
1006     if (amiga2aspect_line_map)
1007 	free (amiga2aspect_line_map);
1008 
1009     /* At least for this array the +1 is necessary. */
1010     amiga2aspect_line_map = (int *)malloc (sizeof (int) * (MAXVPOS + 1)*2 + 1);
1011     native2amiga_line_map = (int *)malloc (sizeof (int) * gfxvidinfo.height);
1012 
1013     if (curr_gfx->correct_aspect)
1014 	native_lines_per_amiga_line = ((double)gfxvidinfo.height
1015 				       * (curr_gfx->lores ? 320 : 640)
1016 				       / (curr_gfx->linedbl ? 512 : 256)
1017 				       / gfxvidinfo.width);
1018     else
1019 	native_lines_per_amiga_line = 1;
1020 
1021     maxl = (MAXVPOS + 1) * (curr_gfx->linedbl ? 2 : 1);
1022     min_ypos_for_screen = minfirstline << (curr_gfx->linedbl ? 1 : 0);
1023     max_drawn_amiga_line = -1;
1024     for (i = 0; i < maxl; i++) {
1025 	int v = (int) ((i - min_ypos_for_screen) * native_lines_per_amiga_line);
1026 	if (v >= gfxvidinfo.height && max_drawn_amiga_line == -1)
1027 	    max_drawn_amiga_line = i - min_ypos_for_screen;
1028 	if (i < min_ypos_for_screen || v >= gfxvidinfo.height)
1029 	    v = -1;
1030 	amiga2aspect_line_map[i] = v;
1031     }
1032     if (curr_gfx->linedbl)
1033 	max_drawn_amiga_line >>= 1;
1034 
1035     if (curr_gfx->ycenter && !(curr_gfx->correct_aspect)) {
1036 	/* @@@ verify maxvpos vs. MAXVPOS */
1037 	extra_y_adjust = (gfxvidinfo.height - (maxvpos << (curr_gfx->linedbl ? 1 : 0))) >> 1;
1038 	if (extra_y_adjust < 0)
1039 	    extra_y_adjust = 0;
1040     }
1041 
1042     for (i = 0; i < gfxvidinfo.height; i++)
1043 	native2amiga_line_map[i] = -1;
1044 
1045     if (native_lines_per_amiga_line < 1) {
1046 	/* Must omit drawing some lines. */
1047 	for (i = maxl - 1; i > min_ypos_for_screen; i--) {
1048 	    if (amiga2aspect_line_map[i] == amiga2aspect_line_map[i-1]) {
1049 		if (curr_gfx->linedbl && (i & 1) == 0 && amiga2aspect_line_map[i+1] != -1) {
1050 		    /* If only the first line of a line pair would be omitted,
1051 		     * omit the second one instead to avoid problems with line
1052 		     * doubling. */
1053 		    amiga2aspect_line_map[i] = amiga2aspect_line_map[i+1];
1054 		    amiga2aspect_line_map[i+1] = -1;
1055 		} else
1056 		    amiga2aspect_line_map[i] = -1;
1057 	    }
1058 	}
1059     }
1060 
1061     for (i = maxl-1; i >= min_ypos_for_screen; i--) {
1062 	int j;
1063 	if (amiga2aspect_line_map[i] == -1)
1064 	    continue;
1065 	for (j = amiga2aspect_line_map[i]; j < gfxvidinfo.height && native2amiga_line_map[j] == -1; j++)
1066 	    native2amiga_line_map[j] = i >> (curr_gfx->linedbl ? 1 : 0);
1067     }
1068 }
1069 
1070 /*
1071  * A raster line has been built in the graphics buffer. Tell the graphics code
1072  * to do anything necessary to display it.
1073  */
do_flush_line_1(int lineno)1074 static void do_flush_line_1 (int lineno)
1075 {
1076     if (lineno < first_drawn_line)
1077 	first_drawn_line = lineno;
1078     if (lineno > last_drawn_line)
1079 	last_drawn_line = lineno;
1080 
1081     if (gfxvidinfo.maxblocklines == 0)
1082 	flush_line (lineno);
1083     else {
1084 	if ((last_block_line+1) != lineno) {
1085 	    if (first_block_line != NO_BLOCK)
1086 		flush_block (first_block_line, last_block_line);
1087 	    first_block_line = lineno;
1088 	}
1089 	last_block_line = lineno;
1090 	if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) {
1091 	    flush_block (first_block_line, last_block_line);
1092 	    first_block_line = last_block_line = NO_BLOCK;
1093 	}
1094     }
1095 }
1096 
do_flush_line(int lineno)1097 STATIC_INLINE void do_flush_line (int lineno)
1098 {
1099     do_flush_line_1 (lineno);
1100 }
1101 
1102 /*
1103  * One drawing frame has been finished. Tell the graphics code about it.
1104  * Note that the actual flush_screen() call is a no-op for all reasonable
1105  * systems.
1106  */
1107 
do_flush_screen(int start,int stop)1108 STATIC_INLINE void do_flush_screen (int start, int stop)
1109 {
1110     /* TODO: this flush operation is executed outside locked state!
1111        Should be corrected.
1112        (sjo 26.9.99) */
1113 
1114     if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) {
1115 	flush_block (first_block_line, last_block_line);
1116     }
1117     unlockscr ();
1118     if (start <= stop)
1119 	flush_screen (start, stop);
1120 }
1121 
1122 /* We only save hardware registers during the hardware frame. Now, when
1123  * drawing the frame, we expand the data into a slightly more useful
1124  * form. */
pfield_expand_dp_bplcon(void)1125 static void pfield_expand_dp_bplcon (void)
1126 {
1127     int plf1pri, plf2pri;
1128     bplres = dp_for_drawing->bplres;
1129     bplplanecnt = dp_for_drawing->nr_planes;
1130     bplham = dp_for_drawing->ham_at_start;
1131 
1132     if (currprefs.chipset_mask & CSMASK_AGA) {
1133 	/* The KILLEHB bit exists in ECS, but is apparently meant for Genlock
1134 	 * stuff, and it's set by some demos (e.g. Andromeda Seven Seas) */
1135 	bplehb = ((dp_for_drawing->bplcon0 & 0xFCC0) == 0x6000 && !(dp_for_drawing->bplcon2 & 0x200));
1136     } else {
1137 	bplehb = (dp_for_drawing->bplcon0 & 0xFC00) == 0x6000;
1138     }
1139     plf1pri = dp_for_drawing->bplcon2 & 7;
1140     plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7;
1141     plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri);
1142     plf_sprite_mask |= (0xFFFF << (4 * plf1pri)) & 0xFFFF;
1143     bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400;
1144     bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40;
1145     bpldualpf2of = (dp_for_drawing->bplcon3 >> 10) & 7;
1146     sbasecol[0] = ((dp_for_drawing->bplcon4 >> 4) & 15) << 4;
1147     sbasecol[1] = ((dp_for_drawing->bplcon4 >> 0) & 15) << 4;
1148 }
1149 
1150 static int drawing_color_matches;
1151 static enum { color_match_acolors, color_match_full } color_match_type;
1152 
1153 /* Set up colors_for_drawing to the state at the beginning of the currently drawn
1154    line.  Try to avoid copying color tables around whenever possible.  */
adjust_drawing_colors(int ctable,int need_full)1155 static void adjust_drawing_colors (int ctable, int need_full)
1156 {
1157     if (drawing_color_matches != ctable) {
1158 	if (need_full) {
1159 	    color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable);
1160 	    color_match_type = color_match_full;
1161 	} else {
1162 	    memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors,
1163 		sizeof colors_for_drawing.acolors);
1164 	    color_match_type = color_match_acolors;
1165 	}
1166 	drawing_color_matches = ctable;
1167     } else if (need_full && color_match_type != color_match_full) {
1168 	color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]);
1169 	color_match_type = color_match_full;
1170     }
1171 }
1172 
do_color_changes(line_draw_func worker_border,line_draw_func worker_pfield)1173 STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield)
1174 {
1175     int i;
1176     int lastpos = visible_left_border;
1177 
1178     for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) {
1179 	int regno = curr_color_changes[i].regno;
1180 	unsigned int value = curr_color_changes[i].value;
1181 	int nextpos, nextpos_in_range;
1182 	if (i == dip_for_drawing->last_color_change)
1183 	    nextpos = max_diwlastword;
1184 	else
1185 	    nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos * 2);
1186 
1187 	nextpos_in_range = nextpos;
1188 	if (nextpos > visible_right_border)
1189 	    nextpos_in_range = visible_right_border;
1190 
1191 	if (nextpos_in_range > lastpos) {
1192 	    if (lastpos < playfield_start) {
1193 		int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
1194 		(*worker_border) (lastpos, t);
1195 		lastpos = t;
1196 	    }
1197 	}
1198 	if (nextpos_in_range > lastpos) {
1199 	    if (lastpos >= playfield_start && lastpos < playfield_end) {
1200 		int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
1201 		(*worker_pfield) (lastpos, t);
1202 		lastpos = t;
1203 	    }
1204 	}
1205 	if (nextpos_in_range > lastpos) {
1206 	    if (lastpos >= playfield_end)
1207 		(*worker_border) (lastpos, nextpos_in_range);
1208 	    lastpos = nextpos_in_range;
1209 	}
1210 	if (i != dip_for_drawing->last_color_change) {
1211 	    if (regno == -1)
1212 		bplham = value;
1213 	    else {
1214 		color_reg_set (&colors_for_drawing, regno, value);
1215 		colors_for_drawing.acolors[regno] = getxcolor (value);
1216 	    }
1217 	}
1218 	if (lastpos >= visible_right_border)
1219 	    break;
1220     }
1221 }
1222 
1223 enum double_how {
1224     dh_buf,
1225     dh_line,
1226     dh_emerg
1227 };
1228 
pfield_draw_line(int lineno,int gfx_ypos,int follow_ypos)1229 STATIC_INLINE void pfield_draw_line (int lineno, int gfx_ypos, int follow_ypos)
1230 {
1231     static int warned = 0;
1232     int border = 0;
1233     int do_double = 0;
1234     enum double_how dh;
1235 
1236     dp_for_drawing = line_decisions + lineno;
1237     dip_for_drawing = curr_drawinfo + lineno;
1238     switch (linestate[lineno]) {
1239     case LINE_REMEMBERED_AS_PREVIOUS:
1240 	if (!warned)
1241 	    write_log ("Shouldn't get here... this is a bug.\n"), warned++;
1242 	return;
1243 
1244     case LINE_BLACK:
1245 	linestate[lineno] = LINE_REMEMBERED_AS_BLACK;
1246 	border = 2;
1247 	break;
1248 
1249     case LINE_REMEMBERED_AS_BLACK:
1250 	return;
1251 
1252     case LINE_AS_PREVIOUS:
1253 	dp_for_drawing--;
1254 	dip_for_drawing--;
1255 	if (dp_for_drawing->plfleft == -1)
1256 	    border = 1;
1257 	linestate[lineno] = LINE_DONE_AS_PREVIOUS;
1258 	break;
1259 
1260     case LINE_DONE_AS_PREVIOUS:
1261 	/* fall through */
1262     case LINE_DONE:
1263 	return;
1264 
1265     case LINE_DECIDED_DOUBLE:
1266 	if (follow_ypos != -1) {
1267 	    do_double = 1;
1268 	    linetoscr_double_offset = gfxvidinfo.rowbytes * (follow_ypos - gfx_ypos);
1269 	    linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS;
1270 	}
1271 
1272 	/* fall through */
1273     default:
1274 	if (dp_for_drawing->plfleft == -1)
1275 	    border = 1;
1276 	linestate[lineno] = LINE_DONE;
1277 	break;
1278     }
1279 
1280     dh = dh_line;
1281     xlinebuffer = gfxvidinfo.linemem;
1282     if (xlinebuffer == 0 && do_double
1283 	&& (border == 0 || (border != 1 && dip_for_drawing->nr_color_changes > 0)))
1284 	xlinebuffer = gfxvidinfo.emergmem, dh = dh_emerg;
1285     if (xlinebuffer == 0)
1286 	xlinebuffer = row_map[gfx_ypos], dh = dh_buf;
1287     xlinebuffer -= linetoscr_x_adjust_bytes;
1288 
1289     if (border == 0) {
1290 	pfield_expand_dp_bplcon ();
1291 
1292 	if (bplres == RES_LORES && ! curr_gfx->lores)
1293 	    curr_gfx->lores = 2;
1294 
1295 	pfield_init_linetoscr ();
1296 	pfield_doline (lineno);
1297 
1298 	adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
1299 
1300 	/* The problem is that we must call decode_ham() BEFORE we do the
1301 	   sprites. */
1302 	if (! border && dp_for_drawing->ham_seen) {
1303 	    init_ham_decoding ();
1304 	    if (dip_for_drawing->nr_color_changes == 0) {
1305 		/* The easy case: need to do HAM decoding only once for the
1306 		 * full line. */
1307 		decode_ham (visible_left_border, visible_right_border);
1308 	    } else /* Argh. */ {
1309 		do_color_changes (dummy_worker, decode_ham);
1310 		adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
1311 	    }
1312 	    bplham = dp_for_drawing->ham_at_start;
1313 	}
1314 
1315 	{
1316 	    int i;
1317 	    for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
1318 		if (currprefs.chipset_mask & CSMASK_AGA)
1319 		    draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
1320 		else
1321 		    draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
1322 	    }
1323 	}
1324 
1325 	do_color_changes (pfield_do_fill_line, pfield_do_linetoscr);
1326 	if (dh == dh_emerg)
1327 	    memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1328 
1329 	do_flush_line (gfx_ypos);
1330 	if (do_double) {
1331 	    if (dh == dh_emerg)
1332 		memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1333 	    else if (dh == dh_buf)
1334 		memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width);
1335 	    do_flush_line (follow_ypos);
1336 	}
1337 	if (curr_gfx->lores == 2)
1338 	    curr_gfx->lores = 0;
1339     } else if (border == 1) {
1340 	adjust_drawing_colors (dp_for_drawing->ctable, 0);
1341 
1342 	if (dip_for_drawing->nr_color_changes == 0) {
1343 	    fill_line ();
1344 	    do_flush_line (gfx_ypos);
1345 #if 0
1346 	    if (dh == dh_emerg)
1347 		abort ();
1348 #endif
1349 	    if (do_double) {
1350 		if (dh == dh_buf) {
1351 		    xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_bytes;
1352 		    fill_line ();
1353 		}
1354 		/* If dh == dh_line, do_flush_line will re-use the rendered line
1355 		 * from linemem.  */
1356 		do_flush_line (follow_ypos);
1357 	    }
1358 	    return;
1359 	}
1360 
1361 	playfield_start = visible_right_border;
1362 	playfield_end = visible_right_border;
1363 
1364 	do_color_changes (pfield_do_fill_line, pfield_do_fill_line);
1365 
1366 	if (dh == dh_emerg)
1367 	    memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1368 
1369 	do_flush_line (gfx_ypos);
1370 	if (do_double) {
1371 	    if (dh == dh_emerg)
1372 		memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1373 	    else if (dh == dh_buf)
1374 		memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width);
1375 	    /* If dh == dh_line, do_flush_line will re-use the rendered line
1376 	     * from linemem.  */
1377 	    do_flush_line (follow_ypos);
1378 	}
1379     } else {
1380 	xcolnr tmp = colors_for_drawing.acolors[0];
1381 	colors_for_drawing.acolors[0] = getxcolor (0);
1382 	fill_line ();
1383 	do_flush_line (gfx_ypos);
1384 	colors_for_drawing.acolors[0] = tmp;
1385     }
1386 }
1387 
center_image(void)1388 static void center_image (void)
1389 {
1390     int prev_x_adjust = visible_left_border;
1391     int prev_y_adjust = thisframe_y_adjust;
1392 
1393     if (curr_gfx->xcenter) {
1394 	if (max_diwstop - min_diwstart < gfxvidinfo.width && curr_gfx->xcenter == 2)
1395 	    /* Try to center. */
1396 	    visible_left_border = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1;
1397 	else
1398 	    visible_left_border = max_diwstop - gfxvidinfo.width;
1399 
1400 	/* Would the old value be good enough? If so, leave it as it is if we want to
1401 	 * be clever. */
1402 	if (curr_gfx->xcenter == 2) {
1403 	    if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart)
1404 		visible_left_border = prev_x_adjust;
1405 	}
1406     } else
1407 	visible_left_border = max_diwlastword - gfxvidinfo.width;
1408     if (visible_left_border < 0)
1409 	visible_left_border = 0;
1410 
1411     linetoscr_x_adjust_bytes = visible_left_border * gfxvidinfo.pixbytes;
1412 
1413     visible_right_border = visible_left_border + gfxvidinfo.width;
1414     if (visible_right_border > max_diwlastword)
1415 	visible_right_border = max_diwlastword;
1416 
1417     thisframe_y_adjust = minfirstline;
1418     if (curr_gfx->ycenter && thisframe_first_drawn_line != -1) {
1419 	if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && curr_gfx->ycenter == 2)
1420 	    thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line;
1421 	else
1422 	    thisframe_y_adjust = thisframe_first_drawn_line;
1423 	/* Would the old value be good enough? If so, leave it as it is if we want to
1424 	 * be clever. */
1425 	if (curr_gfx->ycenter == 2) {
1426 	    if (thisframe_y_adjust != prev_y_adjust
1427 		&& prev_y_adjust <= thisframe_first_drawn_line
1428 		&& prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line)
1429 		thisframe_y_adjust = prev_y_adjust;
1430 	}
1431 	/* Make sure the value makes sense */
1432 	if (thisframe_y_adjust + max_drawn_amiga_line > maxvpos)
1433 	    thisframe_y_adjust = maxvpos - max_drawn_amiga_line;
1434 	if (thisframe_y_adjust < minfirstline)
1435 	    thisframe_y_adjust = minfirstline;
1436     }
1437     thisframe_y_adjust_real = thisframe_y_adjust << (curr_gfx->linedbl ? 1 : 0);
1438     max_ypos_thisframe = (maxvpos - thisframe_y_adjust) << (curr_gfx->linedbl ? 1 : 0);
1439 
1440     /* @@@ interlace_seen used to be (bplcon0 & 4), but this is probably
1441      * better.  */
1442     if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust)
1443 	frame_redraw_necessary |= interlace_seen && curr_gfx->linedbl ? 2 : 1;
1444 
1445     max_diwstop = 0;
1446     min_diwstart = 10000;
1447 }
1448 
init_drawing_frame(void)1449 static void init_drawing_frame (void)
1450 {
1451     int i, maxline;
1452 
1453     init_hardware_for_drawing_frame ();
1454 
1455     if (thisframe_first_drawn_line == -1)
1456 	thisframe_first_drawn_line = minfirstline;
1457     if (thisframe_first_drawn_line > thisframe_last_drawn_line)
1458 	thisframe_last_drawn_line = thisframe_first_drawn_line;
1459 
1460     if (!curr_gfx)
1461 	return;
1462 
1463     maxline = curr_gfx->linedbl ? (maxvpos+1) * 2 + 1 : (maxvpos+1) + 1;
1464 #ifdef SMART_UPDATE
1465     for (i = 0; i < maxline; i++) {
1466 	switch (linestate[i]) {
1467 	 case LINE_DONE_AS_PREVIOUS:
1468 	    linestate[i] = LINE_REMEMBERED_AS_PREVIOUS;
1469 	    break;
1470 	 case LINE_REMEMBERED_AS_BLACK:
1471 	    break;
1472 	 default:
1473 	    linestate[i] = LINE_UNDECIDED;
1474 	    break;
1475 	}
1476     }
1477 #else
1478     memset (linestate, LINE_UNDECIDED, maxline);
1479 #endif
1480     last_drawn_line = 0;
1481     first_drawn_line = 32767;
1482 
1483     first_block_line = last_block_line = NO_BLOCK;
1484     if (currprefs.test_drawing_speed)
1485 	frame_redraw_necessary = 1;
1486     else if (frame_redraw_necessary)
1487 	frame_redraw_necessary--;
1488 
1489     center_image ();
1490 
1491     thisframe_first_drawn_line = -1;
1492     thisframe_last_drawn_line = -1;
1493 
1494     drawing_color_matches = -1;
1495 }
1496 
1497 /*
1498  * Some code to put status information on the screen.
1499  */
1500 
1501 #define TD_PADX 10
1502 #define TD_PADY 2
1503 #define TD_WIDTH 32
1504 #define TD_LED_WIDTH 24
1505 #define TD_LED_HEIGHT 4
1506 
1507 #define TD_RIGHT 1
1508 #define TD_BOTTOM 2
1509 
1510 static int td_pos = (TD_RIGHT|TD_BOTTOM);
1511 
1512 #define TD_NUM_WIDTH 7
1513 #define TD_NUM_HEIGHT 7
1514 
1515 #define TD_TOTAL_HEIGHT (TD_PADY * 2 + TD_NUM_HEIGHT)
1516 
1517 #define NUMBERS_NUM 16
1518 
1519 #define TD_BORDER 0x333
1520 
1521 static const char *numbers = { /* ugly  0123456789CHD%+- */
1522 "+++++++--++++-+++++++++++++++++-++++++++++++++++++++++++++++++++++++++++++++-++++++-++++----++---+--------------"
1523 "+xxxxx+--+xx+-+xxxxx++xxxxx++x+-+x++xxxxx++xxxxx++xxxxx++xxxxx++xxxxx++xxxx+-+x++x+-+xxx++-+xx+-+x---+----------"
1524 "+x+++x+--++x+-+++++x++++++x++x+++x++x++++++x++++++++++x++x+++x++x+++x++x++++-+x++x+-+x++x+--+x++x+--+x+----+++--"
1525 "+x+-+x+---+x+-+xxxxx++xxxxx++xxxxx++xxxxx++xxxxx+--++x+-+xxxxx++xxxxx++x+----+xxxx+-+x++x+----+x+--+xxx+--+xxx+-"
1526 "+x+++x+---+x+-+x++++++++++x++++++x++++++x++x+++x+--+x+--+x+++x++++++x++x++++-+x++x+-+x++x+---+x+x+--+x+----+++--"
1527 "+xxxxx+---+x+-+xxxxx++xxxxx+----+x++xxxxx++xxxxx+--+x+--+xxxxx++xxxxx++xxxx+-+x++x+-+xxx+---+x++xx--------------"
1528 "+++++++---+++-++++++++++++++----+++++++++++++++++--+++--++++++++++++++++++++-++++++-++++------------------------"
1529 };
1530 
putpixel(int x,xcolnr c8)1531 STATIC_INLINE void putpixel (int x, xcolnr c8)
1532 {
1533     switch (gfxvidinfo.pixbytes) {
1534     case 1:
1535 	xlinebuffer[x] = (uae_u8)c8;
1536 	break;
1537     case 2:
1538     {
1539 	uae_u16 *p = (uae_u16 *)xlinebuffer + x;
1540 	*p = (uae_u16)c8;
1541 	break;
1542     }
1543     case 3:
1544 	/* no 24 bit yet */
1545 	break;
1546     case 4:
1547     {
1548 	uae_u32 *p = (uae_u32 *)xlinebuffer + x;
1549 	*p = c8;
1550 	break;
1551     }
1552     }
1553 }
1554 
write_tdnumber(int x,int y,int num)1555 static void write_tdnumber (int x, int y, int num)
1556 {
1557     int j;
1558     uae_u8 *numptr;
1559 
1560     numptr = numbers + num * TD_NUM_WIDTH + NUMBERS_NUM * TD_NUM_WIDTH * y;
1561     for (j = 0; j < TD_NUM_WIDTH; j++) {
1562 	if (*numptr == 'x')
1563 	    putpixel (x + j, xcolors[0xfff]);
1564 	else if (*numptr == '+')
1565 	    putpixel (x + j, xcolors[0x000]);
1566 	numptr++;
1567     }
1568 }
1569 
draw_status_line(int line)1570 static void draw_status_line (int line)
1571 {
1572     int x_start, y, j, led;
1573 
1574     if (td_pos & TD_RIGHT)
1575 	x_start = gfxvidinfo.width - TD_PADX - 5 * TD_WIDTH;
1576     else
1577 	x_start = TD_PADX;
1578 
1579     y = line - (gfxvidinfo.height - TD_TOTAL_HEIGHT);
1580     xlinebuffer = gfxvidinfo.linemem;
1581     if (xlinebuffer == 0)
1582 	xlinebuffer = row_map[line];
1583 
1584     memset (xlinebuffer, 0, gfxvidinfo.width * gfxvidinfo.pixbytes);
1585 
1586     for (led = 0; led < 5; led++) {
1587 	int side, pos, num1 = -1, num2 = -1, num3 = -1, num4 = -1;
1588 	int x, off_rgb, on_rgb, c, on = 0;
1589 	if (led > 0) {
1590 	    int pled = led - 1;
1591 	    int track = gui_data.drive_track[pled];
1592 	    pos = 1 + pled;
1593 	    on_rgb = 0x0c0;
1594 	    off_rgb = 0x030;
1595 	    if (1 /*!gui_data.drive_disabled[pled]*/) {
1596 		num1 = -1;
1597 		num2 = track / 10;
1598 		num3 = track % 10;
1599 		on = gui_data.drive_motor[pled];
1600 		if (gui_data.drive_writing[pled])
1601 		    on_rgb = 0xc00;
1602 	    }
1603 	    /*side = gui_data.drive_side;*/
1604 	} else {
1605 	    pos = 0;
1606 	    on = gui_data.powerled;
1607 	    on_rgb = 0xc00;
1608 	    off_rgb = 0x300;
1609 	}
1610 	c = xcolors[on ? on_rgb : off_rgb];
1611 	if (y == 0 || y == TD_TOTAL_HEIGHT - 1)
1612 	    c = xcolors[TD_BORDER];
1613 
1614 	x = x_start + pos * TD_WIDTH;
1615 	putpixel (x - 1, xcolors[TD_BORDER]);
1616 	for (j = 0; j < TD_LED_WIDTH; j++)
1617 	    putpixel (x + j, c);
1618 	putpixel (x + j, xcolors[TD_BORDER]);
1619 
1620 	if (y >= TD_PADY && y - TD_PADY < TD_NUM_HEIGHT) {
1621 	    if (num3 >= 0) {
1622 		int tn = num1 > 0 ? 3 : 2;
1623 		x += (TD_LED_WIDTH - tn * TD_NUM_WIDTH) / 2;
1624 		if (num1 > 0) {
1625 		    write_tdnumber (x, y - TD_PADY, num1);
1626 		    x += TD_NUM_WIDTH;
1627 		}
1628 		write_tdnumber (x, y - TD_PADY, num2);
1629 		x += TD_NUM_WIDTH;
1630 		write_tdnumber (x, y - TD_PADY, num3);
1631 		x += TD_NUM_WIDTH;
1632 		if (num4 > 0)
1633 		    write_tdnumber (x, y - TD_PADY, num4);
1634 	    }
1635 	}
1636     }
1637 }
1638 
finish_drawing_frame(void)1639 void finish_drawing_frame (void)
1640 {
1641     int i;
1642 
1643     if (! lockscr ()) {
1644 	notice_screen_contents_lost ();
1645 	return;
1646     }
1647 
1648 #ifndef SMART_UPDATE
1649     /* @@@ This isn't exactly right yet. FIXME */
1650     if (!interlace_seen)
1651 	do_flush_screen (first_drawn_line, last_drawn_line);
1652     else
1653 	unlockscr ();
1654     return;
1655 #endif
1656     for (i = 0; i < max_ypos_thisframe; i++) {
1657 	int where;
1658 	int i1 = i + min_ypos_for_screen;
1659 	int line = i + thisframe_y_adjust_real;
1660 
1661 	if (linestate[line] == LINE_UNDECIDED)
1662 	    break;
1663 
1664 	where = amiga2aspect_line_map[i1];
1665 	if (where >= gfxvidinfo.height - (curr_gfx->leds_on_screen ? TD_TOTAL_HEIGHT : 0))
1666 	    break;
1667 	if (where == -1)
1668 	    continue;
1669 
1670 	pfield_draw_line (line, where, amiga2aspect_line_map[i1 + 1]);
1671     }
1672     if (curr_gfx->leds_on_screen) {
1673 	for (i = 0; i < TD_TOTAL_HEIGHT; i++) {
1674 	    int line = gfxvidinfo.height - TD_TOTAL_HEIGHT + i;
1675 	    draw_status_line (line);
1676 	    do_flush_line (line);
1677 	}
1678     }
1679     do_flush_screen (first_drawn_line, last_drawn_line);
1680 }
1681 
hardware_line_completed(int lineno)1682 void hardware_line_completed (int lineno)
1683 {
1684 #ifndef SMART_UPDATE
1685     {
1686 	int i, where;
1687 	/* l is the line that has been finished for drawing. */
1688 	i = lineno - thisframe_y_adjust_real;
1689 	if (i >= 0 && i < max_ypos_thisframe) {
1690 	    where = amiga2aspect_line_map[i+min_ypos_for_screen];
1691 	    if (where < gfxvidinfo.height && where != -1)
1692 		pfield_draw_line (lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]);
1693 	}
1694     }
1695 #endif
1696 }
1697 
check_picasso(void)1698 STATIC_INLINE void check_picasso (void)
1699 {
1700 #ifdef PICASSO96
1701     if (picasso_on && picasso_redraw_necessary)
1702 	picasso_refresh ();
1703     picasso_redraw_necessary = 0;
1704 
1705     if (picasso_requested_on == picasso_on)
1706 	return;
1707 
1708     picasso_on = picasso_requested_on;
1709 
1710     if (!picasso_on)
1711 	clear_inhibit_frame (IHF_PICASSO);
1712     else
1713 	set_inhibit_frame (IHF_PICASSO);
1714 
1715     gfx_set_picasso_state (picasso_on);
1716     picasso_enablescreen (picasso_requested_on);
1717 
1718     notice_screen_contents_lost ();
1719     notice_new_xcolors ();
1720 #endif
1721 }
1722 
check_prefs_changed_gfx(void)1723 int check_prefs_changed_gfx (void)
1724 {
1725     int params_changed = 0, screen_changed = 0;
1726     int old_x, old_y;
1727 
1728     if (!screen_is_picasso) {
1729 	if (curr_gfx == &currprefs.gfx_w
1730 	    && memcmp (&changed_prefs.gfx_w, &currprefs.gfx_w, sizeof (struct gfx_params)) != 0)
1731 	{
1732 	    old_x = currprefs.gfx_w.width;
1733 	    old_y = currprefs.gfx_w.height;
1734 	    fixup_prefs_dimensions (&changed_prefs.gfx_w, gfx_windowed_modes, n_windowed_modes);
1735 	    currprefs.gfx_w = changed_prefs.gfx_w;
1736 	    params_changed = 1;
1737 	    screen_changed = (old_x != currprefs.gfx_w.width
1738 			      || old_y != currprefs.gfx_w.height);
1739 	} else if (curr_gfx == &currprefs.gfx_f
1740 		   && memcmp (&changed_prefs.gfx_f, &currprefs.gfx_f, sizeof (struct gfx_params)) != 0)
1741 	{
1742 	    old_x = currprefs.gfx_f.width;
1743 	    old_y = currprefs.gfx_f.height;
1744 	    fixup_prefs_dimensions (&changed_prefs.gfx_f, gfx_fullscreen_modes, n_fullscreen_modes);
1745 	    currprefs.gfx_f = changed_prefs.gfx_f;
1746 	    params_changed = 1;
1747 	    screen_changed = (old_x != currprefs.gfx_f.width
1748 			      || old_y != currprefs.gfx_f.height);
1749 	}
1750 	if (changed_prefs.gfx_afullscreen != currprefs.gfx_afullscreen) {
1751 	    screen_changed = 1;
1752 	}
1753     } else if (changed_prefs.gfx_pfullscreen != currprefs.gfx_pfullscreen) {
1754 	screen_changed = 1;
1755     }
1756 
1757     currprefs.gfx_afullscreen = changed_prefs.gfx_afullscreen;
1758     currprefs.gfx_pfullscreen = changed_prefs.gfx_pfullscreen;
1759 
1760     if (screen_changed) {
1761 	graphics_subshutdown (0);
1762 
1763 	gui_update_gfx ();
1764 
1765 	graphics_subinit ();
1766 
1767 	reset_drawing ();
1768     }
1769 
1770     return params_changed || screen_changed;
1771 }
1772 
vsync_handle_redraw(int long_frame,int lof_changed)1773 void vsync_handle_redraw (int long_frame, int lof_changed)
1774 {
1775     last_redraw_point++;
1776     if (lof_changed || ! interlace_seen || last_redraw_point >= 2 || long_frame) {
1777 	last_redraw_point = 0;
1778 	interlace_seen = 0;
1779 
1780 	if (framecnt == 0)
1781 	    finish_drawing_frame ();
1782 
1783 	/* At this point, we have finished both the hardware and the
1784 	 * drawing frame. Essentially, we are outside of all loops and
1785 	 * can do some things which would cause confusion if they were
1786 	 * done at other times.
1787 	 */
1788 
1789 	if (savestate_state == STATE_DOSAVE) {
1790 	    custom_prepare_savestate ();
1791 	    savestate_state = STATE_SAVE;
1792 	    save_state (savestate_filename, "Description!");
1793 	    savestate_state = 0;
1794 	} else if (savestate_state == STATE_DORESTORE) {
1795 	    savestate_state = STATE_RESTORE;
1796 	    uae_reset (0);
1797 	}
1798 
1799 	if (quit_program < 0) {
1800 	    quit_program = -quit_program;
1801 	    set_inhibit_frame (IHF_QUIT_PROGRAM);
1802 	    set_special (SPCFLAG_BRK);
1803 	    filesys_prepare_reset ();
1804 	    return;
1805 	}
1806 
1807 	count_frame ();
1808 	check_picasso ();
1809 
1810 	currprefs.keyboard_lang = changed_prefs.keyboard_lang;
1811 	check_prefs_changed_audio ();
1812 	check_prefs_changed_custom ();
1813 	check_prefs_changed_cpu ();
1814 	if (check_prefs_changed_gfx ()) {
1815 	    if (curr_gfx) {
1816 		init_row_map ();
1817 		init_aspect_maps ();
1818 	    }
1819 	    notice_screen_contents_lost ();
1820 	    notice_new_xcolors ();
1821 
1822 	    if (screen_is_picasso)
1823 		picasso_enablescreen (1);
1824 	}
1825 
1826 	if (inhibit_frame != 0)
1827 	    framecnt = 1;
1828 
1829 	if (framecnt == 0)
1830 	    init_drawing_frame ();
1831     }
1832 }
1833 
hsync_record_line_state(int lineno,enum nln_how how,int changed)1834 void hsync_record_line_state (int lineno, enum nln_how how, int changed)
1835 {
1836     char *state;
1837     if (framecnt != 0)
1838 	return;
1839 
1840     state = linestate + lineno;
1841     changed += frame_redraw_necessary;
1842 
1843     switch (how) {
1844      case nln_normal:
1845 	*state = changed ? LINE_DECIDED : LINE_DONE;
1846 	break;
1847      case nln_doubled:
1848 	*state = changed ? LINE_DECIDED_DOUBLE : LINE_DONE;
1849 	changed += state[1] != LINE_REMEMBERED_AS_PREVIOUS;
1850 	state[1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS;
1851 	break;
1852      case nln_nblack:
1853 	*state = changed ? LINE_DECIDED : LINE_DONE;
1854 	if (state[1] != LINE_REMEMBERED_AS_BLACK)
1855 	    state[1] = LINE_BLACK;
1856 	break;
1857      case nln_lower:
1858 	if (state[-1] == LINE_UNDECIDED)
1859 	    state[-1] = LINE_BLACK;
1860 	*state = changed ? LINE_DECIDED : LINE_DONE;
1861 	break;
1862      case nln_upper:
1863 	*state = changed ? LINE_DECIDED : LINE_DONE;
1864 	if (state[1] == LINE_UNDECIDED
1865 	    || state[1] == LINE_REMEMBERED_AS_PREVIOUS
1866 	    || state[1] == LINE_AS_PREVIOUS)
1867 	    state[1] = LINE_BLACK;
1868 	break;
1869     }
1870 }
1871 
notice_interlace_seen(void)1872 void notice_interlace_seen (void)
1873 {
1874     interlace_seen = 1;
1875 }
1876 
reset_drawing(void)1877 void reset_drawing (void)
1878 {
1879     int i;
1880 
1881     max_diwstop = 0;
1882 
1883     if (!curr_gfx)
1884 	return;
1885     lores_factor = curr_gfx->lores ? 1 : 2;
1886     lores_shift = curr_gfx->lores ? 0 : 1;
1887 
1888     /*memset(blitcount, 0, sizeof(blitcount));  blitter debug */
1889     for (i = 0; i < sizeof linestate / sizeof *linestate; i++)
1890 	linestate[i] = LINE_UNDECIDED;
1891 
1892     xlinebuffer = gfxvidinfo.bufmem;
1893 
1894     init_aspect_maps ();
1895 
1896     if (line_drawn == 0)
1897 	line_drawn = (char *)malloc (gfxvidinfo.height);
1898 
1899     init_row_map();
1900 
1901     last_redraw_point = 0;
1902 
1903     memset (spixels, 0, sizeof spixels);
1904     memset (&spixstate, 0, sizeof spixstate);
1905 
1906     init_drawing_frame ();
1907 }
1908 
init_drawing_at_reset(void)1909 void init_drawing_at_reset (void)
1910 {
1911     InitPicasso96 ();
1912     picasso_requested_on = 0;
1913     picasso_on = 0;
1914     gfx_set_picasso_state (0);
1915 
1916     inhibit_frame = 0;
1917 }
1918 
drawing_init()1919 void drawing_init ()
1920 {
1921     inhibit_frame = 0;
1922 
1923     native2amiga_line_map = 0;
1924     amiga2aspect_line_map = 0;
1925     line_drawn = 0;
1926 
1927     gen_pfield_tables ();
1928 }
1929 
1930