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