--- uae/src/drawing.c 2018/04/24 16:53:01 1.1.1.9 +++ uae/src/drawing.c 2018/04/24 17:07:22 1.1.1.16 @@ -5,6 +5,7 @@ * * Copyright 1995-2000 Bernd Schmidt * Copyright 1995 Alessandro Bissacco + * Copyright 2000,2001 Toni Wilen */ /* There are a couple of concepts of "coordinates" in this file. @@ -33,20 +34,19 @@ #include "config.h" #include "options.h" -#include "threaddep/penguin.h" +#include "threaddep/thread.h" #include "uae.h" #include "memory.h" #include "custom.h" -#include "readcpu.h" #include "newcpu.h" #include "xwin.h" #include "autoconf.h" #include "gui.h" #include "picasso96.h" #include "drawing.h" +#include "savestate.h" -int lores_factor, lores_shift, sprite_width, borderblank; -int fetchmode, fetchstart, fetchstart_shift, prefetch, fetchsize; +int lores_factor, lores_shift; /* The shift factor to apply when converting between Amiga coordinates and window coordinates. Zero if the resolution is the same, positive if window coordinates @@ -56,11 +56,24 @@ static int res_shift; static int interlace_seen = 0; -static int dblpf_ind1[256], dblpf_ind2[256], dblpf_2nd1[256], dblpf_2nd2[256]; -static int dblpf_aga1[256], dblpf_aga2[256], linear_map_256[256], lots_of_twos[256]; +/* Lookup tables for dual playfields. The dblpf_*1 versions are for the case + that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has + priority. If we need an array for non-dual playfield mode, it has no number. */ +/* The dbplpf_ms? arrays contain a shift value. plf_spritemask is initialized + to contain two 16 bit words, with the appropriate mask if pf1 is in the + foreground being at bit offset 0, the one used if pf2 is in front being at + offset 16. */ + +static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256]; +static int dblpf_ind1[256], dblpf_ind2[256]; + +static int dblpf_2nd1[256], dblpf_2nd2[256]; +static int dblpf_ind1_aga[256], dblpf_ind2_aga[256]; static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 }; +static int sprite_offs[256]; + static uae_u32 clxtab[256]; /* Video buffer description structure. Filled in by the graphics system @@ -82,12 +95,17 @@ union { /* Let's try to align this thing. */ double uupzuq; long int cruxmedo; - uae_u8 apixels[1760]; - uae_u16 apixels_w[880]; - uae_u32 apixels_l[440]; + uae_u8 apixels[MAX_PIXELS_PER_LINE * 2]; + uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / 2]; + uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / 4]; } pixdata; -uae_u32 ham_linebuf[1760]; +uae_u16 spixels[2 * MAX_SPR_PIXELS]; +/* Eight bits for every pixel. */ +union sps_union spixstate; + +static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2]; +static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE * 2]; /* AGA dualplayfield sprite */ char *xlinebuffer; @@ -134,9 +152,9 @@ static int first_block_line, last_block_ /* These are generated by the drawing code from the line_decisions array for each line that needs to be drawn. These are basically extracted out of bit fields in the hardware registers. */ -static int bplehb, bplham, bpldualpf, bpldualpfpri, bplplanecnt, bplres; -static int bpldelay1, bpldelay2; -static int plfpri[3]; +static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, bplres; +static uae_u32 plf_sprite_mask; +static int sbasecol[2]; int picasso_requested_on; int picasso_on; @@ -159,7 +177,7 @@ int coord_native_to_amiga_x (int x) { x += visible_left_border; x <<= (1 - lores_shift); - return x + 2*DISPLAY_LEFT_SHIFT; + return x + 2*DISPLAY_LEFT_SHIFT - 2*DIW_DDF_OFFSET; } int coord_native_to_amiga_y (int y) @@ -219,15 +237,12 @@ static int unpainted; * borders. */ static void pfield_init_linetoscr (void) { - int delay_changes = dip_for_drawing->last_delay_change != dip_for_drawing->first_delay_change; - int mindelay = delay_changes ? 0 : bpldelay1 > bpldelay2 ? bpldelay2 : bpldelay1; - int maxdelay = delay_changes ? (16 << fetchmode) - 1 : bpldelay1 < bpldelay2 ? bpldelay2 : bpldelay1; /* First, get data fetch start/stop in DIW coordinates. */ - int ddf_left = (dp_for_drawing->plfstrt + prefetch) * 2; - int ddf_right = (dp_for_drawing->plfstrt + dp_for_drawing->plflinelen + prefetch) * 2; + int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET; + int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET; /* Compute datafetch start/stop in pixels; native display coordinates. */ - int native_ddf_left = coord_hw_to_window_x (ddf_left + mindelay); - int native_ddf_right = coord_hw_to_window_x (ddf_right + maxdelay); + int native_ddf_left = coord_hw_to_window_x (ddf_left); + int native_ddf_right = coord_hw_to_window_x (ddf_right); int linetoscr_diw_start = dp_for_drawing->diwfirstword; int linetoscr_diw_end = dp_for_drawing->diwlastword; @@ -257,16 +272,13 @@ static void pfield_init_linetoscr (void) /* Now, compute some offsets. */ - /* Convert ddf_left/ddf_right into Amiga coordinate system used by the - sprite drawing code. */ - ddf_left = ddf_left + mindelay - DISPLAY_LEFT_SHIFT; - if (currprefs.gfx_lores == 0) - ddf_left <<= 1; - res_shift = lores_shift - bplres; - pixels_offset = 880 - ddf_left; + ddf_left -= DISPLAY_LEFT_SHIFT; + ddf_left <<= bplres; + pixels_offset = MAX_PIXELS_PER_LINE - ddf_left; + unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start; - src_pixel = 880 + res_shift_from_window (playfield_start - native_ddf_left + unpainted); + src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left + unpainted); if (dip_for_drawing->nr_sprites == 0) return; @@ -274,13 +286,13 @@ static void pfield_init_linetoscr (void) if (linetoscr_diw_start < native_ddf_left) { int size = res_shift_from_window (native_ddf_left - linetoscr_diw_start); linetoscr_diw_start = native_ddf_left; - memset (pixdata.apixels + 880 - size, 0, size); + memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size); } if (linetoscr_diw_end > native_ddf_right) { int pos = res_shift_from_window (native_ddf_right - native_ddf_left); int size = res_shift_from_window (linetoscr_diw_end - native_ddf_right); linetoscr_diw_start = native_ddf_left; - memset (pixdata.apixels + 880 + pos, 0, size); + memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size); } } @@ -490,9 +502,7 @@ static void pfield_do_linetoscr (int sta } else abort (); - } else { - if (res_shift == 0) switch (gfxvidinfo.pixbytes) { case 1: src_pixel = linetoscr_8 (src_pixel, start, stop); break; @@ -553,7 +563,15 @@ static void init_ham_decoding (void) ham_decode_pixel = src_pixel; ham_lastcolor = color_reg_get (&colors_for_drawing, 0); - if (currprefs.chipset_mask & CSMASK_AGA) { + if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) { + if (unpainted_amiga > 0) { + int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1]; + if (currprefs.chipset_mask & CSMASK_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; + else + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; + } + } else if (currprefs.chipset_mask & CSMASK_AGA) { if (bplplanecnt == 8) { /* AGA mode HAM8 */ while (unpainted_amiga-- > 0) { int pv = pixdata.apixels[ham_decode_pixel++]; @@ -564,7 +582,7 @@ static void init_ham_decoding (void) case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; } } - } else if(bplplanecnt == 6) { /* AGA mode HAM6 */ + } else if (bplplanecnt == 6) { /* AGA mode HAM6 */ while (unpainted_amiga-- > 0) { int pv = pixdata.apixels[ham_decode_pixel++]; switch (pv & 0x30) { @@ -593,10 +611,18 @@ static void init_ham_decoding (void) static void decode_ham (int pix, int stoppos) { int todraw_amiga = res_shift_from_window (stoppos - pix); - if (!bplham || (bplplanecnt != 6 && bplplanecnt != 8)) - abort (); - if (currprefs.chipset_mask & CSMASK_AGA) { + if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) { + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; + if (currprefs.chipset_mask & CSMASK_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; + else + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; + + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } else if (currprefs.chipset_mask & CSMASK_AGA) { if (bplplanecnt == 8) { /* AGA mode HAM8 */ while (todraw_amiga-- > 0) { int pv = pixdata.apixels[ham_decode_pixel]; @@ -608,7 +634,7 @@ static void decode_ham (int pix, int sto } ham_linebuf[ham_decode_pixel++] = ham_lastcolor; } - } else if(bplplanecnt == 6) { /* AGA mode HAM6 */ + } else if (bplplanecnt == 6) { /* AGA mode HAM6 */ while (todraw_amiga-- > 0) { int pv = pixdata.apixels[ham_decode_pixel]; switch (pv & 0x30) { @@ -648,15 +674,21 @@ static void gen_pfield_tables (void) for (i = 0; i < 256; i++) { int plane1 = (i & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8); int plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8); + dblpf_2nd1[i] = plane1 == 0 ? (plane2 == 0 ? 0 : 2) : 1; dblpf_2nd2[i] = plane2 == 0 ? (plane1 == 0 ? 0 : 1) : 2; + dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1; + dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2; + + dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0; + dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8; + dblpf_ms[i] = i == 0 ? 16 : 8; if (plane2 > 0) plane2 += 8; dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1); dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2); - lots_of_twos[i] = i == 0 ? 0 : 2; - linear_map_256[i] = i; + sprite_offs[i] = (i & 15) ? 0 : 2; clxtab[i] = ((((i & 3) && (i & 12)) << 9) | (((i & 3) && (i & 48)) << 10) @@ -667,217 +699,184 @@ static void gen_pfield_tables (void) } } -static uae_u32 attach_2nd; - -static uae_u32 do_sprite_collisions (struct sprite_draw *spd, int prev_overlap, int i, int nr_spr) -{ - int j; - int sprxp = spd[i].linepos; - uae_u32 datab = spd[i].datab; - uae_u32 mask2 = 0; - int sbit = 1 << spd[i].num; - int sprx_shift = 1; - int attach_compare = -1; - if (currprefs.gfx_lores != 1) - sprx_shift = 0; - - attach_2nd = 0; - if ((spd[i].num & 1) == 1 && (spd[i].ctl & 0x80) == 0x80) - attach_compare = spd[i].num - 1; - - for (j = prev_overlap; j < i; j++) { - uae_u32 mask1; - int off; - - if (spd[i].num < spd[j].num) - continue; - - off = sprxp - spd[j].linepos; - off <<= sprx_shift; - mask1 = spd[j].datab >> off; - - /* If j is an attachment for i, then j doesn't block i */ - if (spd[j].num == attach_compare) { - attach_2nd |= mask1; - } else { - mask1 |= (mask1 & 0xAAAAAAAA) >> 1; - mask1 |= (mask1 & 0x55555555) << 1; - if (datab & mask1) - clxdat |= clxtab[(sbit | (1 << spd[j].num)) & clx_sprmask]; - mask2 |= mask1; - } - } - for (j = i+1; j < nr_spr; j++) { - uae_u32 mask1; - int off = spd[j].linepos - sprxp; - - if (off >= sprite_width || spd[i].num < spd[j].num) - break; - - off <<= sprx_shift; - mask1 = spd[j].datab << off; - - /* If j is an attachment for i, then j doesn't block i */ - if (spd[j].num == attach_compare) { - attach_2nd |= mask1; - } else { - mask1 |= (mask1 & 0xAAAAAAAA) >> 1; - mask1 |= (mask1 & 0x55555555) << 1; - if (datab & mask1) - clxdat |= clxtab[(sbit | (1 << spd[j].num)) & clx_sprmask]; - mask2 |= mask1; - } - } - datab &= ~mask2; - return datab; -} - -/* We use the compiler's inlining ability to ensure that HAM, ATTCH and - SPRX_INC are in effect compile time constants. That will cause some - unnecessary code to be optimized away. - Don't touch this if you don't know what you are doing. */ -static void render_sprite (int spr, int sprxp, uae_u32 datab, int ham, int attch, int sprx_inc) -{ - uae_u32 datcd; - int basecol = 16; - if (!attch) - basecol += (spr & ~1)*2; - if (bpldualpf) - basecol |= 128; - if (attch) - datcd = attach_2nd; - - for (; attch ? datab | datcd : datab; sprxp += sprx_inc) { - int col; - - if (attch) { - col = ((datab & 3) << 2) | (datcd & 3); - datcd >>= 2; - } else - col = datab & 3; - datab >>= 2; - if (col) { - col |= basecol; - if (ham) { - col = color_reg_get (&colors_for_drawing, col); - ham_linebuf[sprxp + pixels_offset] = col; - if (sprx_inc == 2) { - ham_linebuf[sprxp + pixels_offset + 1] = col; - } +/* When looking at this function and the ones that inline it, bear in mind + what an optimizing compiler will do with this code. All callers of this + function only pass in constant arguments (except for E). This means + that many of the if statements will go away completely after inlining. */ +STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int ham, int dualpf, + int doubling, int skip, int has_attach, int aga) +{ + int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; + uae_u16 *buf = spixels + e->first_pixel; + uae_u8 *stbuf = spixstate.bytes + e->first_pixel; + int pos, window_pos; + uae_u8 xor_val = (uae_u8)(dp_for_drawing->bplcon4 >> 8); + + buf -= e->pos; + stbuf -= e->pos; + + window_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (aga ? 1 : 0)); + if (skip) + window_pos >>= 1; + else if (doubling) + window_pos <<= 1; + window_pos += pixels_offset; + for (pos = e->pos; pos < e->max; pos += 1 << skip) { + int maskshift, plfmask; + unsigned int v = buf[pos]; + + /* The value in the shift lookup table is _half_ the shift count we + need. This is because we can't shift 32 bits at once (undefined + behaviour in C). */ + maskshift = shift_lookup[pixdata.apixels[window_pos]]; + plfmask = (plf_sprite_mask >> maskshift) >> maskshift; + v &= ~plfmask; + if (v != 0) { + unsigned int vlo, vhi, col; + unsigned int v1 = v & 255; + /* OFFS determines the sprite pair with the highest priority that has + any bits set. E.g. if we have 0xFF00 in the buffer, we have sprite + pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will + have a value of 4. + 2 * OFFS is the bit number in V of the sprite pair, and it also + happens to be the color offset for that pair. */ + int offs; + if (v1 == 0) + offs = 4 + sprite_offs[v >> 8]; + else + offs = sprite_offs[v1]; + + /* Shift highest priority sprite pair down to bit zero. */ + v >>= offs * 2; + v &= 15; + + if (has_attach && (stbuf[pos] & (1 << offs))) { + col = v; + if (aga) + col += sbasecol[1]; + else + col += 16; } else { - pixdata.apixels[sprxp + pixels_offset] = col; - if (sprx_inc == 2) { - pixdata.apixels[sprxp + pixels_offset + 1] = col; - } - } - } - } -} - -STATIC_INLINE void walk_sprites (struct sprite_draw *spd, int nr_spr) -{ - int i, prev_overlap; - int last_sprite_pos = -64; - uae_u32 plane1 = 0, plane2 = 0; - int sprx_inc = 1, sprx_shift = 1; - - if (currprefs.gfx_lores == 0) - sprx_inc = 2, sprx_shift = 0; - - prev_overlap = 0; - for (i = 0; i < nr_spr; i++) { - int sprxp = spd[i].linepos; - int m = 1 << spd[i].num; - uae_u32 datab; - while (prev_overlap < i && spd[prev_overlap].linepos + sprite_width <= sprxp) - prev_overlap++; - - datab = do_sprite_collisions (spd, prev_overlap, i, nr_spr); - if (currprefs.gfx_lores == 2) - sprxp >>= 1; - if ((bpldualpf && plfpri[1] < 256) || (plfpri[2] < 256)) { - if (sprxp != last_sprite_pos) { - int ok = last_sprite_pos-sprxp+16; - int ok2; - if (ok <= 0) { - ok = ok2 = 0; - plane1 = 0; - plane2 = 0; + /* This sequence computes the correct color value. We have to select + either the lower-numbered or the higher-numbered sprite in the pair. + We have to select the high one if the low one has all bits zero. + If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in + the range of 0..2, and with the mask and shift, VHI will be zero. + If the lower-numbered sprite is zero, (VLO - 1) is a mask of + 0xFFFFFFFF, and we select the bits of the higher numbered sprite + in VHI. + This is _probably_ more efficient than doing it with branches. */ + vlo = v & 3; + vhi = (v & (vlo - 1)) >> 2; + col = (vlo | vhi); + if (aga) { + if (vhi > 0) + col += sbasecol[1]; + else + col += sbasecol[0]; } else { - ok2 = ok << sprx_shift; - plane1 >>= 32 - ok2; - plane2 >>= 32 - ok2; - } - last_sprite_pos = sprxp; - - if (bpldualpf) { - uae_u32 mask = 3 << ok2; - int p = sprxp+ok; - - for (; mask; mask <<= 2, p += sprx_inc) { - int data = pixdata.apixels[p + pixels_offset]; - if (dblpf_2nd2[data] == 2) - plane2 |= mask; - if (dblpf_2nd1[data] == 1) - plane1 |= mask; - } - } else { - uae_u32 mask = 3 << ok2; - int p = sprxp+ok; - - for (; mask; mask <<= 2, p += sprx_inc) { - if (pixdata.apixels[p + pixels_offset]) - plane2 |= mask; - } + col += 16; } + col += (offs * 2); } - if (bpldualpf && m >= plfpri[1]) { - datab &= ~plane1; - attach_2nd &= ~plane1; - } - if (m >= plfpri[2]) { - datab &= ~plane2; - attach_2nd &= ~plane2; - } - } - /* If this seems strange to you, see the comment near render_sprite - about inlining. If it still seems strange, don't touch any of - this. */ - if ((spd[i].num & 1) == 1 && (spd[i].ctl & 0x80) == 0x80) { - /* Attached sprite */ - if (bplham) { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 1, 1, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 1, 1, 2); - } - } else { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 0, 1, 1); + if (dualpf) { + if (aga) { + spriteagadpfpixels[window_pos] = col; + if (doubling) + spriteagadpfpixels[window_pos + 1] = col; } else { - render_sprite (spd[i].num, sprxp, datab, 0, 1, 2); - } - } - /* This still leaves one attached sprite bug, but at the moment I'm too lazy */ - if (i + 1 < nr_spr && spd[i+1].num == spd[i].num - 1 && spd[i+1].linepos == spd[i].linepos) - i++; - } else { - if (0 && bplham) { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 1, 0, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 1, 0, 2); + col += 128; + if (doubling) + pixdata.apixels_w[window_pos >> 1] = col | (col << 8); + else + pixdata.apixels[window_pos] = col; } + } else if (ham) { + col = color_reg_get (&colors_for_drawing, col); + if (aga) + col ^= xor_val; + ham_linebuf[window_pos] = col; + if (doubling) + ham_linebuf[window_pos + 1] = col; } else { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 0, 0, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 0, 0, 2); - } + if (aga) + col ^= xor_val; + if (doubling) + pixdata.apixels_w[window_pos >> 1] = col | (col << 8); + else + pixdata.apixels[window_pos] = col; } } + window_pos += 1 << doubling; } } + +/* See comments above. Do not touch if you don't know what's going on. + * (We do _not_ want the following to be inlined themselves). */ +/* lores bitplane, lores sprites */ +static void draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 0, 0); } +static void draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 0, 0); } +static void draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 0, 0); } +static void draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 1, 0); } +static void draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 1, 0); } +static void draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 1, 0); } +/* hires bitplane, lores sprites */ +static void draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 0, 0); } +static void draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 0, 0); } +static void draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 0, 0); } +static void draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 1, 0); } +static void draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 1, 0); } +static void draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 1, 0); } + +/* not very optimized */ +STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e) +{ + int diff = RES_HIRES - bplres; + if (diff > 0) + draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, 0, diff, e->has_attached, 1); + else + draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, -diff, 0, e->has_attached, 1); +} + + +STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e) +{ + if (e->has_attached) + if (bplres == 1) + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_hi_at (e); + else + if (bpldualpf) + draw_sprites_normal_dp_hi_at (e); + else + draw_sprites_normal_sp_hi_at (e); + else + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_lo_at (e); + else + if (bpldualpf) + draw_sprites_normal_dp_lo_at (e); + else + draw_sprites_normal_sp_lo_at (e); + else + if (bplres == 1) + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_hi_nat (e); + else + if (bpldualpf) + draw_sprites_normal_dp_hi_nat (e); + else + draw_sprites_normal_sp_hi_nat (e); + else + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_lo_nat (e); + else + if (bpldualpf) + draw_sprites_normal_dp_lo_nat (e); + else + draw_sprites_normal_sp_lo_nat (e); +} + #define MERGE(a,b,mask,shift) do {\ uae_u32 tmp = mask & (a ^ (b >> shift)); \ @@ -885,30 +884,26 @@ STATIC_INLINE void walk_sprites (struct b ^= (tmp << shift); \ } while (0) -#define GETLONG(P, SHIFT, SHIFT_ZERO) \ - ((SHIFT_ZERO) ? do_get_mem_long (P) \ - : (do_get_mem_long (P) << (32 - (SHIFT))) | (do_get_mem_long ((P) + 1) >> (SHIFT))) - -/* We use the compiler's inlining ability to ensure that PLANES, D1Z and D2Z - are in effect compile time constants. That will cause some unnecessary - code to be optimized away. +#define GETLONG(P) (*(uae_u32 *)P) + +/* We use the compiler's inlining ability to ensure that PLANES is in effect a compile time + constant. That will cause some unnecessary code to be optimized away. Don't touch this if you don't know what you are doing. */ -STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int delay1, int delay2, int d1z, int d2z, - int wordcount, int planes) +STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes) { while (wordcount-- > 0) { uae_u32 b0, b1, b2, b3, b4, b5, b6, b7; b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0; switch (planes) { - case 8: b0 = GETLONG ((uae_u32 *)real_bplpt[7], delay2, d2z); real_bplpt[7] += 4; - case 7: b1 = GETLONG ((uae_u32 *)real_bplpt[6], delay1, d1z); real_bplpt[6] += 4; - case 6: b2 = GETLONG ((uae_u32 *)real_bplpt[5], delay2, d2z); real_bplpt[5] += 4; - case 5: b3 = GETLONG ((uae_u32 *)real_bplpt[4], delay1, d1z); real_bplpt[4] += 4; - case 4: b4 = GETLONG ((uae_u32 *)real_bplpt[3], delay2, d2z); real_bplpt[3] += 4; - case 3: b5 = GETLONG ((uae_u32 *)real_bplpt[2], delay1, d1z); real_bplpt[2] += 4; - case 2: b6 = GETLONG ((uae_u32 *)real_bplpt[1], delay2, d2z); real_bplpt[1] += 4; - case 1: b7 = GETLONG ((uae_u32 *)real_bplpt[0], delay1, d1z); real_bplpt[0] += 4; + case 8: b0 = GETLONG ((uae_u32 *)real_bplpt[7]); real_bplpt[7] += 4; + case 7: b1 = GETLONG ((uae_u32 *)real_bplpt[6]); real_bplpt[6] += 4; + case 6: b2 = GETLONG ((uae_u32 *)real_bplpt[5]); real_bplpt[5] += 4; + case 5: b3 = GETLONG ((uae_u32 *)real_bplpt[4]); real_bplpt[4] += 4; + case 4: b4 = GETLONG ((uae_u32 *)real_bplpt[3]); real_bplpt[3] += 4; + case 3: b5 = GETLONG ((uae_u32 *)real_bplpt[2]); real_bplpt[2] += 4; + case 2: b6 = GETLONG ((uae_u32 *)real_bplpt[1]); real_bplpt[1] += 4; + case 1: b7 = GETLONG ((uae_u32 *)real_bplpt[0]); real_bplpt[0] += 4; } MERGE (b0, b1, 0x55555555, 1); @@ -949,42 +944,19 @@ STATIC_INLINE void pfield_doline_1 (uae_ /* See above for comments on inlining. These functions should _not_ be inlined themselves. */ -static void pfield_doline_none_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 1); } -static void pfield_doline_none_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 2); } -static void pfield_doline_none_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 3); } -static void pfield_doline_none_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 4); } -static void pfield_doline_none_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 5); } -static void pfield_doline_none_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 6); } -static void pfield_doline_none_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 7); } -static void pfield_doline_none_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, 0, 0, 1, 1, count, 8); } - -static void pfield_doline_2_n1 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 1); } -static void pfield_doline_2_n2 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 2); } -static void pfield_doline_2_n3 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 3); } -static void pfield_doline_2_n4 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 4); } -static void pfield_doline_2_n5 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 5); } -static void pfield_doline_2_n6 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 6); } -static void pfield_doline_2_n7 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 7); } -static void pfield_doline_2_n8 (uae_u32 *data, int delay2, int count) { pfield_doline_1 (data, 0, delay2, 1, 0, count, 8); } - -static void pfield_doline_1_n1 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 1); } -static void pfield_doline_1_n2 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 2); } -static void pfield_doline_1_n3 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 3); } -static void pfield_doline_1_n4 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 4); } -static void pfield_doline_1_n5 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 5); } -static void pfield_doline_1_n6 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 6); } -static void pfield_doline_1_n7 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 7); } -static void pfield_doline_1_n8 (uae_u32 *data, int delay1, int count) { pfield_doline_1 (data, delay1, 0, 0, 1, count, 8); } +static void pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); } +static void pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); } +static void pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); } +static void pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); } +static void pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); } +static void pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); } +static void pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); } +static void pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); } static void pfield_doline (int lineno) { - /* Delay values in pixels (adjusted to the resolution). */ - int delay1 = bpldelay1 << bplres; - int delay2 = bpldelay2 << bplres; - int mindelay = delay1 < delay2 ? delay1 : delay2; - int wordcount = (dp_for_drawing->plflinelen + (RES_SHIFT (bplres) * 2 - 1)) / (RES_SHIFT (bplres) * 2); - uae_u32 *data = pixdata.apixels_l + 220; - int dsub1, dsub2; + int wordcount = dp_for_drawing->plflinelen; + uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE/4; #ifdef SMART_UPDATE #define DATA_POINTER(n) (line_data[lineno] + (n)*MAX_WORDS_PER_LINE*2) @@ -998,112 +970,17 @@ static void pfield_doline (int lineno) real_bplpt[7] = DATA_POINTER (7); #endif - delay1 -= mindelay; - delay2 -= mindelay; - - dsub1 = (delay1 + 31) >> 5; - dsub2 = (delay2 + 31) >> 5; - real_bplpt[0] -= dsub1 * 4; - real_bplpt[2] -= dsub1 * 4; - real_bplpt[4] -= dsub1 * 4; - real_bplpt[1] -= dsub2 * 4; - real_bplpt[3] -= dsub2 * 4; - real_bplpt[5] -= dsub2 * 4; - real_bplpt[6] -= dsub1 * 4; - real_bplpt[7] -= dsub2 * 4; - - if (dsub1 > dsub2) - wordcount += dsub1; - else - wordcount += dsub2; - - delay1 &= 31; - delay2 &= 31; - - if (delay1) - switch (bplplanecnt) { - default: break; - case 1: pfield_doline_1_n1 (data, delay1, wordcount); break; - case 2: pfield_doline_1_n2 (data, delay1, wordcount); break; - case 3: pfield_doline_1_n3 (data, delay1, wordcount); break; - case 4: pfield_doline_1_n4 (data, delay1, wordcount); break; - case 5: pfield_doline_1_n5 (data, delay1, wordcount); break; - case 6: pfield_doline_1_n6 (data, delay1, wordcount); break; - case 7: pfield_doline_1_n7 (data, delay1, wordcount); break; - case 8: pfield_doline_1_n8 (data, delay1, wordcount); break; - } - else if (delay2) - switch (bplplanecnt) { - default: break; - case 1: pfield_doline_2_n1 (data, delay2, wordcount); break; - case 2: pfield_doline_2_n2 (data, delay2, wordcount); break; - case 3: pfield_doline_2_n3 (data, delay2, wordcount); break; - case 4: pfield_doline_2_n4 (data, delay2, wordcount); break; - case 5: pfield_doline_2_n5 (data, delay2, wordcount); break; - case 6: pfield_doline_2_n6 (data, delay2, wordcount); break; - case 7: pfield_doline_2_n7 (data, delay2, wordcount); break; - case 8: pfield_doline_2_n8 (data, delay2, wordcount); break; - } - else - switch (bplplanecnt) { - default: break; - case 1: pfield_doline_none_n1 (data, wordcount); break; - case 2: pfield_doline_none_n2 (data, wordcount); break; - case 3: pfield_doline_none_n3 (data, wordcount); break; - case 4: pfield_doline_none_n4 (data, wordcount); break; - case 5: pfield_doline_none_n5 (data, wordcount); break; - case 6: pfield_doline_none_n6 (data, wordcount); break; - case 7: pfield_doline_none_n7 (data, wordcount); break; - case 8: pfield_doline_none_n8 (data, wordcount); break; - } -} - - -static void fix_delays(int delay, int *dst1, int *dst2) -{ - int delay1 = (delay & 0x0f) | ((delay & 0x0c00) >> 6); - int delay2 = ((delay >> 4) & 0x0f) | (((delay >> 4) & 0x0c00) >> 6); - /* this may not be 100% correct yet but at least it fixes all tested games with incorrect - * horiz position/scrolling (ex: New Zealand Story, James Pond II AGA, Action Snooker...) - */ - int delayoffset = ( (dp_for_drawing->plfstrt - 0x18) & ( (fetchstart - 1) & ~3) ) << 1; - int delaymask = ((16 << fetchmode) - 1) >> bplres; - delay1 += delayoffset; - delay2 += delayoffset; - delay1 &= delaymask; - delay2 &= delaymask; - *dst1 = delay1; - *dst2 = delay2; -} - -static void pfield_adjust_delay (void) -{ - int ddf_left = dp_for_drawing->plfstrt + prefetch; - int ddf_right = dp_for_drawing->plfstrt + dp_for_drawing->plflinelen + prefetch; - int i; - - for (i = dip_for_drawing->last_delay_change-1; i >= dip_for_drawing->first_delay_change-1; i--) { - int delayreg = i < dip_for_drawing->first_delay_change ? dp_for_drawing->bplcon1 : delay_changes[i].value; - int delay1, delay2; - int startpos = i == dip_for_drawing->last_delay_change - 1 ? ddf_right : delay_changes[i+1].linepos; - int stoppos = i < dip_for_drawing->first_delay_change ? ddf_left : delay_changes[i].linepos; - int j; - startpos = ((startpos - ddf_left) * 2) << bplres; - stoppos = ((stoppos - ddf_left) * 2) << bplres; - - fix_delays (delayreg, &delay1, & delay2); - delay1 <<= bplres; - delay2 <<= bplres; - startpos += 880; stoppos += 880; - for (j = startpos-1; j >= stoppos; j--) { - int t1 = pixdata.apixels[j - delay1]; - int t2 = pixdata.apixels[j - delay2]; -#if 0 - pixdata.apixels[j - delay1] &= 0xAA; - pixdata.apixels[j - delay2] &= 0x55; -#endif - pixdata.apixels[j] = (t1 & 0x55) | (t2 & 0xAA); - } + switch (bplplanecnt) { + default: break; + case 0: memset (data, 0, wordcount * 32); break; + case 1: pfield_doline_n1 (data, wordcount); break; + case 2: pfield_doline_n2 (data, wordcount); break; + case 3: pfield_doline_n3 (data, wordcount); break; + case 4: pfield_doline_n4 (data, wordcount); break; + case 5: pfield_doline_n5 (data, wordcount); break; + case 6: pfield_doline_n6 (data, wordcount); break; + case 7: pfield_doline_n7 (data, wordcount); break; + case 8: pfield_doline_n8 (data, wordcount); break; } } @@ -1201,7 +1078,7 @@ static void do_flush_line_1 (int lineno) last_drawn_line = lineno; if (gfxvidinfo.maxblocklines == 0) - flush_line(lineno); + flush_line (lineno); else { if ((last_block_line+1) != lineno) { if (first_block_line != -2) @@ -1236,6 +1113,7 @@ STATIC_INLINE void do_flush_screen (int if (gfxvidinfo.maxblocklines != 0 && first_block_line != -2) { flush_block (first_block_line, last_block_line); } + unlockscr (); if (start <= stop) flush_screen (start, stop); } @@ -1245,10 +1123,10 @@ static enum { color_match_acolors, color /* Set up colors_for_drawing to the state at the beginning of the currently drawn line. Try to avoid copying color tables around whenever possible. */ -static void adjust_drawing_colors (int ctable, int bplham) +static void adjust_drawing_colors (int ctable, int need_full) { if (drawing_color_matches != ctable) { - if (bplham) { + if (need_full) { color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable); color_match_type = color_match_full; } else { @@ -1257,23 +1135,12 @@ static void adjust_drawing_colors (int c color_match_type = color_match_acolors; } drawing_color_matches = ctable; - } else if (bplham && color_match_type != color_match_full) { + } else if (need_full && color_match_type != color_match_full) { color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]); color_match_type = color_match_full; } } -STATIC_INLINE void adjust_color0_for_color_change (void) -{ - drawing_color_matches = -1; - if (dp_for_drawing->color0 != 0xFFFFFFFFul) { - color_reg_set (&colors_for_drawing, 0, dp_for_drawing->color0); - colors_for_drawing.acolors[0] = getxcolor (dp_for_drawing->color0); - } -} - -#define COPPER_MAGIC_FUDGE -1 - STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield) { int i; @@ -1286,7 +1153,7 @@ STATIC_INLINE void do_color_changes (lin if (i == dip_for_drawing->last_color_change) nextpos = max_diwlastword; else - nextpos = PIXEL_XPOS (curr_color_changes[i].linepos) + (COPPER_MAGIC_FUDGE << lores_shift); + nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos * 2); nextpos_in_range = nextpos; if (nextpos > visible_right_border) @@ -1312,12 +1179,16 @@ STATIC_INLINE void do_color_changes (lin lastpos = nextpos_in_range; } if (i != dip_for_drawing->last_color_change) { - color_reg_set (&colors_for_drawing, regno, value); - colors_for_drawing.acolors[regno] = getxcolor (value); + if (regno == -1) + bplham = value; + else { + color_reg_set (&colors_for_drawing, regno, value); + colors_for_drawing.acolors[regno] = getxcolor (value); + } } if (lastpos >= visible_right_border) - break; - } + break; + } } /* We only save hardware registers during the hardware frame. Now, when @@ -1325,13 +1196,11 @@ STATIC_INLINE void do_color_changes (lin * form. */ static void pfield_expand_dp_bplcon (void) { - bplres = RES_LORES; - if (dp_for_drawing->bplcon0 & 0x8000) - bplres = RES_HIRES; - if (dp_for_drawing->bplcon0 & 0x40) - bplres = RES_SUPERHIRES; - bplplanecnt = GET_PLANES (dp_for_drawing->bplcon0); - bplham = (dp_for_drawing->bplcon0 & 0x800) == 0x800; + int plf1pri, plf2pri; + bplres = dp_for_drawing->bplres; + bplplanecnt = dp_for_drawing->nr_planes; + bplham = dp_for_drawing->ham_at_start; + if (currprefs.chipset_mask & CSMASK_AGA) { /* The KILLEHB bit exists in ECS, but is apparently meant for Genlock * stuff, and it's set by some demos (e.g. Andromeda Seven Seas) */ @@ -1339,12 +1208,15 @@ static void pfield_expand_dp_bplcon (voi } else { bplehb = (dp_for_drawing->bplcon0 & 0xFC00) == 0x6000; } - expand_fetchmodes (dp_for_drawing->fmode, dp_for_drawing->bplcon0); - fix_delays (dp_for_drawing->bplcon1, &bpldelay1, &bpldelay2); - plfpri[1] = 1 << 2*(dp_for_drawing->bplcon2 & 7); - plfpri[2] = 1 << 2*((dp_for_drawing->bplcon2 >> 3) & 7); + plf1pri = dp_for_drawing->bplcon2 & 7; + plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7; + plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri); + plf_sprite_mask |= (0xFFFF << (4 * plf1pri)) & 0xFFFF; bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400; bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40; + bpldualpf2of = (dp_for_drawing->bplcon3 >> 10) & 7; + sbasecol[0] = ((dp_for_drawing->bplcon4 >> 4) & 15) << 4; + sbasecol[1] = ((dp_for_drawing->bplcon4 >> 0) & 15) << 4; } enum double_how { @@ -1366,12 +1238,9 @@ STATIC_INLINE void pfield_draw_line (int case LINE_REMEMBERED_AS_PREVIOUS: if (!warned) write_log ("Shouldn't get here... this is a bug.\n"), warned++; - - line_decisions[lineno].which = -2; return; case LINE_BLACK: - line_decisions[lineno].which = -2; linestate[lineno] = LINE_REMEMBERED_AS_BLACK; border = 2; break; @@ -1382,20 +1251,17 @@ STATIC_INLINE void pfield_draw_line (int case LINE_AS_PREVIOUS: dp_for_drawing--; dip_for_drawing--; - if (dp_for_drawing->which != 1) + if (dp_for_drawing->plfleft == -1) border = 1; - line_decisions[lineno].which = -2; linestate[lineno] = LINE_DONE_AS_PREVIOUS; break; case LINE_DONE_AS_PREVIOUS: - line_decisions[lineno].which = -2; /* fall through */ case LINE_DONE: return; case LINE_DECIDED_DOUBLE: - line_decisions[lineno+1].which = -2; if (follow_ypos != -1) { do_double = 1; linetoscr_double_offset = gfxvidinfo.rowbytes * (follow_ypos - gfx_ypos); @@ -1404,7 +1270,7 @@ STATIC_INLINE void pfield_draw_line (int /* fall through */ default: - if (dp_for_drawing->which != 1) + if (dp_for_drawing->plfleft == -1) border = 1; linestate[lineno] = LINE_DONE; break; @@ -1412,63 +1278,59 @@ STATIC_INLINE void pfield_draw_line (int dh = dh_line; xlinebuffer = gfxvidinfo.linemem; - if (xlinebuffer == 0 && do_double && border != 2 && dip_for_drawing->nr_color_changes != 0) + if (xlinebuffer == 0 && do_double + && (border == 0 || (border != 1 && dip_for_drawing->nr_color_changes > 0))) xlinebuffer = gfxvidinfo.emergmem, dh = dh_emerg; if (xlinebuffer == 0) xlinebuffer = row_map[gfx_ypos], dh = dh_buf; xlinebuffer -= linetoscr_x_adjust_bytes; - if (border == 0 || (dp_for_drawing->plfleft >= 0 && dip_for_drawing->nr_sprites > 0)) { + if (border == 0) { pfield_expand_dp_bplcon (); - if (bplres == RES_LORES && !currprefs.gfx_lores) + if (bplres == RES_LORES && ! currprefs.gfx_lores) currprefs.gfx_lores = 2; - pfield_init_linetoscr (); - if (! border) { - if (dip_for_drawing->first_delay_change != dip_for_drawing->last_delay_change) { - bpldelay1 = bpldelay2 = 0; - pfield_doline (lineno); - pfield_adjust_delay (); - } else - pfield_doline (lineno); - } + pfield_init_linetoscr (); + pfield_doline (lineno); - /* Check color0 adjust only if we have color changes - shouldn't happen - otherwise. */ - adjust_drawing_colors (dp_for_drawing->ctable, bplham || bplehb); + adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb); /* The problem is that we must call decode_ham() BEFORE we do the sprites. */ - if (! border && bplham) { + if (! border && dp_for_drawing->ham_seen) { init_ham_decoding (); if (dip_for_drawing->nr_color_changes == 0) { /* The easy case: need to do HAM decoding only once for the * full line. */ decode_ham (visible_left_border, visible_right_border); } else /* Argh. */ { - adjust_color0_for_color_change (); do_color_changes (dummy_worker, decode_ham); - adjust_drawing_colors (dp_for_drawing->ctable, bplham || bplehb); + adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb); } + bplham = dp_for_drawing->ham_at_start; } - if (dip_for_drawing->nr_sprites != 0) - walk_sprites (curr_sprite_positions + dip_for_drawing->first_sprite_draw, dip_for_drawing->nr_sprites); + { + int i; + for (i = 0; i < dip_for_drawing->nr_sprites; i++) { + if (currprefs.chipset_mask & CSMASK_AGA) + draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + else + draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + } + } - adjust_color0_for_color_change (); do_color_changes (pfield_do_fill_line, pfield_do_linetoscr); - if (dh == dh_emerg) - memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); do_flush_line (gfx_ypos); if (do_double) { if (dh == dh_emerg) - memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); else if (dh == dh_buf) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); - line_decisions[lineno + 1].which = -2; + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width); do_flush_line (follow_ypos); } if (currprefs.gfx_lores == 2) @@ -1476,9 +1338,6 @@ STATIC_INLINE void pfield_draw_line (int } else if (border == 1) { adjust_drawing_colors (dp_for_drawing->ctable, 0); - /* Check color0 adjust only if we have color changes - shouldn't happen - * otherwise. */ - if (dip_for_drawing->nr_color_changes == 0) { fill_line (); do_flush_line (gfx_ypos); @@ -1501,22 +1360,20 @@ STATIC_INLINE void pfield_draw_line (int playfield_start = visible_right_border; playfield_end = visible_right_border; - adjust_color0_for_color_change (); do_color_changes (pfield_do_fill_line, pfield_do_fill_line); if (dh == dh_emerg) - memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); do_flush_line (gfx_ypos); if (do_double) { if (dh == dh_emerg) - memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); else if (dh == dh_buf) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width); /* If dh == dh_line, do_flush_line will re-use the rendered line * from linemem. */ do_flush_line (follow_ypos); - line_decisions[lineno + 1].which = -2; } } else { xcolnr tmp = colors_for_drawing.acolors[0]; @@ -1594,11 +1451,6 @@ static void init_drawing_frame (void) init_hardware_for_drawing_frame (); - if (max_diwstop == 0) - max_diwstop = diwlastword; - if (min_diwstart > max_diwstop) - min_diwstart = 0; - if (thisframe_first_drawn_line == -1) thisframe_first_drawn_line = minfirstline; if (thisframe_first_drawn_line > thisframe_last_drawn_line) @@ -1638,37 +1490,159 @@ static void init_drawing_frame (void) drawing_color_matches = -1; } +/* + * Some code to put status information on the screen. + */ + +#define TD_PADX 10 +#define TD_PADY 2 +#define TD_WIDTH 32 +#define TD_LED_WIDTH 24 +#define TD_LED_HEIGHT 4 + +#define TD_RIGHT 1 +#define TD_BOTTOM 2 + +static int td_pos = (TD_RIGHT|TD_BOTTOM); + +#define TD_NUM_WIDTH 7 +#define TD_NUM_HEIGHT 7 + +#define TD_TOTAL_HEIGHT (TD_PADY * 2 + TD_NUM_HEIGHT) + +static char *numbers = { /* ugly */ +"------ ------ ------ ------ ------ ------ ------ ------ ------ ------ " +"-xxxxx ---xx- -xxxxx -xxxxx -x---x -xxxxx -xxxxx -xxxxx -xxxxx -xxxxx " +"-x---x ----x- -----x -----x -x---x -x---- -x---- -----x -x---x -x---x " +"-x---x ----x- -xxxxx -xxxxx -xxxxx -xxxxx -xxxxx ----x- -xxxxx -xxxxx " +"-x---x ----x- -x---- -----x -----x -----x -x---x ---x-- -x---x -----x " +"-xxxxx ----x- -xxxxx -xxxxx -----x -xxxxx -xxxxx ---x-- -xxxxx -xxxxx " +"------ ------ ------ ------ ------ ------ ------ ------ ------ ------ " +}; + +STATIC_INLINE void putpixel (int x, xcolnr c8) +{ + switch(gfxvidinfo.pixbytes) + { + case 1: + xlinebuffer[x] = (uae_u8)c8; + break; + case 2: + { + uae_u16 *p = (uae_u16 *)xlinebuffer + x; + *p = c8; + break; + } + case 3: + /* no 24 bit yet */ + break; + case 4: + { + uae_u32 *p = (uae_u32 *)xlinebuffer + x; + *p = c8; + break; + } + } +} + +static void write_tdnumber (int x, int y, int num) +{ + int j; + uae_u8 *numptr; + + numptr = numbers + num * TD_NUM_WIDTH + 10 * TD_NUM_WIDTH * y; + for (j = 0; j < TD_NUM_WIDTH; j++) { + putpixel (x + j, *numptr == 'x' ? xcolors[0xfff] : xcolors[0x000]); + numptr++; + } +} + +static void draw_status_line (int line) +{ + int x, y, i, j, led, on; + int on_rgb, off_rgb, c; + uae_u8 *buf; + + if (td_pos & TD_RIGHT) + x = gfxvidinfo.width - TD_PADX - 5*TD_WIDTH; + else + x = TD_PADX; + + y = line - (gfxvidinfo.height - TD_TOTAL_HEIGHT); + xlinebuffer = gfxvidinfo.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + + memset (xlinebuffer, 0, gfxvidinfo.width * gfxvidinfo.pixbytes); + + for (led = 0; led < 5; led++) { + int track; + if (led > 0) { + track = gui_data.drive_track[led-1]; + on = gui_data.drive_motor[led-1]; + on_rgb = 0x0f0; + off_rgb = 0x040; + } else { + track = -1; + on = gui_data.powerled; + on_rgb = 0xf00; + off_rgb = 0x400; + } + c = xcolors[on ? on_rgb : off_rgb]; + + for (j = 0; j < TD_LED_WIDTH; j++) + putpixel (x + j, c); + + if (y >= TD_PADY && y - TD_PADY < TD_NUM_HEIGHT) { + if (track >= 0) { + int offs = (TD_WIDTH - 2 * TD_NUM_WIDTH) / 2; + write_tdnumber (x + offs, y - TD_PADY, track / 10); + write_tdnumber (x + offs + TD_NUM_WIDTH, y - TD_PADY, track % 10); + } + } + x += TD_WIDTH; + } +} + void finish_drawing_frame (void) { int i; -#ifndef SMART_UPDATE - /* @@@ This isn't exactly right yet. FIXME */ - if (!interlace_seen) { - do_flush_screen (first_drawn_line, last_drawn_line); - return; - } -#endif if (! lockscr ()) { notice_screen_contents_lost (); return; } + +#ifndef SMART_UPDATE + /* @@@ This isn't exactly right yet. FIXME */ + if (!interlace_seen) + do_flush_screen (first_drawn_line, last_drawn_line); + else + unlockscr (); + return; +#endif for (i = 0; i < max_ypos_thisframe; i++) { int where; + int i1 = i + min_ypos_for_screen; int line = i + thisframe_y_adjust_real; if (linestate[line] == LINE_UNDECIDED) break; - where = amiga2aspect_line_map[i+min_ypos_for_screen]; - if (where >= gfxvidinfo.height) + where = amiga2aspect_line_map[i1]; + if (where >= gfxvidinfo.height - TD_TOTAL_HEIGHT) break; if (where == -1) continue; - pfield_draw_line (line, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); + pfield_draw_line (line, where, amiga2aspect_line_map[i1 + 1]); } - unlockscr (); + for (i = 0; i < TD_TOTAL_HEIGHT; i++) { + int line = gfxvidinfo.height - TD_TOTAL_HEIGHT + i; + draw_status_line (line); + do_flush_line (line); + } + do_flush_screen (first_drawn_line, last_drawn_line); } @@ -1729,10 +1703,20 @@ void vsync_handle_redraw (int long_frame * done at other times. */ + if (savestate_state == STATE_DOSAVE) { + custom_prepare_savestate (); + savestate_state = STATE_SAVE; + save_state (savestate_filename, "Description!"); + savestate_state = 0; + } else if (savestate_state == STATE_DORESTORE) { + savestate_state = STATE_RESTORE; + uae_reset (); + } + if (quit_program < 0) { quit_program = -quit_program; set_inhibit_frame (IHF_QUIT_PROGRAM); - regs.spcflags |= SPCFLAG_BRK; + set_special (SPCFLAG_BRK); filesys_prepare_reset (); return; } @@ -1818,7 +1802,6 @@ void reset_drawing (void) lores_factor = currprefs.gfx_lores ? 1 : 2; lores_shift = currprefs.gfx_lores ? 0 : 1; - sprite_width = currprefs.gfx_lores ? 16 : 32; /*memset(blitcount, 0, sizeof(blitcount)); blitter debug */ for (i = 0; i < sizeof linestate / sizeof *linestate; i++) @@ -1835,6 +1818,9 @@ void reset_drawing (void) last_redraw_point = 0; + memset (spixels, 0, sizeof spixels); + memset (&spixstate, 0, sizeof spixstate); + init_drawing_frame (); }