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