|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Screen drawing functions
5: *
1.1.1.8 root 6: * Copyright 1995-2000 Bernd Schmidt
1.1 root 7: * Copyright 1995 Alessandro Bissacco
1.1.1.13 root 8: * Copyright 2000,2001 Toni Wilen
1.1 root 9: */
10:
1.1.1.8 root 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:
1.1 root 29: #include "sysconfig.h"
30: #include "sysdeps.h"
31:
32: #include <ctype.h>
33: #include <assert.h>
34:
35: #include "options.h"
1.1.1.14 root 36: #include "threaddep/thread.h"
1.1 root 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"
1.1.1.13 root 46: #include "savestate.h"
1.1 root 47:
1.1.1.12 root 48: int lores_factor, lores_shift;
1.1 root 49:
1.1.1.8 root 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:
1.1 root 56: static int interlace_seen = 0;
57:
1.1.1.11 root 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. */
1.1.1.12 root 65:
1.1.1.11 root 66: static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256];
67: static int dblpf_ind1[256], dblpf_ind2[256];
1.1.1.12 root 68:
69: static int dblpf_2nd1[256], dblpf_2nd2[256];
70: static int dblpf_ind1_aga[256], dblpf_ind2_aga[256];
71:
1.1 root 72: static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 };
73:
1.1.1.11 root 74: static int sprite_offs[256];
75:
1.1 root 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:
1.1.1.9 root 83: /* OCS/ECS color lookup table. */
1.1 root 84: xcolnr xcolors[4096];
1.1.1.9 root 85: /* AGA mode color lookup tables */
86: unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256];
1.1 root 87:
88: struct color_entry colors_for_drawing;
89:
1.1.1.8 root 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). */
1.1 root 93: union {
94: /* Let's try to align this thing. */
95: double uupzuq;
96: long int cruxmedo;
1.1.1.13 root 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];
1.1 root 100: } pixdata;
101:
1.1.1.11 root 102: uae_u16 spixels[2 * MAX_SPR_PIXELS];
103: /* Eight bits for every pixel. */
104: union sps_union spixstate;
105:
1.1.1.13 root 106: static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2];
107: static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE * 2]; /* AGA dualplayfield sprite */
1.1 root 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:
1.1.1.9 root 115: /* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */
1.1 root 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
1.1.1.2 root 122: #define LINE_BLACK 5
123: #define LINE_REMEMBERED_AS_BLACK 6
1.1 root 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;
1.1.1.5 root 129: static char linestate[(MAXVPOS + 1)*2 + 1];
1.1 root 130:
1.1.1.5 root 131: uae_u8 line_data[(MAXVPOS + 1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
1.1 root 132:
1.1.1.8 root 133: /* Centering variables. */
1.1.1.17 root 134: static int min_diwstart, max_diwstop;
1.1.1.8 root 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;
1.1 root 138: static int linetoscr_x_adjust_bytes;
1.1.1.17 root 139: static int thisframe_y_adjust;
1.1 root 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:
1.1.1.8 root 144: /* A frame counter that forces a redraw after at least one skipped frame in
145: interlace mode. */
1.1 root 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:
1.1.1.20! root 151: #define NO_BLOCK -3
! 152:
1.1 root 153: /* These are generated by the drawing code from the line_decisions array for
1.1.1.8 root 154: each line that needs to be drawn. These are basically extracted out of
155: bit fields in the hardware registers. */
1.1.1.20! root 156: static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt;
! 157: static int bplres, adjusted_bplres;
1.1.1.11 root 158: static uae_u32 plf_sprite_mask;
1.1.1.12 root 159: static int sbasecol[2];
1.1 root 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:
1.1.1.6 root 170: STATIC_INLINE void count_frame (void)
1.1 root 171: {
172: framecnt++;
1.1.1.5 root 173: if (framecnt >= currprefs.gfx_framerate)
1.1 root 174: framecnt = 0;
175: }
176:
177: int coord_native_to_amiga_x (int x)
178: {
1.1.1.8 root 179: x += visible_left_border;
1.1 root 180: x <<= (1 - lores_shift);
1.1.1.11 root 181: return x + 2*DISPLAY_LEFT_SHIFT - 2*DIW_DDF_OFFSET;
1.1 root 182: }
183:
184: int coord_native_to_amiga_y (int y)
185: {
186: return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline;
187: }
188:
1.1.1.8 root 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:
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:
1.1 root 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:
1.1.1.8 root 212: /* Record DIW of the current line for use by centering code. */
1.1 root 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:
1.1.1.8 root 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;
1.1 root 235:
1.1.1.8 root 236: /* Initialize the variables necessary for drawing a line.
237: * This involves setting up start/stop positions and display window
238: * borders. */
239: static void pfield_init_linetoscr (void)
1.1 root 240: {
1.1.1.8 root 241: /* First, get data fetch start/stop in DIW coordinates. */
1.1.1.11 root 242: int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET;
243: int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET;
1.1.1.8 root 244: /* Compute datafetch start/stop in pixels; native display coordinates. */
1.1.1.11 root 245: int native_ddf_left = coord_hw_to_window_x (ddf_left);
246: int native_ddf_right = coord_hw_to_window_x (ddf_right);
1.1.1.8 root 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;
1.1 root 256: }
257:
1.1.1.8 root 258: /* Perverse cases happen. */
259: if (linetoscr_diw_end < linetoscr_diw_start)
260: linetoscr_diw_end = linetoscr_diw_start;
1.1 root 261:
1.1.1.8 root 262: playfield_start = linetoscr_diw_start;
263: playfield_end = linetoscr_diw_end;
1.1 root 264:
1.1.1.8 root 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;
1.1.1.11 root 277: ddf_left -= DISPLAY_LEFT_SHIFT;
278: ddf_left <<= bplres;
1.1.1.12 root 279: pixels_offset = MAX_PIXELS_PER_LINE - ddf_left;
1.1.1.11 root 280:
1.1.1.8 root 281: unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start;
1.1.1.12 root 282: src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left + unpainted);
1.1 root 283:
1.1.1.8 root 284: if (dip_for_drawing->nr_sprites == 0)
1.1 root 285: return;
1.1.1.8 root 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;
1.1.1.12 root 290: memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size);
1.1.1.8 root 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;
1.1.1.12 root 296: memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size);
1.1 root 297: }
298: }
1.1.1.2 root 299:
1.1.1.8 root 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
1.1.1.17 root 306: #define AGAC 0
1.1.1.8 root 307: #include "linetoscr.c"
1.1.1.9 root 308: #define LNAME linetoscr_8_stretch1
1.1.1.8 root 309: #define SRC_INC 1
310: #define HDOUBLE 1
1.1.1.17 root 311: #define AGAC 0
1.1.1.8 root 312: #include "linetoscr.c"
1.1.1.9 root 313: #define LNAME linetoscr_8_shrink1
1.1.1.8 root 314: #define SRC_INC 2
315: #define HDOUBLE 0
1.1.1.17 root 316: #define AGAC 0
1.1.1.9 root 317: #include "linetoscr.c"
318:
319: #define LNAME linetoscr_8_aga
320: #define SRC_INC 1
321: #define HDOUBLE 0
1.1.1.17 root 322: #define AGAC 1
1.1.1.9 root 323: #include "linetoscr.c"
324: #define LNAME linetoscr_8_stretch1_aga
325: #define SRC_INC 1
326: #define HDOUBLE 1
1.1.1.17 root 327: #define AGAC 1
1.1.1.9 root 328: #include "linetoscr.c"
329: #define LNAME linetoscr_8_shrink1_aga
330: #define SRC_INC 2
331: #define HDOUBLE 0
1.1.1.17 root 332: #define AGAC 1
1.1.1.8 root 333: #include "linetoscr.c"
334:
335: #undef TYPE
1.1.1.9 root 336:
1.1.1.8 root 337: #define TYPE uae_u16
338: #define LNAME linetoscr_16
339: #define SRC_INC 1
340: #define HDOUBLE 0
1.1.1.17 root 341: #define AGAC 0
1.1.1.8 root 342: #include "linetoscr.c"
1.1.1.9 root 343: #define LNAME linetoscr_16_stretch1
1.1.1.8 root 344: #define SRC_INC 1
345: #define HDOUBLE 1
1.1.1.17 root 346: #define AGAC 0
1.1.1.8 root 347: #include "linetoscr.c"
1.1.1.9 root 348: #define LNAME linetoscr_16_shrink1
1.1.1.8 root 349: #define SRC_INC 2
350: #define HDOUBLE 0
1.1.1.17 root 351: #define AGAC 0
1.1.1.9 root 352: #include "linetoscr.c"
353:
354: #define LNAME linetoscr_16_aga
355: #define SRC_INC 1
356: #define HDOUBLE 0
1.1.1.17 root 357: #define AGAC 1
1.1.1.9 root 358: #include "linetoscr.c"
359: #define LNAME linetoscr_16_stretch1_aga
360: #define SRC_INC 1
361: #define HDOUBLE 1
1.1.1.17 root 362: #define AGAC 1
1.1.1.9 root 363: #include "linetoscr.c"
364: #define LNAME linetoscr_16_shrink1_aga
365: #define SRC_INC 2
366: #define HDOUBLE 0
1.1.1.17 root 367: #define AGAC 1
1.1.1.8 root 368: #include "linetoscr.c"
369:
370: #undef TYPE
1.1.1.9 root 371:
1.1.1.8 root 372: #define TYPE uae_u32
373: #define LNAME linetoscr_32
374: #define SRC_INC 1
375: #define HDOUBLE 0
1.1.1.17 root 376: #define AGAC 0
1.1.1.8 root 377: #include "linetoscr.c"
1.1.1.9 root 378: #define LNAME linetoscr_32_stretch1
1.1.1.8 root 379: #define SRC_INC 1
380: #define HDOUBLE 1
1.1.1.17 root 381: #define AGAC 0
1.1.1.8 root 382: #include "linetoscr.c"
1.1.1.9 root 383: #define LNAME linetoscr_32_shrink1
1.1.1.8 root 384: #define SRC_INC 2
385: #define HDOUBLE 0
1.1.1.17 root 386: #define AGAC 0
1.1.1.9 root 387: #include "linetoscr.c"
388:
389: #define LNAME linetoscr_32_aga
390: #define SRC_INC 1
391: #define HDOUBLE 0
1.1.1.17 root 392: #define AGAC 1
1.1.1.9 root 393: #include "linetoscr.c"
394: #define LNAME linetoscr_32_stretch1_aga
395: #define SRC_INC 1
396: #define HDOUBLE 1
1.1.1.17 root 397: #define AGAC 1
1.1.1.9 root 398: #include "linetoscr.c"
399: #define LNAME linetoscr_32_shrink1_aga
400: #define SRC_INC 2
401: #define HDOUBLE 0
1.1.1.17 root 402: #define AGAC 1
1.1.1.8 root 403: #include "linetoscr.c"
1.1 root 404:
1.1.1.9 root 405: #undef TYPE
406:
1.1.1.8 root 407: static void fill_line_8 (char *buf, int start, int stop)
1.1 root 408: {
1.1.1.8 root 409: uae_u8 *b = (uae_u8 *)buf;
1.1 root 410: int i;
1.1.1.8 root 411: xcolnr col = colors_for_drawing.acolors[0];
412: for (i = start; i < stop; i++)
413: b[i] = col;
1.1 root 414: }
1.1.1.8 root 415: static void fill_line_16 (char *buf, int start, int stop)
1.1 root 416: {
1.1.1.8 root 417: uae_u16 *b = (uae_u16 *)buf;
1.1 root 418: int i;
1.1.1.8 root 419: xcolnr col = colors_for_drawing.acolors[0];
420: for (i = start; i < stop; i++)
421: b[i] = col;
1.1 root 422: }
1.1.1.8 root 423: static void fill_line_32 (char *buf, int start, int stop)
1.1 root 424: {
1.1.1.8 root 425: uae_u32 *b = (uae_u32 *)buf;
1.1 root 426: int i;
1.1.1.8 root 427: xcolnr col = colors_for_drawing.acolors[0];
428: for (i = start; i < stop; i++)
429: b[i] = col;
1.1.1.2 root 430: }
431:
1.1.1.6 root 432: STATIC_INLINE void fill_line (void)
1.1 root 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;
1.1.1.8 root 448: start = (int *)(((char *)xlinebuffer) + (visible_left_border << shift));
1.1 root 449: val = colors_for_drawing.acolors[0];
1.1.1.9 root 450: if (gfxvidinfo.pixbytes == 2)
1.1.1.18 root 451: val |= val << 16;
1.1 root 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:
1.1.1.8 root 481: static int linetoscr_double_offset;
1.1 root 482:
1.1.1.8 root 483: static void pfield_do_linetoscr (int start, int stop)
484: {
1.1.1.9 root 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: }
1.1.1.20! root 492: else if (res_shift > 0)
1.1.1.9 root 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: }
1.1.1.20! root 498: else if (res_shift < 0)
1.1.1.9 root 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: }
1.1.1.18 root 504: else
1.1.1.9 root 505: abort ();
506: } else {
1.1.1.18 root 507: if (res_shift == 0)
1.1.1.9 root 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: }
1.1 root 528: }
529:
1.1.1.8 root 530: static void pfield_do_fill_line (int start, int stop)
1.1 root 531: {
1.1.1.8 root 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;
1.1 root 536: }
537: }
538:
1.1.1.8 root 539: static void pfield_do_linetoscr_full (int double_line)
1.1 root 540: {
541: char *oldxlb = (char *)xlinebuffer;
1.1.1.8 root 542: int old_src_pixel = src_pixel;
543:
544: pfield_do_linetoscr (playfield_start, playfield_end);
1.1 root 545: xlinebuffer = oldxlb + linetoscr_double_offset;
1.1.1.8 root 546: src_pixel = old_src_pixel;
547: pfield_do_linetoscr (playfield_start, playfield_end);
1.1 root 548: }
1.1.1.8 root 549:
550: static void dummy_worker (int start, int stop)
1.1 root 551: {
552: }
553:
1.1.1.8 root 554: static unsigned int ham_lastcolor;
1.1.1.2 root 555:
1.1.1.8 root 556: static int ham_decode_pixel;
1.1 root 557:
1.1.1.8 root 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,
1.1.1.9 root 560: when decode_ham runs. */
1.1.1.8 root 561: static void init_ham_decoding (void)
1.1 root 562: {
1.1.1.8 root 563: int unpainted_amiga = res_shift_from_window (unpainted);
564: ham_decode_pixel = src_pixel;
1.1.1.9 root 565: ham_lastcolor = color_reg_get (&colors_for_drawing, 0);
566:
1.1.1.15 root 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) {
1.1.1.9 root 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: }
1.1.1.15 root 586: } else if (bplplanecnt == 6) { /* AGA mode HAM6 */
1.1.1.9 root 587: while (unpainted_amiga-- > 0) {
1.1.1.18 root 588: int pv = pixdata.apixels[ham_decode_pixel++];
1.1.1.9 root 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 {
1.1.1.18 root 598: if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */
1.1.1.9 root 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: }
1.1 root 608: }
609: }
610: }
611:
1.1.1.9 root 612: static void decode_ham (int pix, int stoppos)
1.1 root 613: {
1.1.1.8 root 614: int todraw_amiga = res_shift_from_window (stoppos - pix);
1.1 root 615:
1.1.1.15 root 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) {
1.1.1.9 root 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: }
1.1.1.15 root 638: } else if (bplplanecnt == 6) { /* AGA mode HAM6 */
1.1.1.9 root 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 {
1.1.1.18 root 651: if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */
1.1.1.9 root 652: while (todraw_amiga-- > 0) {
1.1.1.18 root 653: int pv = pixdata.apixels[ham_decode_pixel];
1.1.1.9 root 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: }
1.1 root 662: }
663: }
664: }
665:
1.1.1.2 root 666: static void gen_pfield_tables (void)
1.1 root 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);
1.1.1.11 root 678:
1.1.1.12 root 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:
1.1.1.11 root 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;
1.1 root 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:
1.1.1.11 root 692: sprite_offs[i] = (i & 15) ? 0 : 2;
1.1 root 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:
1.1.1.11 root 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. */
1.1.1.13 root 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)
1.1.1.11 root 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;
1.1.1.13 root 713: int pos, window_pos;
714: uae_u8 xor_val = (uae_u8)(dp_for_drawing->bplcon4 >> 8);
1.1.1.11 root 715:
716: buf -= e->pos;
717: stbuf -= e->pos;
718:
1.1.1.13 root 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) {
1.1.1.11 root 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). */
1.1.1.13 root 732: maskshift = shift_lookup[pixdata.apixels[window_pos]];
1.1.1.11 root 733: plfmask = (plf_sprite_mask >> maskshift) >> maskshift;
734: v &= ~plfmask;
735: if (v != 0) {
1.1.1.13 root 736: unsigned int vlo, vhi, col;
1.1.1.11 root 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;
1.1.1.18 root 753:
1.1.1.11 root 754: if (has_attach && (stbuf[pos] & (1 << offs))) {
755: col = v;
1.1.1.13 root 756: if (aga)
757: col += sbasecol[1];
758: else
759: col += 16;
1.1.1.11 root 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;
1.1.1.13 root 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: }
1.1.1.11 root 781: col += (offs * 2);
782: }
1.1.1.13 root 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;
1.1 root 794: }
1.1.1.13 root 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;
1.1 root 802: } else {
1.1.1.13 root 803: if (aga)
804: col ^= xor_val;
805: if (doubling)
806: pixdata.apixels_w[window_pos >> 1] = col | (col << 8);
1.1.1.11 root 807: else
1.1.1.13 root 808: pixdata.apixels[window_pos] = col;
1.1 root 809: }
810: }
1.1.1.13 root 811: window_pos += 1 << doubling;
1.1 root 812: }
813: }
1.1.1.18 root 814:
1.1.1.11 root 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). */
1.1.1.13 root 817: /* lores bitplane, lores sprites */
1.1.1.17 root 818: static void NOINLINE draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 0, 0); }
819: static void NOINLINE draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 0, 0); }
820: static void NOINLINE draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 0, 0); }
821: static void NOINLINE draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 1, 0); }
822: static void NOINLINE draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 1, 0); }
823: static void NOINLINE draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 1, 0); }
1.1.1.13 root 824: /* hires bitplane, lores sprites */
1.1.1.17 root 825: static void NOINLINE draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 0, 0); }
826: static void NOINLINE draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 0, 0); }
827: static void NOINLINE draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 0, 0); }
828: static void NOINLINE draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 1, 0); }
829: static void NOINLINE draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 1, 0); }
830: static void NOINLINE draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 1, 0); }
1.1.1.13 root 831:
832: /* not very optimized */
833: STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e)
834: {
835: int diff = RES_HIRES - bplres;
836: if (diff > 0)
1.1.1.15 root 837: draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, 0, diff, e->has_attached, 1);
1.1.1.13 root 838: else
1.1.1.15 root 839: draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, -diff, 0, e->has_attached, 1);
1.1.1.13 root 840: }
841:
1.1.1.11 root 842:
1.1.1.13 root 843: STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e)
1.1.1.11 root 844: {
845: if (e->has_attached)
846: if (bplres == 1)
1.1.1.15 root 847: if (dp_for_drawing->ham_seen)
1.1.1.11 root 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
1.1.1.15 root 855: if (dp_for_drawing->ham_seen)
1.1.1.11 root 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)
1.1.1.15 root 864: if (dp_for_drawing->ham_seen)
1.1.1.11 root 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
1.1.1.15 root 872: if (dp_for_drawing->ham_seen)
1.1.1.11 root 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);
1.1 root 879: }
880:
1.1.1.13 root 881:
1.1.1.8 root 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:
1.1.1.11 root 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.
1.1.1.8 root 892: Don't touch this if you don't know what you are doing. */
1.1.1.11 root 893: STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes)
1.1.1.8 root 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) {
1.1.1.11 root 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;
1.1.1.8 root 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. */
1.1.1.17 root 948: static void NOINLINE pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); }
949: static void NOINLINE pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); }
950: static void NOINLINE pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); }
951: static void NOINLINE pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); }
952: static void NOINLINE pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); }
953: static void NOINLINE pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); }
954: static void NOINLINE pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); }
955: static void NOINLINE pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); }
1.1.1.8 root 956:
957: static void pfield_doline (int lineno)
958: {
1.1.1.11 root 959: int wordcount = dp_for_drawing->plflinelen;
1.1.1.20! root 960: uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / 4;
1.1 root 961:
962: #ifdef SMART_UPDATE
1.1.1.8 root 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:
1.1.1.11 root 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;
1.1 root 985: }
986: }
987:
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:
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. */
1.1.1.5 root 1010: amiga2aspect_line_map = (int *)malloc (sizeof (int) * (MAXVPOS + 1)*2 + 1);
1.1 root 1011: native2amiga_line_map = (int *)malloc (sizeof (int) * gfxvidinfo.height);
1012:
1.1.1.19 root 1013: if (curr_gfx->correct_aspect)
1.1 root 1014: native_lines_per_amiga_line = ((double)gfxvidinfo.height
1.1.1.19 root 1015: * (curr_gfx->lores ? 320 : 640)
1016: / (curr_gfx->linedbl ? 512 : 256)
1.1 root 1017: / gfxvidinfo.width);
1018: else
1019: native_lines_per_amiga_line = 1;
1020:
1.1.1.19 root 1021: maxl = (MAXVPOS + 1) * (curr_gfx->linedbl ? 2 : 1);
1022: min_ypos_for_screen = minfirstline << (curr_gfx->linedbl ? 1 : 0);
1.1 root 1023: max_drawn_amiga_line = -1;
1024: for (i = 0; i < maxl; i++) {
1.1.1.9 root 1025: int v = (int) ((i - min_ypos_for_screen) * native_lines_per_amiga_line);
1.1 root 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: }
1.1.1.19 root 1032: if (curr_gfx->linedbl)
1.1 root 1033: max_drawn_amiga_line >>= 1;
1034:
1.1.1.19 root 1035: if (curr_gfx->ycenter && !(curr_gfx->correct_aspect)) {
1.1.1.5 root 1036: /* @@@ verify maxvpos vs. MAXVPOS */
1.1.1.19 root 1037: extra_y_adjust = (gfxvidinfo.height - (maxvpos << (curr_gfx->linedbl ? 1 : 0))) >> 1;
1.1 root 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]) {
1.1.1.19 root 1049: if (curr_gfx->linedbl && (i & 1) == 0 && amiga2aspect_line_map[i+1] != -1) {
1.1 root 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++)
1.1.1.19 root 1066: native2amiga_line_map[j] = i >> (curr_gfx->linedbl ? 1 : 0);
1.1 root 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: */
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)
1.1.1.11 root 1082: flush_line (lineno);
1.1 root 1083: else {
1084: if ((last_block_line+1) != lineno) {
1.1.1.20! root 1085: if (first_block_line != NO_BLOCK)
1.1 root 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);
1.1.1.20! root 1092: first_block_line = last_block_line = NO_BLOCK;
1.1 root 1093: }
1094: }
1095: }
1096:
1.1.1.6 root 1097: STATIC_INLINE void do_flush_line (int lineno)
1.1 root 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:
1.1.1.6 root 1108: STATIC_INLINE void do_flush_screen (int start, int stop)
1.1 root 1109: {
1.1.1.6 root 1110: /* TODO: this flush operation is executed outside locked state!
1111: Should be corrected.
1112: (sjo 26.9.99) */
1113:
1.1.1.20! root 1114: if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) {
1.1 root 1115: flush_block (first_block_line, last_block_line);
1116: }
1.1.1.15 root 1117: unlockscr ();
1.1 root 1118: if (start <= stop)
1119: flush_screen (start, stop);
1120: }
1121:
1.1.1.20! root 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. */
! 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:
1.1 root 1150: static int drawing_color_matches;
1151: static enum { color_match_acolors, color_match_full } color_match_type;
1152:
1.1.1.8 root 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. */
1.1.1.15 root 1155: static void adjust_drawing_colors (int ctable, int need_full)
1.1 root 1156: {
1157: if (drawing_color_matches != ctable) {
1.1.1.15 root 1158: if (need_full) {
1.1.1.9 root 1159: color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable);
1.1 root 1160: color_match_type = color_match_full;
1161: } else {
1162: memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors,
1.1.1.18 root 1163: sizeof colors_for_drawing.acolors);
1.1 root 1164: color_match_type = color_match_acolors;
1165: }
1166: drawing_color_matches = ctable;
1.1.1.15 root 1167: } else if (need_full && color_match_type != color_match_full) {
1.1.1.9 root 1168: color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]);
1.1 root 1169: color_match_type = color_match_full;
1170: }
1171: }
1172:
1.1.1.8 root 1173: STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield)
1.1 root 1174: {
1.1.1.8 root 1175: int i;
1176: int lastpos = visible_left_border;
1.1.1.9 root 1177:
1.1.1.8 root 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;
1.1 root 1182: if (i == dip_for_drawing->last_color_change)
1183: nextpos = max_diwlastword;
1184: else
1.1.1.11 root 1185: nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos * 2);
1.1.1.8 root 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: }
1.1 root 1210: if (i != dip_for_drawing->last_color_change) {
1.1.1.15 root 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: }
1.1 root 1217: }
1.1.1.8 root 1218: if (lastpos >= visible_right_border)
1.1.1.11 root 1219: break;
1220: }
1.1 root 1221: }
1222:
1223: enum double_how {
1224: dh_buf,
1225: dh_line,
1226: dh_emerg
1227: };
1228:
1.1.1.6 root 1229: STATIC_INLINE void pfield_draw_line (int lineno, int gfx_ypos, int follow_ypos)
1.1 root 1230: {
1.1.1.8 root 1231: static int warned = 0;
1.1 root 1232: int border = 0;
1233: int do_double = 0;
1234: enum double_how dh;
1235:
1.1.1.2 root 1236: dp_for_drawing = line_decisions + lineno;
1237: dip_for_drawing = curr_drawinfo + lineno;
1.1 root 1238: switch (linestate[lineno]) {
1.1.1.8 root 1239: case LINE_REMEMBERED_AS_PREVIOUS:
1240: if (!warned)
1241: write_log ("Shouldn't get here... this is a bug.\n"), warned++;
1.1 root 1242: return;
1243:
1.1.1.8 root 1244: case LINE_BLACK:
1.1.1.2 root 1245: linestate[lineno] = LINE_REMEMBERED_AS_BLACK;
1246: border = 2;
1.1 root 1247: break;
1248:
1.1.1.8 root 1249: case LINE_REMEMBERED_AS_BLACK:
1.1.1.2 root 1250: return;
1251:
1.1.1.8 root 1252: case LINE_AS_PREVIOUS:
1.1.1.2 root 1253: dp_for_drawing--;
1254: dip_for_drawing--;
1.1.1.11 root 1255: if (dp_for_drawing->plfleft == -1)
1.1.1.2 root 1256: border = 1;
1257: linestate[lineno] = LINE_DONE_AS_PREVIOUS;
1.1 root 1258: break;
1259:
1.1.1.8 root 1260: case LINE_DONE_AS_PREVIOUS:
1.1 root 1261: /* fall through */
1.1.1.8 root 1262: case LINE_DONE:
1.1 root 1263: return;
1264:
1.1.1.8 root 1265: case LINE_DECIDED_DOUBLE:
1.1 root 1266: if (follow_ypos != -1) {
1267: do_double = 1;
1268: linetoscr_double_offset = gfxvidinfo.rowbytes * (follow_ypos - gfx_ypos);
1.1.1.2 root 1269: linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS;
1.1 root 1270: }
1271:
1272: /* fall through */
1.1.1.8 root 1273: default:
1.1.1.11 root 1274: if (dp_for_drawing->plfleft == -1)
1.1 root 1275: border = 1;
1276: linestate[lineno] = LINE_DONE;
1.1.1.2 root 1277: break;
1.1 root 1278: }
1279:
1280: dh = dh_line;
1281: xlinebuffer = gfxvidinfo.linemem;
1.1.1.10 root 1282: if (xlinebuffer == 0 && do_double
1283: && (border == 0 || (border != 1 && dip_for_drawing->nr_color_changes > 0)))
1.1 root 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:
1.1.1.11 root 1289: if (border == 0) {
1.1 root 1290: pfield_expand_dp_bplcon ();
1291:
1.1.1.19 root 1292: if (bplres == RES_LORES && ! curr_gfx->lores)
1293: curr_gfx->lores = 2;
1.1.1.8 root 1294:
1.1.1.13 root 1295: pfield_init_linetoscr ();
1.1.1.11 root 1296: pfield_doline (lineno);
1.1 root 1297:
1.1.1.15 root 1298: adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
1.1 root 1299:
1.1.1.9 root 1300: /* The problem is that we must call decode_ham() BEFORE we do the
1.1.1.8 root 1301: sprites. */
1.1.1.15 root 1302: if (! border && dp_for_drawing->ham_seen) {
1.1.1.8 root 1303: init_ham_decoding ();
1.1 root 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. */
1.1.1.9 root 1307: decode_ham (visible_left_border, visible_right_border);
1.1 root 1308: } else /* Argh. */ {
1.1.1.9 root 1309: do_color_changes (dummy_worker, decode_ham);
1.1.1.15 root 1310: adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
1.1 root 1311: }
1.1.1.15 root 1312: bplham = dp_for_drawing->ham_at_start;
1.1 root 1313: }
1314:
1.1.1.11 root 1315: {
1316: int i;
1.1.1.13 root 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);
1.1.1.15 root 1320: else
1.1.1.13 root 1321: draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
1322: }
1.1.1.11 root 1323: }
1.1 root 1324:
1.1.1.8 root 1325: do_color_changes (pfield_do_fill_line, pfield_do_linetoscr);
1326: if (dh == dh_emerg)
1.1.1.14 root 1327: memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1.1 root 1328:
1.1.1.8 root 1329: do_flush_line (gfx_ypos);
1330: if (do_double) {
1331: if (dh == dh_emerg)
1.1.1.14 root 1332: memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1.1.1.8 root 1333: else if (dh == dh_buf)
1.1.1.14 root 1334: memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width);
1.1.1.8 root 1335: do_flush_line (follow_ypos);
1.1 root 1336: }
1.1.1.19 root 1337: if (curr_gfx->lores == 2)
1338: curr_gfx->lores = 0;
1.1.1.2 root 1339: } else if (border == 1) {
1.1 root 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:
1.1.1.8 root 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);
1.1 root 1365:
1366: if (dh == dh_emerg)
1.1.1.14 root 1367: memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1.1 root 1368:
1369: do_flush_line (gfx_ypos);
1370: if (do_double) {
1371: if (dh == dh_emerg)
1.1.1.14 root 1372: memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
1.1 root 1373: else if (dh == dh_buf)
1.1.1.14 root 1374: memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width);
1.1 root 1375: /* If dh == dh_line, do_flush_line will re-use the rendered line
1376: * from linemem. */
1377: do_flush_line (follow_ypos);
1378: }
1.1.1.2 root 1379: } else {
1380: xcolnr tmp = colors_for_drawing.acolors[0];
1.1.1.9 root 1381: colors_for_drawing.acolors[0] = getxcolor (0);
1.1.1.2 root 1382: fill_line ();
1383: do_flush_line (gfx_ypos);
1384: colors_for_drawing.acolors[0] = tmp;
1.1 root 1385: }
1386: }
1387:
1388: static void center_image (void)
1389: {
1.1.1.17 root 1390: int prev_x_adjust = visible_left_border;
1391: int prev_y_adjust = thisframe_y_adjust;
1.1 root 1392:
1.1.1.19 root 1393: if (curr_gfx->xcenter) {
1394: if (max_diwstop - min_diwstart < gfxvidinfo.width && curr_gfx->xcenter == 2)
1.1 root 1395: /* Try to center. */
1.1.1.8 root 1396: visible_left_border = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1;
1.1 root 1397: else
1.1.1.8 root 1398: visible_left_border = max_diwstop - gfxvidinfo.width;
1.1 root 1399:
1400: /* Would the old value be good enough? If so, leave it as it is if we want to
1401: * be clever. */
1.1.1.19 root 1402: if (curr_gfx->xcenter == 2) {
1.1.1.8 root 1403: if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart)
1404: visible_left_border = prev_x_adjust;
1.1 root 1405: }
1406: } else
1.1.1.8 root 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;
1.1 root 1416:
1417: thisframe_y_adjust = minfirstline;
1.1.1.19 root 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)
1.1 root 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. */
1.1.1.19 root 1425: if (curr_gfx->ycenter == 2) {
1.1 root 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: }
1.1.1.19 root 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);
1.1 root 1439:
1440: /* @@@ interlace_seen used to be (bplcon0 & 4), but this is probably
1441: * better. */
1.1.1.8 root 1442: if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust)
1.1.1.19 root 1443: frame_redraw_necessary |= interlace_seen && curr_gfx->linedbl ? 2 : 1;
1.1 root 1444:
1445: max_diwstop = 0;
1446: min_diwstart = 10000;
1447: }
1448:
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:
1.1.1.19 root 1460: if (!curr_gfx)
1461: return;
1462:
1463: maxline = curr_gfx->linedbl ? (maxvpos+1) * 2 + 1 : (maxvpos+1) + 1;
1.1 root 1464: #ifdef SMART_UPDATE
1.1.1.2 root 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: }
1.1 root 1477: #else
1478: memset (linestate, LINE_UNDECIDED, maxline);
1479: #endif
1480: last_drawn_line = 0;
1481: first_drawn_line = 32767;
1482:
1.1.1.20! root 1483: first_block_line = last_block_line = NO_BLOCK;
1.1 root 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:
1.1.1.14 root 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:
1.1.1.20! root 1517: #define NUMBERS_NUM 16
! 1518:
! 1519: #define TD_BORDER 0x333
1.1.1.17 root 1520:
1.1.1.20! root 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: "+++++++---+++-++++++++++++++----+++++++++++++++++--+++--++++++++++++++++++++-++++++-++++------------------------"
1.1.1.14 root 1529: };
1530:
1531: STATIC_INLINE void putpixel (int x, xcolnr c8)
1532: {
1.1.1.20! root 1533: switch (gfxvidinfo.pixbytes) {
1.1.1.14 root 1534: case 1:
1535: xlinebuffer[x] = (uae_u8)c8;
1536: break;
1537: case 2:
1538: {
1539: uae_u16 *p = (uae_u16 *)xlinebuffer + x;
1.1.1.17 root 1540: *p = (uae_u16)c8;
1.1.1.14 root 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:
1555: static void write_tdnumber (int x, int y, int num)
1556: {
1557: int j;
1558: uae_u8 *numptr;
1.1.1.18 root 1559:
1.1.1.17 root 1560: numptr = numbers + num * TD_NUM_WIDTH + NUMBERS_NUM * TD_NUM_WIDTH * y;
1.1.1.14 root 1561: for (j = 0; j < TD_NUM_WIDTH; j++) {
1.1.1.17 root 1562: if (*numptr == 'x')
1563: putpixel (x + j, xcolors[0xfff]);
1564: else if (*numptr == '+')
1565: putpixel (x + j, xcolors[0x000]);
1.1.1.14 root 1566: numptr++;
1567: }
1568: }
1569:
1570: static void draw_status_line (int line)
1571: {
1.1.1.17 root 1572: int x_start, y, j, led;
1573:
1.1.1.14 root 1574: if (td_pos & TD_RIGHT)
1.1.1.18 root 1575: x_start = gfxvidinfo.width - TD_PADX - 5 * TD_WIDTH;
1.1.1.14 root 1576: else
1.1.1.18 root 1577: x_start = TD_PADX;
1.1.1.14 root 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++) {
1.1.1.20! root 1587: int side, pos, num1 = -1, num2 = -1, num3 = -1, num4 = -1;
! 1588: int x, off_rgb, on_rgb, c, on = 0;
1.1.1.14 root 1589: if (led > 0) {
1.1.1.17 root 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;
1.1.1.18 root 1599: on = gui_data.drive_motor[pled];
1600: if (gui_data.drive_writing[pled])
1.1.1.17 root 1601: on_rgb = 0xc00;
1602: }
1603: /*side = gui_data.drive_side;*/
1.1.1.14 root 1604: } else {
1.1.1.17 root 1605: pos = 0;
1.1.1.14 root 1606: on = gui_data.powerled;
1.1.1.17 root 1607: on_rgb = 0xc00;
1608: off_rgb = 0x300;
1.1.1.14 root 1609: }
1610: c = xcolors[on ? on_rgb : off_rgb];
1.1.1.20! root 1611: if (y == 0 || y == TD_TOTAL_HEIGHT - 1)
! 1612: c = xcolors[TD_BORDER];
1.1.1.14 root 1613:
1.1.1.17 root 1614: x = x_start + pos * TD_WIDTH;
1.1.1.20! root 1615: putpixel (x - 1, xcolors[TD_BORDER]);
1.1.1.18 root 1616: for (j = 0; j < TD_LED_WIDTH; j++)
1.1.1.14 root 1617: putpixel (x + j, c);
1.1.1.20! root 1618: putpixel (x + j, xcolors[TD_BORDER]);
1.1.1.14 root 1619:
1620: if (y >= TD_PADY && y - TD_PADY < TD_NUM_HEIGHT) {
1.1.1.17 root 1621: if (num3 >= 0) {
1622: int tn = num1 > 0 ? 3 : 2;
1.1.1.20! root 1623: x += (TD_LED_WIDTH - tn * TD_NUM_WIDTH) / 2;
1.1.1.17 root 1624: if (num1 > 0) {
1.1.1.20! root 1625: write_tdnumber (x, y - TD_PADY, num1);
! 1626: x += TD_NUM_WIDTH;
1.1.1.17 root 1627: }
1.1.1.20! root 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;
1.1.1.17 root 1632: if (num4 > 0)
1.1.1.20! root 1633: write_tdnumber (x, y - TD_PADY, num4);
1.1.1.14 root 1634: }
1635: }
1636: }
1637: }
1638:
1.1 root 1639: void finish_drawing_frame (void)
1640: {
1641: int i;
1642:
1643: if (! lockscr ()) {
1644: notice_screen_contents_lost ();
1645: return;
1646: }
1.1.1.15 root 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
1.1 root 1656: for (i = 0; i < max_ypos_thisframe; i++) {
1657: int where;
1.1.1.14 root 1658: int i1 = i + min_ypos_for_screen;
1.1 root 1659: int line = i + thisframe_y_adjust_real;
1660:
1661: if (linestate[line] == LINE_UNDECIDED)
1662: break;
1663:
1.1.1.14 root 1664: where = amiga2aspect_line_map[i1];
1.1.1.20! root 1665: if (where >= gfxvidinfo.height - (curr_gfx->leds_on_screen ? TD_TOTAL_HEIGHT : 0))
1.1 root 1666: break;
1667: if (where == -1)
1668: continue;
1669:
1.1.1.14 root 1670: pfield_draw_line (line, where, amiga2aspect_line_map[i1 + 1]);
1.1 root 1671: }
1.1.1.20! root 1672: if (curr_gfx->leds_on_screen) {
1.1.1.17 root 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: }
1.1.1.14 root 1678: }
1.1 root 1679: do_flush_screen (first_drawn_line, last_drawn_line);
1680: }
1681:
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:
1.1.1.6 root 1698: STATIC_INLINE void check_picasso (void)
1.1 root 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)
1.1.1.3 root 1711: clear_inhibit_frame (IHF_PICASSO);
1.1 root 1712: else
1.1.1.3 root 1713: set_inhibit_frame (IHF_PICASSO);
1.1 root 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:
1.1.1.20! root 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:
1.1 root 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:
1.1.1.13 root 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;
1.1.1.18 root 1796: uae_reset (0);
1.1.1.13 root 1797: }
1798:
1.1 root 1799: if (quit_program < 0) {
1800: quit_program = -quit_program;
1.1.1.3 root 1801: set_inhibit_frame (IHF_QUIT_PROGRAM);
1.1.1.11 root 1802: set_special (SPCFLAG_BRK);
1.1 root 1803: filesys_prepare_reset ();
1804: return;
1805: }
1806:
1807: count_frame ();
1808: check_picasso ();
1809:
1.1.1.20! root 1810: currprefs.keyboard_lang = changed_prefs.keyboard_lang;
1.1.1.2 root 1811: check_prefs_changed_audio ();
1.1 root 1812: check_prefs_changed_custom ();
1813: check_prefs_changed_cpu ();
1814: if (check_prefs_changed_gfx ()) {
1.1.1.19 root 1815: if (curr_gfx) {
1816: init_row_map ();
1817: init_aspect_maps ();
1818: }
1.1 root 1819: notice_screen_contents_lost ();
1820: notice_new_xcolors ();
1.1.1.20! root 1821:
! 1822: if (screen_is_picasso)
! 1823: picasso_enablescreen (1);
1.1 root 1824: }
1825:
1826: if (inhibit_frame != 0)
1827: framecnt = 1;
1828:
1829: if (framecnt == 0)
1830: init_drawing_frame ();
1831: }
1832: }
1833:
1.1.1.2 root 1834: void hsync_record_line_state (int lineno, enum nln_how how, int changed)
1.1 root 1835: {
1.1.1.2 root 1836: char *state;
1.1 root 1837: if (framecnt != 0)
1838: return;
1.1.1.2 root 1839:
1840: state = linestate + lineno;
1841: changed += frame_redraw_necessary;
1842:
1.1 root 1843: switch (how) {
1844: case nln_normal:
1.1.1.2 root 1845: *state = changed ? LINE_DECIDED : LINE_DONE;
1.1 root 1846: break;
1847: case nln_doubled:
1.1.1.2 root 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;
1.1 root 1856: break;
1857: case nln_lower:
1.1.1.2 root 1858: if (state[-1] == LINE_UNDECIDED)
1859: state[-1] = LINE_BLACK;
1860: *state = changed ? LINE_DECIDED : LINE_DONE;
1.1 root 1861: break;
1862: case nln_upper:
1.1.1.2 root 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;
1.1 root 1868: break;
1869: }
1870: }
1871:
1872: void notice_interlace_seen (void)
1873: {
1874: interlace_seen = 1;
1875: }
1876:
1877: void reset_drawing (void)
1878: {
1879: int i;
1880:
1881: max_diwstop = 0;
1882:
1.1.1.19 root 1883: if (!curr_gfx)
1884: return;
1885: lores_factor = curr_gfx->lores ? 1 : 2;
1886: lores_shift = curr_gfx->lores ? 0 : 1;
1.1 root 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:
1.1.1.11 root 1903: memset (spixels, 0, sizeof spixels);
1904: memset (&spixstate, 0, sizeof spixstate);
1905:
1.1 root 1906: init_drawing_frame ();
1907: }
1908:
1.1.1.20! root 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:
1.1 root 1919: void drawing_init ()
1920: {
1.1.1.20! root 1921: inhibit_frame = 0;
! 1922:
1.1 root 1923: native2amiga_line_map = 0;
1924: amiga2aspect_line_map = 0;
1925: line_drawn = 0;
1926:
1.1.1.20! root 1927: gen_pfield_tables ();
1.1 root 1928: }
1929:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.