From: Toni Wilen Date: Mon, 6 Aug 2012 17:51:10 +0000 (+0300) Subject: 2420b10 X-Git-Tag: 2500~22 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=3089987512a32d506820803bd5bcf97a8557d99c;p=francis%2Fwinuae.git 2420b10 --- diff --git a/blitter.cpp b/blitter.cpp index 2e8d35c0..7f7e02c3 100644 --- a/blitter.cpp +++ b/blitter.cpp @@ -1444,12 +1444,14 @@ void maybe_blit (int hpos, int hack) if (savestate_state) return; - if (dmaen (DMA_BLITTER) && (currprefs.waiting_blits || currprefs.m68k_speed < 0)) { - while (bltstate != BLT_done && dmaen (DMA_BLITTER)) { - x_do_cycles (8 * CYCLE_UNIT); + if (dmaen (DMA_BLITTER)) { + if (currprefs.waiting_blits == 1 || (currprefs.waiting_blits == 2 && blit_last_cycle >= blit_diag[0] && blit_dmacount == blit_diag[0]) || currprefs.m68k_speed < 0) { + while (bltstate != BLT_done && dmaen (DMA_BLITTER)) { + x_do_cycles (8 * CYCLE_UNIT); + } + if (bltstate == BLT_done) + return; } - if (bltstate == BLT_done) - return; } if (warned && dmaen (DMA_BLITTER) && blt_info.got_cycle) { diff --git a/cfgfile.cpp b/cfgfile.cpp index 321e89c5..c5cdde01 100644 --- a/cfgfile.cpp +++ b/cfgfile.cpp @@ -188,6 +188,7 @@ static const TCHAR *cdmodes[] = { _T("disabled"), _T(""), _T("image"), _T("ioctl static const TCHAR *cdconmodes[] = { _T(""), _T("uae"), _T("ide"), _T("scsi"), _T("cdtv"), _T("cd32"), 0 }; static const TCHAR *specialmonitors[] = { _T("none"), _T("autodetect"), _T("a2024"), _T("graffiti"), 0 }; static const TCHAR *rtgtype[] = { _T("ZorroII"), _T("ZorroIII"), 0 }; +static const TCHAR *waitblits[] = { _T("false"), _T("true"), _T("noidleonly"), 0 }; static const TCHAR *obsolete[] = { _T("accuracy"), _T("gfx_opengl"), _T("gfx_32bit_blits"), _T("32bit_blits"), @@ -914,7 +915,7 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type) #endif cfgfile_write_bool (f, _T("immediate_blits"), p->immediate_blits); - cfgfile_write_bool (f, _T("waiting_blits"), p->waiting_blits); + cfgfile_dwrite_str (f, _T("waiting_blits"), waitblits[p->waiting_blits]); cfgfile_write_bool (f, _T("ntsc"), p->ntscmode); cfgfile_write_bool (f, _T("genlock"), p->genlock); cfgfile_dwrite_str (f, _T("monitoremu"), specialmonitors[p->monitoremu]); @@ -1182,9 +1183,14 @@ int cfgfile_strval (const TCHAR *option, const TCHAR *value, const TCHAR *name, if (val == -1) { if (more) return 0; - - write_log (_T("Unknown value ('%s') for option '%s'.\n"), value, option); - return -1; + if (!strcasecmp (value, _T("yes")) || !strcasecmp (value, _T("true"))) { + val = 1; + } else if (!strcasecmp (value, _T("no")) || !strcasecmp (value, _T("false"))) { + val = 0; + } else { + write_log (_T("Unknown value ('%s') for option '%s'.\n"), value, option); + return -1; + } } *location = val; return 1; @@ -2507,7 +2513,6 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH return 1; if (cfgfile_yesno (option, value, _T("immediate_blits"), &p->immediate_blits) - || cfgfile_yesno (option, value, _T("waiting_blits"), &p->waiting_blits) || cfgfile_yesno (option, value, _T("cd32cd"), &p->cs_cd32cd) || cfgfile_yesno (option, value, _T("cd32c2p"), &p->cs_cd32c2p) || cfgfile_yesno (option, value, _T("cd32nvram"), &p->cs_cd32nvram) @@ -2603,6 +2608,7 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH || cfgfile_strval (option, value, _T("collision_level"), &p->collision_level, collmode, 0) || cfgfile_strval (option, value, _T("parallel_matrix_emulation"), &p->parallel_matrix_emulation, epsonprinter, 0) || cfgfile_strval (option, value, _T("monitoremu"), &p->monitoremu, specialmonitors, 0) + || cfgfile_strval (option, value, _T("waiting_blits"), &p->waiting_blits, waitblits, 0) || cfgfile_strboolval (option, value, _T("comp_flushmode"), &p->comp_hardflush, flushmode, 0)) return 1; diff --git a/custom.cpp b/custom.cpp index 0b770e7a..0b7bcc35 100644 --- a/custom.cpp +++ b/custom.cpp @@ -306,6 +306,8 @@ enum copper_states { COP_skip1, COP_strobe_delay1, COP_strobe_delay2, + COP_strobe_delay1x, + COP_strobe_delay2x, COP_strobe_extra, // just to skip current cycle when CPU wrote to COPJMP COP_start_delay }; @@ -590,10 +592,10 @@ static void decide_diw (int hpos) */ int hdiw = hpos >= maxhpos ? maxhpos * 2 + 1 : hpos * 2 + 2; - if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE) && vpos <= get_equ_vblank_endline ()) { + if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE) && vpos <= get_equ_vblank_endline ()) hdiw = diw_hcounter; - hdiw &= 511; - } + /* always mask, bad programs may have set maxhpos = 256 */ + hdiw &= 511; for (;;) { int lhdiw = hdiw; if (last_hdiw > lhdiw) @@ -1354,17 +1356,17 @@ STATIC_INLINE void beginning_of_plane_block (int hpos, int fm) } #endif - update_denise (hpos); - maybe_first_bpl1dat (hpos); - + update_denise (hpos); + maybe_first_bpl1dat (hpos); + + bplcon1t2 = bplcon1t; + bplcon1t = bplcon1; + // writing to BPLCON1 1 cycle after BPL1DAT access will + // not (except first BPL1DAT write) affect the display + // until next display block + if (bplcon1_hpos != hpos || oleft < 0) bplcon1t2 = bplcon1t; - bplcon1t = bplcon1; - // writing to BPLCON1 1 cycle after BPL1DAT access will - // not (except first BPL1DAT write) affect the display - // until next display block - if (bplcon1_hpos != hpos || oleft < 0) - bplcon1t2 = bplcon1t; - compute_toscr_delay (hpos, bplcon1t2); + compute_toscr_delay (hpos, bplcon1t2); } #ifdef SPEEDUP @@ -3494,7 +3496,11 @@ static void COPJMP (int num, int vblank) cop_state.ignore_next = 0; if (!oldstrobe) cop_state.state_prev = cop_state.state; - cop_state.state = vblank ? COP_start_delay : (copper_access ? COP_strobe_delay1 : COP_strobe_extra); + if ((cop_state.state == COP_wait || cop_state.state == COP_stop) && !vblank) { + cop_state.state = COP_strobe_delay1x; + } else { + cop_state.state = vblank ? COP_start_delay : (copper_access ? COP_strobe_delay1 : COP_strobe_extra); + } cop_state.vpos = vpos; cop_state.hpos = current_hpos () & ~1; copper_enabled_thisline = 0; @@ -3956,14 +3962,17 @@ static void BPL2MOD (int hpos, uae_u16 v) */ static void BPLxDAT (int hpos, int num, uae_u16 v) { - decide_line (hpos); - decide_fetch (hpos); + // only BPL0DAT access can do anything visible + if (num == 0 && hpos >= 7) { + decide_line (hpos); + decide_fetch (hpos); + } bplxdat[num] = v; - if (num == 0) { + if (num == 0 && hpos >= 7) { bpl1dat_written = true; bpl1dat_written_at_least_once = true; if (thisline_decision.plfleft < 0) { - thisline_decision.plfleft = hpos; + thisline_decision.plfleft = hpos & ~3; reset_bpl_vars (); compute_delay_offset (); } @@ -4494,7 +4503,7 @@ STATIC_INLINE int copper_cant_read2 (int hpos, int alloc) { if (hpos + 1 >= maxhpos) // first refresh slot return 1; - if ((hpos == maxhpos - 3) && (maxhpos & 1)) { + if ((hpos == maxhpos - 3) && (maxhpos & 1) && alloc >= 0) { if (alloc) alloc_cycle (hpos, CYCLE_COPPER); return -1; @@ -4619,12 +4628,14 @@ static void update_copper (int until_hpos) continue; cop_state.state = COP_skip1; break; + case COP_strobe_extra: - // wait 1 copper cycle doing nothing + // Wait 1 copper cycle doing nothing cop_state.state = COP_strobe_delay1; break; case COP_strobe_delay1: - // first cycle after COPJMP is just like normal first read cycle + // First cycle after COPJMP is just like normal first read cycle + // Cycle is used and needs to be free. if (copper_cant_read (old_hpos, 1)) continue; cop_state.state = COP_strobe_delay2; @@ -4636,22 +4647,46 @@ static void update_copper (int until_hpos) cop_state.ip += 2; break; case COP_strobe_delay2: - // second cycle after COPJMP is like second read cycle except - // there is 0x1FE as a target register - // (following word is still read normally and tossed away) + // Second cycle after COPJMP. This is the strange one. + // This cycle does not need to be free + // But it still gets allocated by copper if it is free = CPU and blitter can't use it. + if (copper_cant_read (old_hpos, 1)) { + alloc_cycle (old_hpos, CYCLE_COPPER); + if (debug_dma) + record_dma (0x1fe, chipmem_wget_indirect (cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER); + } + cop_state.state = COP_read1; + // Next cycle finally reads from new pointer + if (cop_state.strobe == 1) + cop_state.ip = cop1lc; + else + cop_state.ip = cop2lc; + cop_state.strobe = 0; + break; + + case COP_strobe_delay1x: + // First cycle after COPJMP and Copper was waiting. This is the buggy one. + // Cycle can be free and copper won't allocate it. + // If Blitter uses this cycle = Copper's address gets copied blitter DMA pointer.. + cop_state.state = COP_strobe_delay2x; + break; + case COP_strobe_delay2x: + // Second cycle fetches following word and tosses it away. Must be free cycle. if (copper_cant_read (old_hpos, 1)) continue; - cop_state.state = COP_read1; alloc_cycle (old_hpos, CYCLE_COPPER); if (debug_dma) record_dma (0x1fe, chipmem_wget_indirect (cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER); - // next cycle finally reads from new pointer + cop_state.state = COP_read1; + // Next cycle finally reads from new pointer if (cop_state.strobe == 1) cop_state.ip = cop1lc; else cop_state.ip = cop2lc; cop_state.strobe = 0; - break; + break; + + case COP_start_delay: if (copper_cant_read (old_hpos, 1)) continue; @@ -4709,10 +4744,9 @@ static void update_copper (int until_hpos) test_copper_dangerous (reg); if (! copper_enabled_thisline) goto out; // was "dangerous" register -> copper stopped - if (cop_state.ignore_next) { + + if (cop_state.ignore_next) reg = 0x1fe; - cop_state.ignore_next = 0; - } cop_state.last_write = reg; cop_state.last_write_hpos = old_hpos; @@ -4742,9 +4776,10 @@ static void update_copper (int until_hpos) #endif } #ifdef DEBUGGER - if (debug_copper) + if (debug_copper && !cop_state.ignore_next) record_copper (debugip - 4, old_hpos, vpos); #endif + cop_state.ignore_next = 0; } break; @@ -4764,8 +4799,12 @@ static void update_copper (int until_hpos) incrementing vpos and setting c_hpos to 0. Especially the various speedup hacks really assume that vpos remains constant during one line. Hence, this hack: defer the entire decision until the next line if necessary. */ - if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1)) +#endif +#if 0 + if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1)) { + write_log(L"*\n"); break; + } #endif cop_state.state = COP_wait; @@ -4788,35 +4827,42 @@ static void update_copper (int until_hpos) /* fall through */ case COP_wait: - if (copper_cant_read (old_hpos, 0)) - continue; + { + int ch_comp = c_hpos; + if (ch_comp & 1) + ch_comp = 0; + + if (copper_cant_read (old_hpos, 0)) + continue; - hp = c_hpos & (cop_state.saved_i2 & 0xFE); - if (vp == cop_state.vcmp && hp < cop_state.hcmp) - break; - /* Now we know that the comparisons were successful. We might still - have to wait for the blitter though. */ - if ((cop_state.saved_i2 & 0x8000) == 0) { - decide_blitter (old_hpos); - if (bltstate != BLT_done) { - /* We need to wait for the blitter. */ - cop_state.state = COP_bltwait; - copper_enabled_thisline = 0; - unset_special (SPCFLAG_COPPER); - goto out; - } else { - if (debug_dma) - record_dma_event (DMA_EVENT_COPPERWAKE, old_hpos, vp); + hp = ch_comp & (cop_state.saved_i2 & 0xFE); + if (vp == cop_state.vcmp && hp < cop_state.hcmp) + break; + + /* Now we know that the comparisons were successful. We might still + have to wait for the blitter though. */ + if ((cop_state.saved_i2 & 0x8000) == 0) { + decide_blitter (old_hpos); + if (bltstate != BLT_done) { + /* We need to wait for the blitter. */ + cop_state.state = COP_bltwait; + copper_enabled_thisline = 0; + unset_special (SPCFLAG_COPPER); + goto out; + } else { + if (debug_dma) + record_dma_event (DMA_EVENT_COPPERWAKE, old_hpos, vp); + } } - } -#ifdef DEBUGGER - if (debug_copper) - record_copper (cop_state.ip - 4, old_hpos, vpos); -#endif + #ifdef DEBUGGER + if (debug_copper) + record_copper (cop_state.ip - 4, old_hpos, vpos); + #endif - cop_state.state = COP_read1; + cop_state.state = COP_read1; + } break; case COP_skip1: @@ -4825,6 +4871,7 @@ static void update_copper (int until_hpos) if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1)) break; + if (copper_cant_read (old_hpos, 0)) continue; @@ -7796,6 +7843,7 @@ void check_prefs_changed_custom (void) if (inputdevice_config_change_test ()) inputdevice_copyconfig (&changed_prefs, &currprefs); currprefs.immediate_blits = changed_prefs.immediate_blits; + currprefs.waiting_blits = changed_prefs.waiting_blits; currprefs.collision_level = changed_prefs.collision_level; currprefs.cs_ciaatod = changed_prefs.cs_ciaatod; diff --git a/drawing - Copy.cpp b/drawing - Copy.cpp new file mode 100644 index 00000000..4c2def42 --- /dev/null +++ b/drawing - Copy.cpp @@ -0,0 +1,3119 @@ +//#define XLINECHECK + +/* +* UAE - The Un*x Amiga Emulator +* +* Screen drawing functions +* +* Copyright 1995-2000 Bernd Schmidt +* Copyright 1995 Alessandro Bissacco +* Copyright 2000-2008 Toni Wilen +*/ + +/* There are a couple of concepts of "coordinates" in this file. +- DIW coordinates +- DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2) +- Pixel coordinates +* in the Amiga's resolution as determined by BPLCON0 ("Amiga coordinates") +* in the window resolution as determined by the preferences ("window coordinates"). +* in the window resolution, and with the origin being the topmost left corner of +the window ("native coordinates") +One note about window coordinates. The visible area depends on the width of the +window, and the centering code. The first visible horizontal window coordinate is +often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead. + +One important thing to remember: DIW coordinates are in the lowest possible +resolution. + +To prevent extremely bad things (think pixels cut in half by window borders) from +happening, all ports should restrict window widths to be multiples of 16 pixels. */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "xwin.h" +#include "autoconf.h" +#include "gui.h" +#include "picasso96.h" +#include "drawing.h" +#include "savestate.h" +#include "statusline.h" +#include "inputdevice.h" +#include "debug.h" + +extern bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*); + +extern int sprite_buffer_res; +int lores_factor, lores_shift; + +int debug_bpl_mask = 0xff, debug_bpl_mask_one; + +static void lores_reset (void) +{ + lores_factor = currprefs.gfx_resolution ? 2 : 1; + lores_shift = currprefs.gfx_resolution; + if (doublescan > 0) { + if (lores_shift < 2) + lores_shift++; + lores_factor = 2; + } + sprite_buffer_res = currprefs.gfx_resolution; + if (doublescan > 0 && sprite_buffer_res < RES_SUPERHIRES) + sprite_buffer_res++; +} + +bool aga_mode; /* mirror of chipset_mask & CSMASK_AGA */ +bool direct_rgb; + +/* The shift factor to apply when converting between Amiga coordinates and window +coordinates. Zero if the resolution is the same, positive if window coordinates +have a higher resolution (i.e. we're stretching the image), negative if window +coordinates have a lower resolution (i.e. we're shrinking the image). */ +static int res_shift; + +static int linedbl, linedbld; + +int interlace_seen = 0; +#define AUTO_LORES_FRAMES 10 +static int can_use_lores = 0, frame_res, frame_res_lace, last_max_ypos; +static uae_u16 bplcon0_store, bplcon3_store; + +/* 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 const 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 +* dependent code. */ + +struct vidbuf_description gfxvidinfo; + +/* OCS/ECS color lookup table. */ +xcolnr xcolors[4096]; + +struct spritepixelsbuf { + uae_u8 attach; + uae_u8 stdata; + uae_u16 data; +}; +static struct spritepixelsbuf spritepixels[MAX_PIXELS_PER_LINE]; +static int sprite_first_x, sprite_last_x; + +#ifdef AGA +/* AGA mode color lookup tables */ +unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256]; +static int dblpf_ind1_aga[256], dblpf_ind2_aga[256]; +#else +static uae_u8 spriteagadpfpixels[1]; +static int dblpf_ind1_aga[1], dblpf_ind2_aga[1]; +#endif +int xredcolor_s, xredcolor_b, xredcolor_m; +int xgreencolor_s, xgreencolor_b, xgreencolor_m; +int xbluecolor_s, xbluecolor_b, xbluecolor_m; + +struct color_entry colors_for_drawing; + +/* The size of these arrays is pretty arbitrary; it was chosen to be "more +than enough". The coordinates used for indexing into these arrays are +almost, but not quite, Amiga coordinates (there's a constant offset). */ +union { + /* Let's try to align this thing. */ + double uupzuq; + long int cruxmedo; + uae_u8 apixels[MAX_PIXELS_PER_LINE * 2]; + uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u16)]; + uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u32)]; +} pixdata; + +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT +uae_u16 *spixels; +#else +uae_u16 spixels[2 * MAX_SPR_PIXELS]; +#endif + +/* Eight bits for every pixel. */ +union sps_union spixstate; + +static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2]; +static uae_u8 *real_bplpt[8]; + +static uae_u8 all_ones[MAX_PIXELS_PER_LINE]; +static uae_u8 all_zeros[MAX_PIXELS_PER_LINE]; + +uae_u8 *xlinebuffer; + +static int *amiga2aspect_line_map, *native2amiga_line_map; +static uae_u8 *row_map[MAX_VIDHEIGHT + 1]; +static uae_u8 row_tmp[MAX_PIXELS_PER_LINE * 32 / 8]; +static int max_drawn_amiga_line; + +/* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */ +typedef void (*line_draw_func)(int, int, bool); + +#define LINE_UNDECIDED 1 +#define LINE_DECIDED 2 +#define LINE_DECIDED_DOUBLE 3 +#define LINE_AS_PREVIOUS 4 +#define LINE_BLACK 5 +#define LINE_REMEMBERED_AS_BLACK 6 +#define LINE_DONE 7 +#define LINE_DONE_AS_PREVIOUS 8 +#define LINE_REMEMBERED_AS_PREVIOUS 9 + +static uae_u8 linestate[(MAXVPOS + 2) * 2 + 1]; + +uae_u8 line_data[(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2]; + +/* Centering variables. */ +static int min_diwstart, max_diwstop; +/* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible +area, VISIBLE_RIGHT_BORDER the right border. These are in window coordinates. */ +int visible_left_border, visible_right_border; +/* Pixels outside of visible_start and visible_stop are always black */ +static int visible_left_start, visible_right_stop; +static int visible_top_start, visible_bottom_stop; + +static int linetoscr_x_adjust_bytes; +static int thisframe_y_adjust; +static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen; +static int extra_y_adjust; +int thisframe_first_drawn_line, thisframe_last_drawn_line; + +/* A frame counter that forces a redraw after at least one skipped frame in +interlace mode. */ +static int last_redraw_point; + +#define MAX_STOP 30000 +static int first_drawn_line, last_drawn_line; +static int first_block_line, last_block_line; + +#define NO_BLOCK -3 + +/* 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, bpldualpf2of, bplplanecnt, ecsshres, issprites; +static int bplres; +static int plf1pri, plf2pri, bplxor; +static uae_u32 plf_sprite_mask; +static int sbasecol[2] = { 16, 16 }; +static bool brdsprt, brdblank, brdblank_changed; +static int hposblank; + +bool picasso_requested_on; +bool picasso_on; + +uae_sem_t gui_sem; +int inhibit_frame; + +int framecnt = 0; +static int frame_redraw_necessary; +static int picasso_redraw_necessary; + +#ifdef XLINECHECK +static void xlinecheck (unsigned int start, unsigned int end) +{ + unsigned int xstart = (unsigned int)xlinebuffer + start * gfxvidinfo.drawbuffer.pixbytes; + unsigned int xend = (unsigned int)xlinebuffer + end * gfxvidinfo.drawbuffer.pixbytes; + unsigned int end1 = (unsigned int)gfxvidinfo.drawbuffer.bufmem + gfxvidinfo.drawbuffer.rowbytes * gfxvidinfo.drawbuffer.height; + int min = linetoscr_x_adjust_bytes / gfxvidinfo.drawbuffer.pixbytes; + int ok = 1; + + if (xstart >= gfxvidinfo.drawbuffer.emergmem && xstart < gfxvidinfo.drawbuffer.emergmem + 4096 * gfxvidinfo.drawbuffer.pixbytes && + xend >= gfxvidinfo.drawbuffer.emergmem && xend < gfxvidinfo.drawbuffer.emergmem + 4096 * gfxvidinfo.drawbuffer.pixbytes) + return; + + if (xstart < (unsigned int)gfxvidinfo.drawbuffer.bufmem || xend < (unsigned int)gfxvidinfo.drawbuffer.bufmem) + ok = 0; + if (xend > end1 || xstart >= end1) + ok = 0; + xstart -= (unsigned int)gfxvidinfo.drawbuffer.bufmem; + xend -= (unsigned int)gfxvidinfo.drawbuffer.bufmem; + if ((xstart % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes) + ok = 0; + if ((xend % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes) + ok = 0; + if (xstart >= xend) + ok = 0; + if (xend - xstart > gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes) + ok = 0; + + if (!ok) { + write_log (_T("*** %d-%d (%dx%dx%d %d) %p\n"), + start - min, end - min, gfxvidinfo.drawbuffer.width, gfxvidinfo.drawbuffer.height, + gfxvidinfo.drawbuffer.pixbytes, gfxvidinfo.drawbuffer.rowbytes, + xlinebuffer); + } +} +#else +#define xlinecheck +#endif + + +STATIC_INLINE void count_frame (void) +{ + framecnt++; + if (framecnt >= currprefs.gfx_framerate) + framecnt = 0; + if (inhibit_frame) + framecnt = 1; +} + +STATIC_INLINE int xshift (int x, int shift) +{ + if (shift < 0) + return x >> (-shift); + else + return x << shift; +} + +int coord_native_to_amiga_x (int x) +{ + x += visible_left_border; + x = xshift (x, 1 - lores_shift); + return x + 2 * DISPLAY_LEFT_SHIFT - 2 * DIW_DDF_OFFSET; +} + +int coord_native_to_amiga_y (int y) +{ + return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline; +} + +STATIC_INLINE int res_shift_from_window (int x) +{ + if (res_shift >= 0) + return x >> res_shift; + return x << -res_shift; +} + +STATIC_INLINE int res_shift_from_amiga (int x) +{ + if (res_shift >= 0) + return x >> res_shift; + return x << -res_shift; +} + +void notice_screen_contents_lost (void) +{ + picasso_redraw_necessary = 1; + frame_redraw_necessary = 2; +} + +bool isnativevidbuf (void) +{ + if (gfxvidinfo.outbuffer == &gfxvidinfo.drawbuffer) + return true; + return gfxvidinfo.outbuffer->nativepositioning; +} + +extern int plffirstline_total, plflastline_total; +extern int first_planes_vpos, last_planes_vpos; +extern int diwfirstword_total, diwlastword_total; +extern int ddffirstword_total, ddflastword_total; +extern int firstword_bplcon1; +extern int lof_store; + +#define MIN_DISPLAY_W 256 +#define MIN_DISPLAY_H 192 +#define MAX_DISPLAY_W 362 +#define MAX_DISPLAY_H 283 + +static int gclow, gcloh, gclox, gcloy; + +void get_custom_topedge (int *x, int *y) +{ + if (isnativevidbuf ()) { + *x = visible_left_border + (DISPLAY_LEFT_SHIFT << currprefs.gfx_resolution); + *y = minfirstline << currprefs.gfx_vresolution; + } else { + *x = 0; + *y = 0; + } +} + +static void reset_custom_limits (void) +{ + gclow = gcloh = gclox = gcloy = 0; +} + +void set_custom_limits (int w, int h, int dx, int dy) +{ + int vls = visible_left_start; + int vrs = visible_right_stop; + int vts = visible_top_start; + int vbs = visible_bottom_stop; + + if (w <= 0 || dx < 0) { + visible_left_start = 0; + visible_right_stop = MAX_STOP; + } else { + visible_left_start = visible_left_border + dx; + visible_right_stop = visible_left_start + w; + } + if (h <= 0 || dy < 0) { + visible_top_start = 0; + visible_bottom_stop = MAX_STOP; + } else { + visible_top_start = min_ypos_for_screen + dy; + visible_bottom_stop = visible_top_start + h; + } + if (vls != visible_left_start || vrs != visible_right_stop || + vts != visible_top_start || vbs != visible_bottom_stop) + notice_screen_contents_lost (); +} + +int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy) +{ + int w, h, dx, dy, y1, y2, dbl1, dbl2; + int ret = 0; + + if (!pw || !ph || !pdx || !pdy) { + reset_custom_limits (); + return 0; + } + + if (!isnativevidbuf ()) { + *pw = gfxvidinfo.outbuffer->outwidth; + *ph = gfxvidinfo.outbuffer->outheight; + *pdx = 0; + *pdy = 0; + return 1; + } + + *pw = gclow; + *ph = gcloh; + *pdx = gclox; + *pdy = gcloy; + + if (gclow > 0 && gcloh > 0) + ret = -1; + + if (interlace_seen) { + // interlace = only use long frames + if (!lof_store) + return ret; + /* program may have set last visible line as last possible line (CD32 boot screen) */ + if (last_planes_vpos < maxvpos) + last_planes_vpos++; + if (plflastline_total < maxvpos) + plflastline_total++; + } + + if (plflastline_total < 4) + plflastline_total = last_planes_vpos; + + ddffirstword_total = coord_hw_to_window_x (ddffirstword_total * 2 + DIW_DDF_OFFSET); + ddflastword_total = coord_hw_to_window_x (ddflastword_total * 2 + DIW_DDF_OFFSET); + + if (doublescan <= 0 && !programmedmode) { + int min = coord_diw_to_window_x (92); + int max = coord_diw_to_window_x (460); + if (diwfirstword_total < min) + diwfirstword_total = min; + if (diwlastword_total > max) + diwlastword_total = max; + if (ddffirstword_total < min) + ddffirstword_total = min; + if (ddflastword_total > max) + ddflastword_total = max; + if (0 && !(currprefs.chipset_mask & CSMASK_AGA)) { + if (ddffirstword_total > diwfirstword_total) + diwfirstword_total = ddffirstword_total; + if (ddflastword_total < diwlastword_total) + diwlastword_total = ddflastword_total; + } + } + + w = diwlastword_total - diwfirstword_total; + dx = diwfirstword_total - visible_left_border; + + y2 = plflastline_total; + if (y2 > last_planes_vpos) + y2 = last_planes_vpos; + y1 = plffirstline_total; + if (first_planes_vpos > y1) + y1 = first_planes_vpos; + if (minfirstline > y1) + y1 = minfirstline; + + dbl2 = dbl1 = currprefs.gfx_vresolution; + if (doublescan > 0 && interlace_seen <= 0) { + dbl1--; + dbl2--; + } + + h = y2 - y1; + dy = y1 - minfirstline; + + if (first_planes_vpos == 0) { + // no planes enabled during frame + if (ret < 0) + return 1; + h = currprefs.ntscmode ? 200 : 240; + w = 320 << currprefs.gfx_resolution; + dy = 36 / 2; + dx = 58; + } + + if (dx < 0) + dx = 0; + + dy = xshift (dy, dbl2); + h = xshift (h, dbl1); + + if (w == 0 || h == 0) + return 0; + + if (doublescan <= 0 && !programmedmode) { + if ((w >> currprefs.gfx_resolution) < MIN_DISPLAY_W) { + dx += (w - (MIN_DISPLAY_W << currprefs.gfx_resolution)) / 2; + w = MIN_DISPLAY_W << currprefs.gfx_resolution; + } + if ((h >> dbl1) < MIN_DISPLAY_H) { + dy += (h - (MIN_DISPLAY_H << dbl1)) / 2; + h = MIN_DISPLAY_H << dbl1; + } + if ((w >> currprefs.gfx_resolution) > MAX_DISPLAY_W) { + dx += (w - (MAX_DISPLAY_W << currprefs.gfx_resolution)) / 2; + w = MAX_DISPLAY_W << currprefs.gfx_resolution; + } + if ((h >> dbl1) > MAX_DISPLAY_H) { + dy += (h - (MAX_DISPLAY_H << dbl1)) / 2; + h = MAX_DISPLAY_H << dbl1; + } + } + + if (gclow == w && gcloh == h && gclox == dx && gcloy == dy) + return ret; + + if (w <= 0 || h <= 0 || dx < 0 || dy < 0) + return ret; + if (doublescan <= 0 && !programmedmode) { + if (dx > gfxvidinfo.outbuffer->inwidth / 3) + return ret; + if (dy > gfxvidinfo.outbuffer->inheight / 3) + return ret; + } + + gclow = w; + gcloh = h; + gclox = dx; + gcloy = dy; + *pw = w; + *ph = h; + *pdx = dx; + *pdy = dy; +#if 1 + write_log (_T("Display Size: %dx%d Offset: %dx%d\n"), w, h, dx, dy); + write_log (_T("First: %d Last: %d MinV: %d MaxV: %d Min: %d\n"), + plffirstline_total, plflastline_total, + first_planes_vpos, last_planes_vpos, minfirstline); +#endif + return 1; +} + +void get_custom_mouse_limits (int *pw, int *ph, int *pdx, int *pdy, int dbl) +{ + int delay1, delay2; + int w, h, dx, dy, dbl1, dbl2, y1, y2; + + w = diwlastword_total - diwfirstword_total; + dx = diwfirstword_total - visible_left_border; + + y2 = plflastline_total; + if (y2 > last_planes_vpos) + y2 = last_planes_vpos; + y1 = plffirstline_total; + if (first_planes_vpos > y1) + y1 = first_planes_vpos; + if (minfirstline > y1) + y1 = minfirstline; + + h = y2 - y1; + dy = y1 - minfirstline; + + if (*pw > 0) + w = *pw; + + w = xshift (w, res_shift); + + if (*ph > 0) + h = *ph; + + delay1 = (firstword_bplcon1 & 0x0f) | ((firstword_bplcon1 & 0x0c00) >> 6); + delay2 = ((firstword_bplcon1 >> 4) & 0x0f) | (((firstword_bplcon1 >> 4) & 0x0c00) >> 6); +// if (delay1 == delay2) +// dx += delay1; + + dx = xshift (dx, res_shift); + + dbl2 = dbl1 = currprefs.gfx_vresolution; + if ((doublescan > 0 || interlace_seen > 0) && !dbl) { + dbl1--; + dbl2--; + } + if (interlace_seen > 0) + dbl2++; + if (interlace_seen <= 0 && dbl) + dbl2--; + h = xshift (h, dbl1); + dy = xshift (dy, dbl2); + + if (w < 1) + w = 1; + if (h < 1) + h = 1; + if (dx < 0) + dx = 0; + if (dy < 0) + dy = 0; + *pw = w; *ph = h; + *pdx = dx; *pdy = dy; +} + +static struct decision *dp_for_drawing; +static struct draw_info *dip_for_drawing; + +/* Record DIW of the current line for use by centering code. */ +void record_diw_line (int plfstrt, int first, int last) +{ + if (last > max_diwstop) + max_diwstop = last; + if (first < min_diwstart) { + min_diwstart = first; + /* + if (plfstrt * 2 > min_diwstart) + min_diwstart = plfstrt * 2; + */ + } +} + +/* +* Screen update macros/functions +*/ + +/* The important positions in the line: where do we start drawing the left border, +where do we start drawing the playfield, where do we start drawing the right border. +All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER). +PLAYFIELD_START and PLAYFIELD_END are in window coordinates. */ +static int playfield_start, playfield_end; +static int real_playfield_start, real_playfield_end; +static int linetoscr_diw_start, linetoscr_diw_end; +static int native_ddf_left, native_ddf_right; + +static int pixels_offset; +static int src_pixel, ham_src_pixel; +/* How many pixels in window coordinates which are to the left of the left border. */ +static int unpainted; +static int seen_sprites; + +/* Initialize the variables necessary for drawing a line. +* This involves setting up start/stop positions and display window +* borders. */ +static void pfield_init_linetoscr (void) +{ + /* First, get data fetch start/stop in DIW coordinates. */ + 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. */ + native_ddf_left = coord_hw_to_window_x (ddf_left); + native_ddf_right = coord_hw_to_window_x (ddf_right); + + linetoscr_diw_start = dp_for_drawing->diwfirstword; + linetoscr_diw_end = dp_for_drawing->diwlastword; + + res_shift = lores_shift - bplres; + + if (dip_for_drawing->nr_sprites == 0) { + if (linetoscr_diw_start < native_ddf_left) + linetoscr_diw_start = native_ddf_left; + if (linetoscr_diw_end > native_ddf_right) + linetoscr_diw_end = native_ddf_right; + } + + /* Perverse cases happen. */ + if (linetoscr_diw_end < linetoscr_diw_start) + linetoscr_diw_end = linetoscr_diw_start; + + playfield_start = linetoscr_diw_start; + playfield_end = linetoscr_diw_end; + + unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start; + ham_src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left); + unpainted = res_shift_from_window (unpainted); + + if (playfield_start < visible_left_border) + playfield_start = visible_left_border; + if (playfield_start > visible_right_border) + playfield_start = visible_right_border; + if (playfield_end < visible_left_border) + playfield_end = visible_left_border; + if (playfield_end > visible_right_border) + playfield_end = visible_right_border; + + real_playfield_end = playfield_end; + real_playfield_start = playfield_start; +#ifdef AGA + if (brdsprt && dip_for_drawing->nr_sprites) { + int min = visible_right_border, max = visible_left_border, i; + for (i = 0; i < dip_for_drawing->nr_sprites; i++) { + int x; + x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].pos; + if (x < min) + min = x; + x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].max; + if (x > max) + max = x; + } + min = coord_hw_to_window_x (min >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); + max = coord_hw_to_window_x (max >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); + if (min < playfield_start) + playfield_start = min; + if (playfield_start < visible_left_border) + playfield_start = visible_left_border; + if (max > playfield_end) + playfield_end = max; + if (playfield_end > visible_right_border) + playfield_end = visible_right_border; + } +#endif + + if (sprite_first_x < sprite_last_x) { + if (sprite_first_x < 0) + sprite_first_x = 0; + if (sprite_last_x >= MAX_PIXELS_PER_LINE - 1) + sprite_last_x = MAX_PIXELS_PER_LINE - 2; + if (sprite_first_x < sprite_last_x) + memset (spritepixels + sprite_first_x, 0, sizeof (struct spritepixelsbuf) * (sprite_last_x - sprite_first_x + 1)); + } + sprite_last_x = 0; + sprite_first_x = MAX_PIXELS_PER_LINE - 1; + + /* Now, compute some offsets. */ + ddf_left -= DISPLAY_LEFT_SHIFT; + pixels_offset = MAX_PIXELS_PER_LINE - (ddf_left << bplres); + ddf_left <<= bplres; + src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left); + + seen_sprites = 0; + if (dip_for_drawing->nr_sprites == 0) + return; + seen_sprites = 1; + /* Must clear parts of apixels. */ + 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 + 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 + MAX_PIXELS_PER_LINE + pos, 0, size); + } +} + +STATIC_INLINE uae_u16 merge_2pixel16 (uae_u16 p1, uae_u16 p2) +{ + uae_u16 v = ((((p1 >> xredcolor_s) & xredcolor_m) + ((p2 >> xredcolor_s) & xredcolor_m)) / 2) << xredcolor_s; + v |= ((((p1 >> xbluecolor_s) & xbluecolor_m) + ((p2 >> xbluecolor_s) & xbluecolor_m)) / 2) << xbluecolor_s; + v |= ((((p1 >> xgreencolor_s) & xgreencolor_m) + ((p2 >> xgreencolor_s) & xgreencolor_m)) / 2) << xgreencolor_s; + return v; +} +STATIC_INLINE uae_u32 merge_2pixel32 (uae_u32 p1, uae_u32 p2) +{ + uae_u32 v = ((((p1 >> 16) & 0xff) + ((p2 >> 16) & 0xff)) / 2) << 16; + v |= ((((p1 >> 8) & 0xff) + ((p2 >> 8) & 0xff)) / 2) << 8; + v |= ((((p1 >> 0) & 0xff) + ((p2 >> 0) & 0xff)) / 2) << 0; + return v; +} + +STATIC_INLINE xcolnr getbgc (bool blank) +{ +#if 0 + if (blank) + return xcolors[0x088]; + else if (hposblank == 1) + return xcolors[0xf00]; + else if (hposblank == 2) + return xcolors[0x0f0]; + else if (hposblank == 3) + return xcolors[0x00f]; + else if (brdblank) + return xcolors[0x880]; + return xcolors[0xf0f]; +#endif + return (blank || brdblank || hposblank) ? 0 : colors_for_drawing.acolors[0]; +} + +STATIC_INLINE void fill_line_16 (uae_u8 *buf, int start, int stop, bool blank) +{ + uae_u16 *b = (uae_u16 *)buf; + unsigned int i; + unsigned int rem = 0; + xcolnr col = getbgc (blank); + if (((long)&b[start]) & 1) + b[start++] = (uae_u16) col; + if (start >= stop) + return; + if (((long)&b[stop]) & 1) { + rem++; + stop--; + } + for (i = start; i < stop; i += 2) { + uae_u32 *b2 = (uae_u32 *)&b[i]; + *b2 = col; + } + if (rem) + b[stop] = (uae_u16)col; +} + +STATIC_INLINE void fill_line_32 (uae_u8 *buf, int start, int stop, bool blank) +{ + uae_u32 *b = (uae_u32 *)buf; + unsigned int i; + xcolnr col = getbgc (blank); + for (i = start; i < stop; i++) + b[i] = col; +} +static void pfield_do_fill_line2 (int start, int stop, bool blank) +{ + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: fill_line_16 (xlinebuffer, start, stop, blank); break; + case 4: fill_line_32 (xlinebuffer, start, stop, blank); break; + } +} +static void pfield_do_fill_line (int start, int stop, bool blank) +{ + xlinecheck(start, stop); + if (!blank) { + if (start < visible_left_start) { + pfield_do_fill_line2 (start, visible_left_start, true); + start = visible_left_start; + } + if (stop > visible_right_stop) { + pfield_do_fill_line2 (start, visible_right_stop, false); + blank = true; + start = visible_right_stop; + } + } + pfield_do_fill_line2 (start, stop, blank); +} + + +STATIC_INLINE void fill_line2 (int startpos, int len) +{ + int shift; + int nints, nrem; + int *start; + xcolnr val; + + shift = 0; + if (gfxvidinfo.drawbuffer.pixbytes == 2) + shift = 1; + if (gfxvidinfo.drawbuffer.pixbytes == 4) + shift = 2; + + nints = len >> (2 - shift); + nrem = nints & 7; + nints &= ~7; + start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift)); + val = getbgc (false); + for (; nints > 0; nints -= 8, start += 8) { + *start = val; + *(start+1) = val; + *(start+2) = val; + *(start+3) = val; + *(start+4) = val; + *(start+5) = val; + *(start+6) = val; + *(start+7) = val; + } + + switch (nrem) { + case 7: + *start++ = val; + case 6: + *start++ = val; + case 5: + *start++ = val; + case 4: + *start++ = val; + case 3: + *start++ = val; + case 2: + *start++ = val; + case 1: + *start = val; + } +} + +static void fill_line (void) +{ + int hs = coord_hw_to_window_x (hsyncstartpos * 2); + if (hs >= gfxvidinfo.drawbuffer.inwidth || hposblank) { + hposblank = 3; + fill_line2 (visible_left_border, gfxvidinfo.drawbuffer.inwidth); + } else { + fill_line2 (visible_left_border, hs); + hposblank = 2; + fill_line2 (visible_left_border + hs, gfxvidinfo.drawbuffer.inwidth); + } +} + +#define SPRITE_DEBUG 0 +STATIC_INLINE uae_u8 render_sprites (int pos, int dualpf, uae_u8 apixel, int aga) +{ + struct spritepixelsbuf *spb = &spritepixels[pos]; + unsigned int v = spb->data; + int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; + int maskshift, plfmask; + + /* 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[apixel]; + plfmask = (plf_sprite_mask >> maskshift) >> maskshift; + v &= ~plfmask; + if (v != 0 || SPRITE_DEBUG) { + 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 SPRITE_DEBUG > 0 + v ^= 8; +#endif + if (spb->attach && (spb->stdata & (3 << offs))) { + col = v; + if (aga) + col += sbasecol[1]; + else + col += 16; + } else { + /* 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 { + col += 16; + } + col += offs * 2; + } + + return col; + } + + return 0; +} + +#include "linetoscr.cpp" + +#define LTPARMS src_pixel, start, stop + +#ifdef ECS_DENISE +/* ECS SuperHires special cases */ + +#define PUTBPIX(x) buf[dpix] = (x); + +STATIC_INLINE uae_u32 shsprite (int dpix, uae_u32 spix_val, uae_u32 v, int spr) +{ + uae_u8 sprcol; + uae_u16 scol; + if (!spr) + return v; + sprcol = render_sprites (dpix, 0, spix_val, 0); + if (!sprcol) + return v; + /* good enough for now.. */ + scol = colors_for_drawing.color_regs_ecs[sprcol] & 0xccc; + scol |= scol >> 2; + return xcolors[scol]; +} + +static int NOINLINE linetoscr_16_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u16 *buf = (uae_u16 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u16 spix_val1, spix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr)); + dpix++; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val2, xcolors[v], spr)); + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_32_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u32 *buf = (uae_u32 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u32 spix_val1, spix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr)); + dpix++; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val2, xcolors[v], spr)); + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_32_shrink1_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u32 *buf = (uae_u32 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u32 spix_val1, spix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr)); + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_32_shrink1f_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u32 *buf = (uae_u32 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u32 spix_val1, spix_val2, dpix_val1, dpix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel32 (dpix_val1, dpix_val2), spr)); + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_16_shrink1_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u16 *buf = (uae_u16 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u16 spix_val1, spix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr)); + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_16_shrink1f_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u16 *buf = (uae_u16 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u16 spix_val1, spix_val2, dpix_val1, dpix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel16 (dpix_val1, dpix_val2), spr)); + dpix++; + } + return spix; +} + + + +static int NOINLINE linetoscr_32_shrink2_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u32 *buf = (uae_u32 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u32 spix_val1, spix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr)); + spix+=2; + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_32_shrink2f_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u32 *buf = (uae_u32 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u32 spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2); + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2); + PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel32 (dpix_val3, dpix_val4), spr)); + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_16_shrink2_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u16 *buf = (uae_u16 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u16 spix_val1, spix_val2; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr)); + spix+=2; + dpix++; + } + return spix; +} +static int NOINLINE linetoscr_16_shrink2f_sh (int spix, int dpix, int stoppos, int spr) +{ + uae_u16 *buf = (uae_u16 *) xlinebuffer; + + while (dpix < stoppos) { + uae_u16 spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4; + uae_u16 v; + int off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2); + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2); + PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel16 (dpix_val3, dpix_val4), spr)); + dpix++; + } + return spix; +} +#endif + +static void pfield_do_linetoscr (int start, int stop, bool blank) +{ + xlinecheck(start, stop); + if (issprites && (currprefs.chipset_mask & CSMASK_AGA)) { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_aga_spr (LTPARMS); break; + } + } else if (res_shift == 2) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch2_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch2_aga_spr (LTPARMS); break; + } + } else if (res_shift == 1) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch1_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch1_aga_spr (LTPARMS); break; + } + } else if (res_shift == -1) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1f_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1f_aga_spr (LTPARMS); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1_aga_spr (LTPARMS); break; + } + } + } else if (res_shift == -2) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink2f_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink2f_aga_spr (LTPARMS); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink2_aga_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink2_aga_spr (LTPARMS); break; + } + } + } + } else +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_aga (LTPARMS); break; + } + } else if (res_shift == 2) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch2_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch2_aga (LTPARMS); break; + } + } else if (res_shift == 1) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch1_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch1_aga (LTPARMS); break; + } + } else if (res_shift == -1) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1f_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1f_aga (LTPARMS); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1_aga (LTPARMS); break; + } + } + } else if (res_shift == -2) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink2f_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink2f_aga (LTPARMS); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink2_aga (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink2_aga (LTPARMS); break; + } + } + } + } else +#endif +#ifdef ECS_DENISE + if (ecsshres) { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_sh (LTPARMS, issprites); break; + case 4: src_pixel = linetoscr_32_sh (LTPARMS, issprites); break; + } + } else if (res_shift == -1) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1f_sh (LTPARMS, issprites); break; + case 4: src_pixel = linetoscr_32_shrink1f_sh (LTPARMS, issprites); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1_sh (LTPARMS, issprites); break; + case 4: src_pixel = linetoscr_32_shrink1_sh (LTPARMS, issprites); break; + } + } + } else if (res_shift == -2) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink2f_sh (LTPARMS, issprites); break; + case 4: src_pixel = linetoscr_32_shrink2f_sh (LTPARMS, issprites); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink2_sh (LTPARMS, issprites); break; + case 4: src_pixel = linetoscr_32_shrink2_sh (LTPARMS, issprites); break; + } + } + } + } else +#endif + if (issprites) { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_spr (LTPARMS); break; + } + } else if (res_shift == 2) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch2_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch2_spr (LTPARMS); break; + } + } else if (res_shift == 1) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch1_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch1_spr (LTPARMS); break; + } + } else if (res_shift == -1) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1f_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1f_spr (LTPARMS); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1_spr (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1_spr (LTPARMS); break; + } + } + } + } else { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16 (LTPARMS); break; + case 4: src_pixel = linetoscr_32 (LTPARMS); break; + } + } else if (res_shift == 2) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch2 (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch2 (LTPARMS); break; + } + } else if (res_shift == 1) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_stretch1 (LTPARMS); break; + case 4: src_pixel = linetoscr_32_stretch1 (LTPARMS); break; + } + } else if (res_shift == -1) { + if (currprefs.gfx_lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1f (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1f (LTPARMS); break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: src_pixel = linetoscr_16_shrink1 (LTPARMS); break; + case 4: src_pixel = linetoscr_32_shrink1 (LTPARMS); break; + } + } + } + } + +} + +static void dummy_worker (int start, int stop, bool blank) +{ +} + +static int ham_decode_pixel; +static unsigned int ham_lastcolor; + +/* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER), + * but don't draw anything in. This is done to prepare HAM_LASTCOLOR for later, + * when decode_ham runs. + * + */ +static void init_ham_decoding (void) +{ + int unpainted_amiga = unpainted; + + ham_decode_pixel = ham_src_pixel; + ham_lastcolor = color_reg_get (&colors_for_drawing, 0); + + if (!bplham) { + if (unpainted_amiga > 0) { + int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1]; +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor]; + else +#endif + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; + } +#ifdef AGA + } else if (currprefs.chipset_mask & CSMASK_AGA) { + if (bplplanecnt >= 7) { /* AGA mode HAM8 */ + while (unpainted_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor; + switch (pv & 0x3) + { + case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break; + case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; + case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; + case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; + } + } + } else { /* AGA mode HAM6 */ + while (unpainted_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor; + switch (pv & 0x30) + { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break; + case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; + case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; + case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; + } + } + } +#endif + } else { + /* OCS/ECS mode HAM6 */ + while (unpainted_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel++]; + switch (pv & 0x30) + { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break; + case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; + case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; + case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; + } + } + } +} + +static void decode_ham (int pix, int stoppos, bool blank) +{ + int todraw_amiga = res_shift_from_window (stoppos - pix); + + if (!bplham) { + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor]; + else +#endif + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; + + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } +#ifdef AGA + } else if (currprefs.chipset_mask & CSMASK_AGA) { + if (bplplanecnt >= 7) { /* AGA mode HAM8 */ + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel] ^ bplxor; + switch (pv & 0x3) + { + case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break; + case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; + case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; + case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } else { /* AGA mode HAM6 */ + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel] ^ bplxor; + switch (pv & 0x30) + { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break; + case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; + case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; + case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } +#endif + } else { + /* OCS/ECS mode HAM6 */ + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; + switch (pv & 0x30) + { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break; + case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; + case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; + case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } +} + +static void gen_pfield_tables (void) +{ + int i; + + for (i = 0; i < 256; i++) { + int plane1 = ((i >> 0) & 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; + dblpf_2nd2[i] = plane2 != 0; + +#ifdef AGA + dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1; + dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2; +#endif + + 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); + + sprite_offs[i] = (i & 15) ? 0 : 2; + + clxtab[i] = ((((i & 3) && (i & 12)) << 9) + | (((i & 3) && (i & 48)) << 10) + | (((i & 3) && (i & 192)) << 11) + | (((i & 12) && (i & 48)) << 12) + | (((i & 12) && (i & 192)) << 13) + | (((i & 48) && (i & 192)) << 14)); + + } + + memset (all_ones, 0xff, MAX_PIXELS_PER_LINE); + +} + +/* 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 dualpf, int has_attach) +{ + uae_u16 *buf = spixels + e->first_pixel; + uae_u8 *stbuf = spixstate.bytes + e->first_pixel; + int spr_pos, pos; + + buf -= e->pos; + stbuf -= e->pos; + + spr_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << sprite_buffer_res); + + if (spr_pos < sprite_first_x) + sprite_first_x = spr_pos; + + for (pos = e->pos; pos < e->max; pos++, spr_pos++) { + if (spr_pos >= 0 && spr_pos < MAX_PIXELS_PER_LINE) { + spritepixels[spr_pos].data = buf[pos]; + spritepixels[spr_pos].stdata = stbuf[pos]; + spritepixels[spr_pos].attach = has_attach; + } + } + + if (spr_pos > sprite_last_x) + sprite_last_x = spr_pos; +} + +/* 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 NOINLINE draw_sprites_normal_sp_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0); } +static void NOINLINE draw_sprites_normal_dp_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0); } +static void NOINLINE draw_sprites_normal_sp_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1); } +static void NOINLINE draw_sprites_normal_dp_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 1); } + +#ifdef AGA +/* not very optimized */ +STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e, int aga) +{ + draw_sprites_1 (e, bpldualpf, e->has_attached); +} +#endif + +STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e) +{ + if (e->has_attached) { + if (bpldualpf) + draw_sprites_normal_dp_at (e); + else + draw_sprites_normal_sp_at (e); + } else { + if (bpldualpf) + draw_sprites_normal_dp_nat (e); + else + draw_sprites_normal_sp_nat (e); + } +} + +#ifdef AGA +/* clear possible bitplane data outside DIW area */ +static void clear_bitplane_border_aga (void) +{ + int len, shift = res_shift; + uae_u8 v = 0; + + if (shift < 0) { + shift = -shift; + len = (real_playfield_start - playfield_start) << shift; + memset (pixdata.apixels + pixels_offset + (playfield_start << shift), v, len); + len = (playfield_end - real_playfield_end) << shift; + memset (pixdata.apixels + pixels_offset + (real_playfield_end << shift), v, len); + } else { + len = (real_playfield_start - playfield_start) >> shift; + memset (pixdata.apixels + pixels_offset + (playfield_start >> shift), v, len); + len = (playfield_end - real_playfield_end) >> shift; + memset (pixdata.apixels + pixels_offset + (real_playfield_end >> shift), v, len); + } +} +#endif + +/* emulate OCS/ECS only undocumented "SWIV" hardware feature */ +static void weird_bitplane_fix (void) +{ + int i; + int sh = lores_shift; + uae_u8 *p = pixdata.apixels + pixels_offset; + + for (i = playfield_start >> sh; i < playfield_end >> sh; i++) { + if (p[i] > 16) + p[i] = 16; + } +} + +#define MERGE(a,b,mask,shift) do {\ + uae_u32 tmp = mask & (a ^ (b >> shift)); \ + a ^= tmp; \ + b ^= (tmp << shift); \ +} while (0) + +#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 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) { +#ifdef AGA + case 8: b0 = GETLONG (real_bplpt[7]); real_bplpt[7] += 4; + case 7: b1 = GETLONG (real_bplpt[6]); real_bplpt[6] += 4; +#endif + case 6: b2 = GETLONG (real_bplpt[5]); real_bplpt[5] += 4; + case 5: b3 = GETLONG (real_bplpt[4]); real_bplpt[4] += 4; + case 4: b4 = GETLONG (real_bplpt[3]); real_bplpt[3] += 4; + case 3: b5 = GETLONG (real_bplpt[2]); real_bplpt[2] += 4; + case 2: b6 = GETLONG (real_bplpt[1]); real_bplpt[1] += 4; + case 1: b7 = GETLONG (real_bplpt[0]); real_bplpt[0] += 4; + } + + MERGE (b0, b1, 0x55555555, 1); + MERGE (b2, b3, 0x55555555, 1); + MERGE (b4, b5, 0x55555555, 1); + MERGE (b6, b7, 0x55555555, 1); + + MERGE (b0, b2, 0x33333333, 2); + MERGE (b1, b3, 0x33333333, 2); + MERGE (b4, b6, 0x33333333, 2); + MERGE (b5, b7, 0x33333333, 2); + + MERGE (b0, b4, 0x0f0f0f0f, 4); + MERGE (b1, b5, 0x0f0f0f0f, 4); + MERGE (b2, b6, 0x0f0f0f0f, 4); + MERGE (b3, b7, 0x0f0f0f0f, 4); + + MERGE (b0, b1, 0x00ff00ff, 8); + MERGE (b2, b3, 0x00ff00ff, 8); + MERGE (b4, b5, 0x00ff00ff, 8); + MERGE (b6, b7, 0x00ff00ff, 8); + + MERGE (b0, b2, 0x0000ffff, 16); + do_put_mem_long (pixels, b0); + do_put_mem_long (pixels + 4, b2); + MERGE (b1, b3, 0x0000ffff, 16); + do_put_mem_long (pixels + 2, b1); + do_put_mem_long (pixels + 6, b3); + MERGE (b4, b6, 0x0000ffff, 16); + do_put_mem_long (pixels + 1, b4); + do_put_mem_long (pixels + 5, b6); + MERGE (b5, b7, 0x0000ffff, 16); + do_put_mem_long (pixels + 3, b5); + do_put_mem_long (pixels + 7, b7); + pixels += 8; + } +} + +/* See above for comments on inlining. These functions should _not_ +be inlined themselves. */ +static void NOINLINE pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); } +static void NOINLINE pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); } +static void NOINLINE pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); } +static void NOINLINE pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); } +static void NOINLINE pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); } +static void NOINLINE pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); } +#ifdef AGA +static void NOINLINE pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); } +static void NOINLINE pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); } +#endif + +static void pfield_doline (int lineno) +{ + int wordcount = dp_for_drawing->plflinelen; + uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / 4; + +#ifdef SMART_UPDATE +#define DATA_POINTER(n) ((debug_bpl_mask & (1 << n)) ? (line_data[lineno] + (n) * MAX_WORDS_PER_LINE * 2) : (debug_bpl_mask_one ? all_ones : all_zeros)) + real_bplpt[0] = DATA_POINTER (0); + real_bplpt[1] = DATA_POINTER (1); + real_bplpt[2] = DATA_POINTER (2); + real_bplpt[3] = DATA_POINTER (3); + real_bplpt[4] = DATA_POINTER (4); + real_bplpt[5] = DATA_POINTER (5); +#ifdef AGA + real_bplpt[6] = DATA_POINTER (6); + real_bplpt[7] = DATA_POINTER (7); +#endif +#endif + + 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; +#ifdef AGA + case 7: pfield_doline_n7 (data, wordcount); break; + case 8: pfield_doline_n8 (data, wordcount); break; +#endif + } +} + +void init_row_map (void) +{ + static uae_u8 *oldbufmem; + static int oldheight, oldpitch; + + int i, j; + if (gfxvidinfo.drawbuffer.height_allocated > MAX_VIDHEIGHT) { + write_log (_T("Resolution too high, aborting\n")); + abort (); + } + if (oldbufmem && oldbufmem == gfxvidinfo.drawbuffer.bufmem && + oldheight == gfxvidinfo.drawbuffer.height_allocated && + oldpitch == gfxvidinfo.drawbuffer.rowbytes) + return; + oldbufmem = gfxvidinfo.drawbuffer.bufmem; + oldheight = gfxvidinfo.drawbuffer.height_allocated; + oldpitch = gfxvidinfo.drawbuffer.rowbytes; + j = 0; + for (i = gfxvidinfo.drawbuffer.height_allocated; i < MAX_VIDHEIGHT + 1; i++) + row_map[i] = row_tmp; + for (i = 0; i < gfxvidinfo.drawbuffer.height_allocated; i++, j += gfxvidinfo.drawbuffer.rowbytes) + row_map[i] = gfxvidinfo.drawbuffer.bufmem + j; +} + +void init_aspect_maps (void) +{ + int i, maxl, h; + + h = gfxvidinfo.drawbuffer.height_allocated; + + if (h == 0) + /* Do nothing if the gfx driver hasn't initialized the screen yet */ + return; + + linedbld = linedbl = currprefs.gfx_vresolution; + if (doublescan > 0 && interlace_seen <= 0) { + linedbl = 0; + linedbld = 1; + } + + if (native2amiga_line_map) + xfree (native2amiga_line_map); + if (amiga2aspect_line_map) + xfree (amiga2aspect_line_map); + + /* At least for this array the +1 is necessary. */ + amiga2aspect_line_map = xmalloc (int, (MAXVPOS + 1) * 2 + 1); + native2amiga_line_map = xmalloc (int, h); + + maxl = (MAXVPOS + 1) << linedbld; + min_ypos_for_screen = minfirstline << linedbl; + max_drawn_amiga_line = -1; + for (i = 0; i < maxl; i++) { + int v = i - min_ypos_for_screen; + if (v >= h && max_drawn_amiga_line < 0) + max_drawn_amiga_line = i - min_ypos_for_screen; + if (i < min_ypos_for_screen || v >= h) + v = -1; + amiga2aspect_line_map[i] = v; + } + if (max_drawn_amiga_line < 0) + max_drawn_amiga_line = maxl - min_ypos_for_screen; + max_drawn_amiga_line >>= linedbl; + + if (currprefs.gfx_ycenter && !currprefs.gfx_filter_autoscale) { + /* @@@ verify maxvpos vs. MAXVPOS */ + extra_y_adjust = (h - (maxvpos_nom << linedbl)) >> 1; + if (extra_y_adjust < 0) + extra_y_adjust = 0; + } + + for (i = 0; i < h; i++) + native2amiga_line_map[i] = -1; + + for (i = maxl - 1; i >= min_ypos_for_screen; i--) { + int j; + if (amiga2aspect_line_map[i] == -1) + continue; + for (j = amiga2aspect_line_map[i]; j < h && native2amiga_line_map[j] == -1; j++) + native2amiga_line_map[j] = i >> linedbl; + } + + gfxvidinfo.xchange = 1 << (RES_MAX - currprefs.gfx_resolution); + gfxvidinfo.ychange = linedbl ? 1 : 2; + + visible_left_start = 0; + visible_right_stop = MAX_STOP; + visible_top_start = 0; + visible_bottom_stop = MAX_STOP; +} + +/* +* A raster line has been built in the graphics buffer. Tell the graphics code +* to do anything necessary to display it. +*/ +static void do_flush_line_1 (struct vidbuffer *vb, int lineno) +{ + if (lineno < first_drawn_line) + first_drawn_line = lineno; + if (lineno > last_drawn_line) + last_drawn_line = lineno; + + if (gfxvidinfo.maxblocklines == 0) + flush_line (vb, lineno); + else { + if ((last_block_line + 2) < lineno) { + if (first_block_line != NO_BLOCK) + flush_block (vb, first_block_line, last_block_line); + first_block_line = lineno; + } + last_block_line = lineno; + if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) { + flush_block (vb, first_block_line, last_block_line); + first_block_line = last_block_line = NO_BLOCK; + } + } +} + +STATIC_INLINE void do_flush_line (struct vidbuffer *vb, int lineno) +{ + do_flush_line_1 (vb, lineno); +} + +/* +* One drawing frame has been finished. Tell the graphics code about it. +* Note that the actual flush_screen() call is a no-op for all reasonable +* systems. +*/ + +STATIC_INLINE void do_flush_screen (struct vidbuffer *vb, int start, int stop) +{ + /* TODO: this flush operation is executed outside locked state! + Should be corrected. + (sjo 26.9.99) */ + + if (vb != gfxvidinfo.outbuffer) + return; + + xlinecheck (start, stop); + if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) { + flush_block (vb, first_block_line, last_block_line); + } + unlockscr (vb); + if (start <= stop) + flush_screen (vb, start, stop); + else if (isvsync_chipset ()) + flush_screen (vb, 0, 0); /* vsync mode */ +} + +/* We only save hardware registers during the hardware frame. Now, when +* drawing the frame, we expand the data into a slightly more useful +* form. */ +static void pfield_expand_dp_bplcon (void) +{ + static int b2; + + bplres = dp_for_drawing->bplres; + bplplanecnt = dp_for_drawing->nr_planes; + bplham = dp_for_drawing->ham_seen; + bplehb = dp_for_drawing->ehb_seen; + if ((currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon2 & 0x0200)) + bplehb = 0; + issprites = dip_for_drawing->nr_sprites; +#ifdef ECS_DENISE + ecsshres = bplres == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA); +#endif + + plf1pri = dp_for_drawing->bplcon2 & 7; + plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7; + plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri); + plf_sprite_mask |= (0x0000FFFF << (4 * plf1pri)) & 0xFFFF; + bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400; + bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40; + +#ifdef AGA + 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; + brdsprt = !brdblank && (currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon0 & 1) && (dp_for_drawing->bplcon3 & 0x02); + bplxor = dp_for_drawing->bplcon4 >> 8; +#endif +} + +static bool isham (uae_u16 bplcon0) +{ + int p = GET_PLANES (bplcon0); + if (!(bplcon0 & 0x800)) + return 0; + if (currprefs.chipset_mask & CSMASK_AGA) { + // AGA only has 6 or 8 plane HAM + if (p == 6 || p == 8) + return 1; + } else { + // OCS/ECS also supports 5 plane HAM + if (GET_RES_DENISE (bplcon0) > 0) + return 0; + if (p >= 5) + return 1; + } + return 0; +} + +static void isbrdblank (void) +{ +#ifdef ECS_DENISE + bool brdblank_2 = (currprefs.chipset_mask & CSMASK_ECS_DENISE) && (bplcon0_store & 1) && (bplcon3_store & 0x20); + if (brdblank_2 != brdblank) + brdblank_changed = true; + brdblank = brdblank_2; +#endif +} + +static void pfield_expand_dp_bplconx (int regno, int v) +{ + if (regno == 0xffff) { + hposblank = 1; + return; + } + regno -= 0x1000; + switch (regno) + { + case 0x100: + dp_for_drawing->bplcon0 = v; + dp_for_drawing->bplres = GET_RES_DENISE (v); + dp_for_drawing->nr_planes = GET_PLANES (v); + dp_for_drawing->ham_seen = isham (v); + bplcon0_store = v; + isbrdblank (); + break; + case 0x104: + dp_for_drawing->bplcon2 = v; + break; +#ifdef ECS_DENISE + case 0x106: + dp_for_drawing->bplcon3 = v; + bplcon3_store = v; + isbrdblank (); + break; +#endif +#ifdef AGA + case 0x10c: + dp_for_drawing->bplcon4 = v; + break; +#endif + } + pfield_expand_dp_bplcon (); + res_shift = lores_shift - bplres; +} + +static int drawing_color_matches; +static enum { color_match_acolors, color_match_full } color_match_type; + +/* 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 need_full) +{ + if (drawing_color_matches != ctable) { + if (need_full) { + color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable); + color_match_type = color_match_full; + } else { + memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors, + sizeof colors_for_drawing.acolors); + color_match_type = color_match_acolors; + } + drawing_color_matches = ctable; + } 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 void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield, int vp) +{ + int i; + int lastpos = visible_left_border; + int endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth; + + for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) { + int regno = curr_color_changes[i].regno; + unsigned int value = curr_color_changes[i].value; + int nextpos, nextpos_in_range; + + if (i == dip_for_drawing->last_color_change) + nextpos = endpos; + else + nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos); + + nextpos_in_range = nextpos; + if (nextpos > endpos) + nextpos_in_range = endpos; + + if (nextpos_in_range > lastpos) { + if (lastpos < playfield_start) { + int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start; + (*worker_border) (lastpos, t, false); + lastpos = t; + } + } + if (nextpos_in_range > lastpos) { + if (lastpos >= playfield_start && lastpos < playfield_end) { + int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end; + (*worker_pfield) (lastpos, t, false); + /* blank start and end that shouldn't be visible */ + if (lastpos < visible_left_start) + (*worker_border) (lastpos, visible_left_start, true); + if (t > visible_right_stop) + (*worker_border) (visible_right_stop, endpos, true); + lastpos = t; + } + } + if (nextpos_in_range > lastpos) { + if (lastpos >= playfield_end) + (*worker_border) (lastpos, nextpos_in_range, false); + lastpos = nextpos_in_range; + } + + if (regno >= 0x1000) { + pfield_expand_dp_bplconx (regno, value); + } else if (regno >= 0) { + color_reg_set (&colors_for_drawing, regno, value); + colors_for_drawing.acolors[regno] = getxcolor (value); + } + if (lastpos >= endpos) + break; + } + if (vp < visible_top_start || vp >= visible_bottom_stop) { + // outside of visible area + // Just overwrite with black. Above code needs to run because of custom registers, + // not worth the trouble for separate code path just for max 10 lines or so + (*worker_border) (visible_left_border, visible_left_border + gfxvidinfo.drawbuffer.inwidth, true); + } + +} +enum double_how { + dh_buf, + dh_line, + dh_emerg +}; + +static void pfield_draw_line (struct vidbuffer *vb, int lineno, int gfx_ypos, int follow_ypos) +{ + static int warned = 0; + int border = 0; + int do_double = 0; + enum double_how dh; + + dp_for_drawing = line_decisions + lineno; + dip_for_drawing = curr_drawinfo + lineno; + + switch (linestate[lineno]) + { + case LINE_REMEMBERED_AS_PREVIOUS: +// if (!warned) // happens when program messes up with VPOSW +// write_log (_T("Shouldn't get here... this is a bug.\n")), warned++; + return; + + case LINE_BLACK: + linestate[lineno] = LINE_REMEMBERED_AS_BLACK; + border = 2; + break; + + case LINE_REMEMBERED_AS_BLACK: + return; + + case LINE_AS_PREVIOUS: + dp_for_drawing--; + dip_for_drawing--; + linestate[lineno] = LINE_DONE_AS_PREVIOUS; + if (dp_for_drawing->plfleft < 0) + border = 1; + break; + + case LINE_DONE_AS_PREVIOUS: + /* fall through */ + case LINE_DONE: + return; + + case LINE_DECIDED_DOUBLE: + if (follow_ypos >= 0) { + do_double = 1; + linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; + } + + /* fall through */ + default: + if (dp_for_drawing->plfleft < 0) + border = 1; + linestate[lineno] = LINE_DONE; + break; + } + + dh = dh_line; + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0 && do_double + && (border == 0 || dip_for_drawing->nr_color_changes > 0)) + xlinebuffer = gfxvidinfo.drawbuffer.emergmem, dh = dh_emerg; + if (xlinebuffer == 0) + xlinebuffer = row_map[gfx_ypos], dh = dh_buf; + xlinebuffer -= linetoscr_x_adjust_bytes; + + if (border == 0) { + + pfield_expand_dp_bplcon (); + pfield_init_linetoscr (); + pfield_doline (lineno); + + adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb || ecsshres); + + /* The problem is that we must call decode_ham() BEFORE we do the + sprites. */ + if (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, false); + } else /* Argh. */ { + do_color_changes (dummy_worker, decode_ham, lineno); + adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb); + } + bplham = dp_for_drawing->ham_at_start; + } + + if (plf2pri > 5 && bplplanecnt == 5 && !(currprefs.chipset_mask & CSMASK_AGA)) + weird_bitplane_fix (); + + if (dip_for_drawing->nr_sprites) { + int i; +#ifdef AGA + if (brdsprt) + clear_bitplane_border_aga (); +#endif + for (i = 0; i < dip_for_drawing->nr_sprites; i++) { +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1); + else +#endif + draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + } + } + + do_color_changes (pfield_do_fill_line, pfield_do_linetoscr, lineno); + + if (dh == dh_emerg) + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + + do_flush_line (vb, gfx_ypos); + if (do_double) { + if (dh == dh_emerg) + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + else if (dh == dh_buf) + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + do_flush_line (vb, follow_ypos); + } + + } else if (border == 1) { + int dosprites = 0; + + adjust_drawing_colors (dp_for_drawing->ctable, 0); + +#ifdef AGA /* this makes things complex.. */ + if (brdsprt && dip_for_drawing->nr_sprites > 0) { + dosprites = 1; + pfield_expand_dp_bplcon (); + pfield_init_linetoscr (); + memset (pixdata.apixels + MAX_PIXELS_PER_LINE, brdblank ? 0 : colors_for_drawing.acolors[0], MAX_PIXELS_PER_LINE); + } +#endif + + if (!dosprites && dip_for_drawing->nr_color_changes == 0) { + fill_line (); + do_flush_line (vb, gfx_ypos); + + if (do_double) { + if (dh == dh_buf) { + xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_bytes; + fill_line (); + } + /* If dh == dh_line, do_flush_line will re-use the rendered line + * from linemem. */ + do_flush_line (vb, follow_ypos); + } + return; + } + + + if (dosprites) { + + int i; + for (i = 0; i < dip_for_drawing->nr_sprites; i++) + draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1); + uae_u16 oxor = bplxor; + memset (pixdata.apixels, 0, sizeof pixdata); + bplxor = 0; + do_color_changes (pfield_do_fill_line, pfield_do_linetoscr, lineno); + bplxor = oxor; + + } else { + + playfield_start = visible_right_border; + playfield_end = visible_right_border; + do_color_changes (pfield_do_fill_line, pfield_do_fill_line, lineno); + + } + + if (dh == dh_emerg) + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + + do_flush_line (vb, gfx_ypos); + if (do_double) { + if (dh == dh_emerg) + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + else if (dh == dh_buf) + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + do_flush_line (vb, follow_ypos); + } + + } else { + + int tmp = hposblank; + hposblank = brdblank; + fill_line (); + do_flush_line (vb, gfx_ypos); + hposblank = tmp; + + } +} + +static void center_image (void) +{ + int prev_x_adjust = visible_left_border; + int prev_y_adjust = thisframe_y_adjust; + int tmp; + + int w = gfxvidinfo.drawbuffer.inwidth; + if (currprefs.gfx_xcenter && !currprefs.gfx_filter_autoscale && max_diwstop > 0) { + + if (max_diwstop - min_diwstart < w && currprefs.gfx_xcenter == 2) + /* Try to center. */ + visible_left_border = (max_diwstop - min_diwstart - w) / 2 + min_diwstart; + else + visible_left_border = max_diwstop - w - (max_diwstop - min_diwstart - w) / 2; + visible_left_border &= ~((xshift (1, lores_shift)) - 1); + + /* Would the old value be good enough? If so, leave it as it is if we want to + * be clever. */ + if (currprefs.gfx_xcenter == 2) { + if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart && min_diwstart - visible_left_border <= 32) + visible_left_border = prev_x_adjust; + } + } else if (gfxvidinfo.drawbuffer.extrawidth) { + visible_left_border = max_diwlastword - w; + //visible_left_border += gfxvidinfo.drawbuffer.extrawidth << currprefs.gfx_resolution; + } else { + if (gfxvidinfo.drawbuffer.inxoffset < 0) { + visible_left_border = 0; + } else { + visible_left_border = gfxvidinfo.drawbuffer.inxoffset - DISPLAY_LEFT_SHIFT; + } + } + + + if (visible_left_border > max_diwlastword - 32) + visible_left_border = max_diwlastword - 32; + if (visible_left_border < 0) + visible_left_border = 0; + visible_left_border &= ~((xshift (1, lores_shift)) - 1); + + //write_log (_T("%d %d %d %d %d\n"), max_diwlastword, gfxvidinfo.drawbuffer.width, lores_shift, currprefs.gfx_resolution, visible_left_border); + + linetoscr_x_adjust_bytes = visible_left_border * gfxvidinfo.drawbuffer.pixbytes; + + visible_right_border = visible_left_border + w; + if (visible_right_border > max_diwlastword) + visible_right_border = max_diwlastword; + + thisframe_y_adjust = minfirstline; + if (currprefs.gfx_ycenter && thisframe_first_drawn_line >= 0 && !currprefs.gfx_filter_autoscale) { + + if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && currprefs.gfx_ycenter == 2) + thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line; + else + thisframe_y_adjust = thisframe_first_drawn_line + ((thisframe_last_drawn_line - thisframe_first_drawn_line) - max_drawn_amiga_line) / 2; + + /* Would the old value be good enough? If so, leave it as it is if we want to + * be clever. */ + if (currprefs.gfx_ycenter == 2) { + if (thisframe_y_adjust != prev_y_adjust + && prev_y_adjust <= thisframe_first_drawn_line + && prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line) + thisframe_y_adjust = prev_y_adjust; + } + } + + /* Make sure the value makes sense */ + if (thisframe_y_adjust + max_drawn_amiga_line > maxvpos_nom) + thisframe_y_adjust = maxvpos_nom - max_drawn_amiga_line; + if (thisframe_y_adjust < minfirstline) + thisframe_y_adjust = minfirstline; + + thisframe_y_adjust_real = thisframe_y_adjust << linedbl; + tmp = (maxvpos_nom - thisframe_y_adjust + 1) << linedbl; + if (tmp != max_ypos_thisframe) { + last_max_ypos = tmp; + if (last_max_ypos < 0) + last_max_ypos = 0; + } + max_ypos_thisframe = tmp; + + /* @@@ interlace_seen used to be (bplcon0 & 4), but this is probably + * better. */ + if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust) + frame_redraw_necessary |= (interlace_seen > 0 && linedbl) ? 2 : 1; + + max_diwstop = 0; + min_diwstart = 10000; + + gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - currprefs.gfx_resolution)); + gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX; + + visible_left_start = visible_left_border; + visible_right_stop = visible_left_start + gfxvidinfo.drawbuffer.inwidth;; +} + +#define FRAMES_UNTIL_RES_SWITCH 1 +static int frame_res_cnt; +static void init_drawing_frame (void) +{ + int i, maxline; +#if 1 + static int frame_res_old; + + if (currprefs.gfx_autoresolution && frame_res >= 0 && frame_res_lace >= 0) { + if (FRAMES_UNTIL_RES_SWITCH > 0 && frame_res_old == frame_res * 2 + frame_res_lace) { + frame_res_cnt--; + if (frame_res_cnt == 0) { + int m = frame_res * 2 + frame_res_lace; + struct wh *dst = currprefs.gfx_apmode[0].gfx_fullscreen ? &changed_prefs.gfx_size_fs : &changed_prefs.gfx_size_win; + while (m < 3 * 2) { + struct wh *src = currprefs.gfx_apmode[0].gfx_fullscreen ? &currprefs.gfx_size_fs_xtra[m] : &currprefs.gfx_size_win_xtra[m]; + if ((src->width > 0 && src->height > 0) || (currprefs.gfx_api || currprefs.gfx_filter > 0)) { + int nr = m >> 1; + int nl = (m & 1) == 0 ? 0 : 1; + int nr_o = nr; + int nl_o = nl; + + if (currprefs.gfx_autoresolution_minh < 0) { + if (nr < nl) + nr = nl; + } else if (nr < currprefs.gfx_autoresolution_minh) { + nr = currprefs.gfx_autoresolution_minh; + } + if (currprefs.gfx_autoresolution_minv < 0) { + if (nl < nr) + nl = nr; + } else if (nl < currprefs.gfx_autoresolution_minv) { + nl = currprefs.gfx_autoresolution_minv; + } + + if (nr > gfxvidinfo.gfx_resolution_reserved) + nr = gfxvidinfo.gfx_resolution_reserved; + if (nl > gfxvidinfo.gfx_vresolution_reserved) + nl = gfxvidinfo.gfx_vresolution_reserved; + + if (changed_prefs.gfx_resolution != nr || changed_prefs.gfx_vresolution != nl) { + changed_prefs.gfx_resolution = nr; + changed_prefs.gfx_vresolution = nl; + write_log (_T("RES -> %d (%d) LINE -> %d (%d) (%d - %d, %d - %d)\n"), nr, nr_o, nl, nl_o, + currprefs.gfx_autoresolution_minh, currprefs.gfx_autoresolution_minv, + gfxvidinfo.gfx_resolution_reserved, gfxvidinfo.gfx_vresolution_reserved); + config_changed = 1; + //activate_debugger (); + } + if (src->width > 0 && src->height > 0) { + if (memcmp (dst, src, sizeof *dst)) { + *dst = *src; + config_changed = 1; + } + } + break; + } + m++; + } + frame_res_cnt = FRAMES_UNTIL_RES_SWITCH; + } + } else { + frame_res_old = frame_res * 2 + frame_res_lace; + frame_res_cnt = FRAMES_UNTIL_RES_SWITCH; + } + } + frame_res = -1; + frame_res_lace = 0; + + if (can_use_lores > AUTO_LORES_FRAMES && 0) { + lores_factor = 1; + lores_shift = 0; + } else { + can_use_lores++; + lores_reset (); + } +#endif + + init_hardware_for_drawing_frame (); + + if (thisframe_first_drawn_line < 0) + thisframe_first_drawn_line = minfirstline; + if (thisframe_first_drawn_line > thisframe_last_drawn_line) + thisframe_last_drawn_line = thisframe_first_drawn_line; + + maxline = ((maxvpos_nom + 1) << linedbl) + 2; +#ifdef SMART_UPDATE + for (i = 0; i < maxline; i++) { + switch (linestate[i]) { + case LINE_DONE_AS_PREVIOUS: + linestate[i] = LINE_REMEMBERED_AS_PREVIOUS; + break; + case LINE_REMEMBERED_AS_BLACK: + break; + default: + linestate[i] = LINE_UNDECIDED; + break; + } + } +#else + memset (linestate, LINE_UNDECIDED, maxline); +#endif + last_drawn_line = 0; + first_drawn_line = 32767; + + first_block_line = last_block_line = NO_BLOCK; + if (frame_redraw_necessary) + frame_redraw_necessary--; + + center_image (); + + thisframe_first_drawn_line = -1; + thisframe_last_drawn_line = -1; + + drawing_color_matches = -1; + seen_sprites = -1; +} + +void putpixel (uae_u8 *buf, int bpp, int x, xcolnr c8, int opaq) +{ + if (x <= 0) + return; + + switch (bpp) { + case 1: + buf[x] = (uae_u8)c8; + break; + case 2: + { + uae_u16 *p = (uae_u16*)buf + x; + *p = (uae_u16)c8; + break; + } + case 3: + /* no 24 bit yet */ + break; + case 4: + { + int i; + if (1 || opaq || currprefs.gfx_filter == 0) { + uae_u32 *p = (uae_u32*)buf + x; + *p = c8; + } else { + for (i = 0; i < 4; i++) { + int v1 = buf[i + bpp * x]; + int v2 = (c8 >> (i * 8)) & 255; + v1 = (v1 * 2 + v2 * 3) / 5; + if (v1 > 255) + v1 = 255; + buf[i + bpp * x] = v1; + } + } + break; + } + } +} + +static void draw_status_line (int line, int statusy) +{ + int bpp, y; + uae_u8 *buf; + + if (!(currprefs.leds_on_screen & STATUSLINE_CHIPSET) || (currprefs.leds_on_screen & STATUSLINE_TARGET)) + return; + bpp = gfxvidinfo.drawbuffer.pixbytes; + y = line - (gfxvidinfo.drawbuffer.outheight - TD_TOTAL_HEIGHT); + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + buf = xlinebuffer; + draw_status_line_single (buf, bpp, statusy, gfxvidinfo.drawbuffer.outwidth, xredcolors, xgreencolors, xbluecolors, NULL); +} + +static void draw_debug_status_line (int line) +{ + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + debug_draw_cycles (xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, line, gfxvidinfo.drawbuffer.outwidth, gfxvidinfo.drawbuffer.outheight, xredcolors, xgreencolors, xbluecolors); +} + +#define LIGHTPEN_HEIGHT 12 +#define LIGHTPEN_WIDTH 17 + +static const char *lightpen_cursor = { + "------.....------" + "------.xxx.------" + "------.xxx.------" + "------.xxx.------" + ".......xxx......." + ".xxxxxxxxxxxxxxx." + ".xxxxxxxxxxxxxxx." + ".......xxx......." + "------.xxx.------" + "------.xxx.------" + "------.xxx.------" + "------.....------" +}; + +static void draw_lightpen_cursor (int x, int y, int line, int onscreen) +{ + int i; + const char *p; + int color1 = onscreen ? 0xff0 : 0xf00; + int color2 = 0x000; + + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + + p = lightpen_cursor + y * LIGHTPEN_WIDTH; + for (i = 0; i < LIGHTPEN_WIDTH; i++) { + int xx = x + i - LIGHTPEN_WIDTH / 2; + if (*p != '-' && xx >= 0 && xx < gfxvidinfo.drawbuffer.outwidth) + putpixel (xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, xx, *p == 'x' ? xcolors[color1] : xcolors[color2], 1); + p++; + } +} + +static int lightpen_y1, lightpen_y2; + +static void lightpen_update (struct vidbuffer *vb) +{ + int i; + + if (lightpen_x < LIGHTPEN_WIDTH + 1) + lightpen_x = LIGHTPEN_WIDTH + 1; + if (lightpen_x >= gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 1) + lightpen_x = gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 2; + if (lightpen_y < LIGHTPEN_HEIGHT + 1) + lightpen_y = LIGHTPEN_HEIGHT + 1; + if (lightpen_y >= gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 1) + lightpen_y = gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 2; + if (lightpen_y >= max_ypos_thisframe - LIGHTPEN_HEIGHT - 1) + lightpen_y = max_ypos_thisframe - LIGHTPEN_HEIGHT - 2; + + lightpen_cx = (((lightpen_x + visible_left_border) >> lores_shift) >> 1) + DISPLAY_LEFT_SHIFT - DIW_DDF_OFFSET; + + lightpen_cy = lightpen_y; + lightpen_cy >>= linedbl; + lightpen_cy += minfirstline; + + if (lightpen_cx < 0x18) + lightpen_cx = 0x18; + if (lightpen_cx >= maxhpos) + lightpen_cx -= maxhpos; + if (lightpen_cy < minfirstline) + lightpen_cy = minfirstline; + if (lightpen_cy >= maxvpos) + lightpen_cy = maxvpos - 1; + + for (i = 0; i < LIGHTPEN_HEIGHT; i++) { + int line = lightpen_y + i - LIGHTPEN_HEIGHT / 2; + if (line >= 0 || line < max_ypos_thisframe) { + draw_lightpen_cursor(lightpen_x, i, line, lightpen_cx > 0); + flush_line (vb, line); + } + } + lightpen_y1 = lightpen_y - LIGHTPEN_HEIGHT / 2 - 1 + min_ypos_for_screen; + lightpen_y2 = lightpen_y1 + LIGHTPEN_HEIGHT + 2; +} + +void finish_drawing_frame (void) +{ + int i; + bool didflush = false; + struct vidbuffer *vb = &gfxvidinfo.drawbuffer; + + gfxvidinfo.outbuffer = vb; + + if (! lockscr (vb, false)) { + 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 i1 = i + min_ypos_for_screen; + int line = i + thisframe_y_adjust_real; + int where2; + + where2 = amiga2aspect_line_map[i1]; + if (where2 >= vb->inheight) + break; + if (where2 < 0) + continue; + hposblank = 0; + pfield_draw_line (vb, line, where2, amiga2aspect_line_map[i1 + 1]); + } + + /* clear possible old garbage at the bottom if emulated area become smaller */ + for (i = last_max_ypos; i < vb->outheight; i++) { + int i1 = i + min_ypos_for_screen; + int line = i + thisframe_y_adjust_real; + int where2 = amiga2aspect_line_map[i1]; + + if (where2 >= gfxvidinfo.drawbuffer.outheight) + break; + if (where2 < 0) + continue; + + hposblank = i > last_max_ypos ;// + AMIGA_HEIGHT_EXTRA; + + xlinebuffer = vb->linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[where2]; + xlinebuffer -= linetoscr_x_adjust_bytes; + fill_line (); + if (line < max_ypos_thisframe) + linestate[line] = LINE_UNDECIDED; + do_flush_line (vb, where2); + } + + if (currprefs.leds_on_screen) { + int slx, sly; + statusline_getpos (&slx, &sly, vb->outwidth, vb->outheight); + for (i = 0; i < TD_TOTAL_HEIGHT; i++) { + int line = sly + i; + draw_status_line (line, i); + do_flush_line (vb, line); + } + } + if (debug_dma > 1) { + for (i = 0; i < vb->outheight; i++) { + int line = i; + draw_debug_status_line (line); + do_flush_line (vb, line); + } + } + + if (lightpen_x > 0 || lightpen_y > 0) + lightpen_update (vb); + + if (currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated) { + static bool specialon; + if (emulate_specialmonitors (vb, &gfxvidinfo.tempbuffer)) { + vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; + if (vb->nativepositioning) { + vb->inwidth = gfxvidinfo.drawbuffer.inwidth; + vb->inheight = gfxvidinfo.drawbuffer.inheight; + vb->inwidth2 = gfxvidinfo.drawbuffer.inwidth2; + vb->inheight2 = gfxvidinfo.drawbuffer.inheight2; + vb->outwidth = gfxvidinfo.drawbuffer.outwidth; + vb->outheight = gfxvidinfo.drawbuffer.outheight; + } + gfxvidinfo.drawbuffer.tempbufferinuse = true; + if (!specialon) + compute_framesync (); + specialon = true; + do_flush_screen (vb, 0, vb->outheight); + didflush = true; + } else { + gfxvidinfo.drawbuffer.tempbufferinuse = false; + if (specialon) + compute_framesync (); + specialon = false; + } + } + + if (!didflush) + do_flush_screen (vb, first_drawn_line, last_drawn_line); + + +#ifdef ECS_DENISE + if (brdblank_changed) { + last_max_ypos = max_ypos_thisframe; + for (i = 0; i < sizeof linestate / sizeof *linestate; i++) + linestate[i] = LINE_UNDECIDED; + notice_screen_contents_lost (); + brdblank_changed = false; + } +#endif +} + +void hardware_line_completed (int lineno) +{ +#ifndef SMART_UPDATE + { + int i, where; + /* l is the line that has been finished for drawing. */ + i = lineno - thisframe_y_adjust_real; + if (i >= 0 && i < max_ypos_thisframe) { + where = amiga2aspect_line_map[i+min_ypos_for_screen]; + if (where < gfxvidinfo.drawbuffer.outheight && where >= 0) + pfield_draw_line (lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); + } + } +#endif +} + +void check_picasso (void) +{ +#ifdef PICASSO96 + if (picasso_on && picasso_redraw_necessary) + picasso_refresh (); + picasso_redraw_necessary = 0; + + if (picasso_requested_on == picasso_on) + return; + + picasso_on = picasso_requested_on; + + if (!picasso_on) + clear_inhibit_frame (IHF_PICASSO); + else + set_inhibit_frame (IHF_PICASSO); + + gfx_set_picasso_state (picasso_on); + picasso_enablescreen (picasso_requested_on); + + notice_screen_contents_lost (); + notice_new_xcolors (); + count_frame (); +#endif +} + +void redraw_frame (void) +{ + last_drawn_line = 0; + first_drawn_line = 32767; + finish_drawing_frame (); + flush_screen (gfxvidinfo.inbuffer, 0, 0); +} + +void vsync_handle_check (void) +{ + check_picasso (); + + int changed = check_prefs_changed_gfx (); + if (changed > 0) { + reset_drawing (); + init_row_map (); + init_aspect_maps (); + notice_screen_contents_lost (); + notice_new_xcolors (); + } else if (changed < 0) { + reset_drawing (); + init_row_map (); + init_aspect_maps (); + notice_screen_contents_lost (); + notice_new_xcolors (); + } + check_prefs_changed_audio (); + check_prefs_changed_custom (); + check_prefs_changed_cpu (); +} + +void vsync_handle_redraw (int long_frame, int lof_changed, uae_u16 bplcon0p, uae_u16 bplcon3p) +{ + last_redraw_point++; + if (lof_changed || interlace_seen <= 0 || last_redraw_point >= 2 || long_frame || doublescan < 0) { + last_redraw_point = 0; + + if (framecnt == 0) + finish_drawing_frame (); +#if 0 + if (interlace_seen > 0) { + interlace_seen = -1; + } else if (interlace_seen == -1) { + interlace_seen = 0; + if (currprefs.gfx_scandoubler && currprefs.gfx_vresolution) + notice_screen_contents_lost (); + } +#endif + + if (quit_program < 0) { +#ifdef SAVESTATE + if (!savestate_state) { + if (currprefs.quitstatefile[0]) { + savestate_initsave (currprefs.quitstatefile, 1, 1, true); + save_state (currprefs.quitstatefile, _T("")); + } + } +#endif + quit_program = -quit_program; + set_inhibit_frame (IHF_QUIT_PROGRAM); + set_special (SPCFLAG_BRK); + return; + } + + count_frame (); + + if (framecnt == 0) + init_drawing_frame (); + else if (currprefs.cpu_cycle_exact) + init_hardware_for_drawing_frame (); + } else { + if (isvsync_chipset ()) + flush_screen (gfxvidinfo.inbuffer, 0, 0); /* vsync mode */ + } + + /* check borderblank here because bplcon0 or especially bplcon3 may only be written once outside of displayable area */ + bplcon0_store = bplcon0p; + bplcon3_store = bplcon3p; + isbrdblank (); + + gui_flicker_led (-1, 0, 0); +#ifdef AVIOUTPUT + frame_drawn (); +#endif +} + +void hsync_record_line_state (int lineno, enum nln_how how, int changed) +{ + uae_u8 *state; + + if (framecnt != 0) + return; + + state = linestate + lineno; + changed += frame_redraw_necessary + ((lineno >= lightpen_y1 && lineno <= lightpen_y2) ? 1 : 0); + + switch (how) { + case nln_normal: + *state = changed ? LINE_DECIDED : LINE_DONE; + break; + case nln_doubled: + *state = changed ? LINE_DECIDED_DOUBLE : LINE_DONE; + changed += state[1] != LINE_REMEMBERED_AS_PREVIOUS; + state[1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS; + break; + case nln_nblack: + *state = changed ? LINE_DECIDED : LINE_DONE; + if (state[1] != LINE_REMEMBERED_AS_BLACK) + state[1] = LINE_BLACK; + break; + case nln_lower: + if (state[-1] == LINE_UNDECIDED) + state[-1] = LINE_DECIDED; //LINE_BLACK; + *state = changed ? LINE_DECIDED : LINE_DONE; + break; + case nln_upper: + *state = changed ? LINE_DECIDED : LINE_DONE; + if (state[1] == LINE_UNDECIDED + || state[1] == LINE_REMEMBERED_AS_PREVIOUS + || state[1] == LINE_AS_PREVIOUS) + state[1] = LINE_DECIDED; //LINE_BLACK; + break; + } +} + +static void dummy_flush_line (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int line_no) +{ +} + +static void dummy_flush_block (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int first_line, int last_line) +{ +} + +static void dummy_flush_screen (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int first_line, int last_line) +{ +} + +static void dummy_flush_clear_screen (struct vidbuf_description *gfxinfo, struct vidbuffer *vb) +{ +} + +static int dummy_lock (struct vidbuf_description *gfxinfo, struct vidbuffer *vb) +{ + return 1; +} + +static void dummy_unlock (struct vidbuf_description *gfxinfo, struct vidbuffer *vb) +{ +} + +static void gfxbuffer_reset (void) +{ + gfxvidinfo.drawbuffer.flush_line = dummy_flush_line; + gfxvidinfo.drawbuffer.flush_block = dummy_flush_block; + gfxvidinfo.drawbuffer.flush_screen = dummy_flush_screen; + gfxvidinfo.drawbuffer.flush_clear_screen = dummy_flush_clear_screen; + gfxvidinfo.drawbuffer.lockscr = dummy_lock; + gfxvidinfo.drawbuffer.unlockscr = dummy_unlock; +} + +void notice_resolution_seen (int res, bool lace) +{ + if (res > frame_res) + frame_res = res; + if (res > 0) + can_use_lores = 0; + if (!frame_res_lace && lace) + frame_res_lace = lace; +} + +bool notice_interlace_seen (bool lace) +{ + bool changed = false; + // non-lace to lace switch (non-lace active at least one frame)? + if (lace) { + if (interlace_seen == 0) { + changed = true; + //write_log (_T("->lace PC=%x\n"), m68k_getpc ()); + } + interlace_seen = currprefs.gfx_vresolution ? 1 : -1; + } else { + if (interlace_seen) { + changed = true; + //write_log (_T("->non-lace PC=%x\n"), m68k_getpc ()); + } + interlace_seen = 0; + } + return changed; +} + +static void clearbuffer (struct vidbuffer *dst) +{ + if (!dst->bufmem_allocated) + return; + uae_u8 *p = dst->bufmem_allocated; + for (int y = 0; y < dst->height_allocated; y++) { + memset (p, 0, dst->width_allocated * dst->pixbytes); + p += dst->rowbytes; + } +} + +void reset_decision_table (void) +{ + for (int i = 0; i < sizeof linestate / sizeof *linestate; i++) + linestate[i] = LINE_UNDECIDED; +} + +void reset_drawing (void) +{ + unsigned int i; + + max_diwstop = 0; + + lores_reset (); + + for (i = 0; i < sizeof linestate / sizeof *linestate; i++) + linestate[i] = LINE_UNDECIDED; + + init_aspect_maps (); + + init_row_map (); + + last_redraw_point = 0; + + memset (spixels, 0, sizeof spixels); + memset (&spixstate, 0, sizeof spixstate); + + init_drawing_frame (); + + notice_screen_contents_lost (); + frame_res_cnt = FRAMES_UNTIL_RES_SWITCH; + lightpen_y1 = lightpen_y2 = -1; + + reset_custom_limits (); + + clearbuffer (&gfxvidinfo.drawbuffer); + clearbuffer (&gfxvidinfo.tempbuffer); +} + +void drawing_init (void) +{ + gen_pfield_tables (); + + uae_sem_init (&gui_sem, 0, 1); +#ifdef PICASSO96 + if (!isrestore ()) { + picasso_on = 0; + picasso_requested_on = 0; + gfx_set_picasso_state (0); + } +#endif + xlinebuffer = gfxvidinfo.drawbuffer.bufmem; + + inhibit_frame = 0; + + gfxbuffer_reset (); + reset_drawing (); +} + +int isvsync_chipset (void) +{ + if (picasso_on || !currprefs.gfx_apmode[0].gfx_vsync || (currprefs.gfx_apmode[0].gfx_vsync == 0 && !currprefs.gfx_apmode[0].gfx_fullscreen)) + return 0; + if (currprefs.gfx_apmode[0].gfx_vsyncmode == 0) + return 1; + if (currprefs.m68k_speed >= 0) + return -1; + return currprefs.cachesize ? -3 : -2; +} + +int isvsync_rtg (void) +{ + if (!picasso_on || !currprefs.gfx_apmode[1].gfx_vsync || (currprefs.gfx_apmode[1].gfx_vsync == 0 && !currprefs.gfx_apmode[1].gfx_fullscreen)) + return 0; + if (currprefs.gfx_apmode[1].gfx_vsyncmode == 0) + return 1; + if (currprefs.m68k_speed >= 0) + return -1; + return currprefs.cachesize ? -3 : -2; +} + +int isvsync (void) +{ + if (picasso_on) + return isvsync_rtg (); + else + return isvsync_chipset (); +} diff --git a/drawing.cpp b/drawing.cpp index ff2b48da..5636a763 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -50,7 +50,7 @@ happening, all ports should restrict window widths to be multiples of 16 pixels. #include "inputdevice.h" #include "debug.h" -extern bool emulate_specialmonitors(struct vidbuffer*, struct vidbuffer*); +extern bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*); extern int sprite_buffer_res; int lores_factor, lores_shift; @@ -565,8 +565,8 @@ void get_custom_mouse_limits (int *pw, int *ph, int *pdx, int *pdy, int dbl) delay1 = (firstword_bplcon1 & 0x0f) | ((firstword_bplcon1 & 0x0c00) >> 6); delay2 = ((firstword_bplcon1 >> 4) & 0x0f) | (((firstword_bplcon1 >> 4) & 0x0c00) >> 6); - if (delay1 == delay2) - ;//dx += delay1; +// if (delay1 == delay2) +// dx += delay1; dx = xshift (dx, res_shift); @@ -2396,13 +2396,10 @@ static void center_image (void) frame_redraw_necessary |= (interlace_seen > 0 && linedbl) ? 2 : 1; max_diwstop = 0; - min_diwstart = 10000; + min_diwstart = MAX_STOP; gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - currprefs.gfx_resolution)); gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX; - - visible_left_start = visible_left_border; - visible_right_stop = visible_left_start + gfxvidinfo.drawbuffer.inwidth;; } #define FRAMES_UNTIL_RES_SWITCH 1 diff --git a/hardfile.cpp b/hardfile.cpp index 1c708c24..4fc6e6a5 100644 --- a/hardfile.cpp +++ b/hardfile.cpp @@ -413,6 +413,26 @@ static uae_u32 vhd_checksum (uae_u8 *p, int offset) return ~sum; } +static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); +static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); + +static void hdf_init_cache (struct hardfiledata *hfd) +{ +} +static void hdf_flush_cache (struct hardfiledata *hdf) +{ +} + +static int hdf_cache_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + return hdf_read2 (hfd, buffer, offset, len); +} + +static int hdf_cache_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + return hdf_write2 (hfd, buffer, offset, len); +} + int hdf_open (struct hardfiledata *hfd, const TCHAR *pname) { uae_u8 tmp[512], tmp2[512]; @@ -472,6 +492,7 @@ int hdf_open (struct hardfiledata *hfd, const TCHAR *pname) write_log (_T("HDF is VHD %s image, virtual size=%dK\n"), hfd->vhd_type == 2 ? _T("fixed") : _T("dynamic"), hfd->virtsize / 1024); + hdf_init_cache (hfd); return 1; nonvhd: hfd->vhd_type = 0; @@ -483,6 +504,7 @@ end: void hdf_close (struct hardfiledata *hfd) { + hdf_flush_cache (hfd); hdf_close_target (hfd); hfd->vhd_type = 0; xfree (hfd->vhd_header); @@ -792,6 +814,16 @@ static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, in return hdf_read_target (hfd, buffer, offset, len); } +static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + if (hfd->vhd_type == VHD_DYNAMIC) + return vhd_write (hfd, buffer, offset, len); + else if (hfd->vhd_type == VHD_FIXED) + return hdf_write_target (hfd, buffer, offset + 512, len); + else + return hdf_write_target (hfd, buffer, offset, len); +} + static void adide_decode (void *v, int len) { int i; @@ -938,10 +970,10 @@ int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) int v; if (!hfd->adide) { - v = hdf_read2 (hfd, buffer, offset, len); + v = hdf_cache_read (hfd, buffer, offset, len); } else { offset += 512; - v = hdf_read2 (hfd, buffer, offset, len); + v = hdf_cache_read (hfd, buffer, offset, len); adide_decode (buffer, len); } if (hfd->byteswap) @@ -949,16 +981,6 @@ int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) return v; } -static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) -{ - if (hfd->vhd_type == VHD_DYNAMIC) - return vhd_write (hfd, buffer, offset, len); - else if (hfd->vhd_type == VHD_FIXED) - return hdf_write_target (hfd, buffer, offset + 512, len); - else - return hdf_write_target (hfd, buffer, offset, len); -} - int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { int v; @@ -966,11 +988,11 @@ int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) if (hfd->byteswap) hdf_byteswap (buffer, len); if (!hfd->adide) { - v = hdf_write2 (hfd, buffer, offset, len); + v = hdf_cache_write (hfd, buffer, offset, len); } else { offset += 512; adide_encode (buffer, len); - v = hdf_write2 (hfd, buffer, offset, len); + v = hdf_cache_write (hfd, buffer, offset, len); adide_decode (buffer, len); } if (hfd->byteswap) diff --git a/include/filesys.h b/include/filesys.h index a01289c1..e33af5a5 100644 --- a/include/filesys.h +++ b/include/filesys.h @@ -8,6 +8,18 @@ struct hardfilehandle; +#define MAX_HDF_CACHE_BLOCKS 128 +struct hdf_cache +{ + bool valid; + uae_u8 *data; + uae_u64 block; + bool dirty; + int readcount; + int writecount; + time_t lastaccess; +}; + struct hardfiledata { uae_u64 virtsize; // virtual size uae_u64 physsize; // physical size (dynamic disk) @@ -51,6 +63,8 @@ struct hardfiledata { int drive_empty; TCHAR *emptyname; + + struct hdf_cache bcache[MAX_HDF_CACHE_BLOCKS]; }; #define HFD_FLAGS_REALDRIVE 1 diff --git a/include/inputdevice.h b/include/inputdevice.h index 653e12c7..75f6865f 100644 --- a/include/inputdevice.h +++ b/include/inputdevice.h @@ -55,7 +55,7 @@ extern int pause_emulation; struct uae_input_device_default_node { int evt; - int flags; + uae_u64 flags; }; struct uae_input_device_kbr_default { @@ -84,19 +84,22 @@ struct inputevent { #define ID_FLAG_GAMEPORTSCUSTOM_MASK (ID_FLAG_GAMEPORTSCUSTOM1 | ID_FLAG_GAMEPORTSCUSTOM2) #define ID_FLAG_AUTOFIRE_MASK (ID_FLAG_TOGGLE | ID_FLAG_INVERTTOGGLE | ID_FLAG_AUTOFIRE) -#define ID_FLAG_QUALIFIER1 0x00010000 -#define ID_FLAG_QUALIFIER2 0x00020000 -#define ID_FLAG_QUALIFIER3 0x00040000 -#define ID_FLAG_QUALIFIER4 0x00080000 -#define ID_FLAG_QUALIFIER5 0x00100000 -#define ID_FLAG_QUALIFIER6 0x00200000 -#define ID_FLAG_QUALIFIER7 0x00400000 -#define ID_FLAG_QUALIFIER8 0x00800000 -#define ID_FLAG_QUALIFIER_SPECIAL 0x01000000 -#define ID_FLAG_QUALIFIER_SHIFT 0x02000000 -#define ID_FLAG_QUALIFIER_CONTROL 0x04000000 -#define ID_FLAG_QUALIFIER_ALT 0x08000000 -#define ID_FLAG_QUALIFIER_MASK 0x0fff0000 +#define ID_FLAG_QUALIFIER1 0x00000100000000 +#define ID_FLAG_QUALIFIER1_R 0x00000200000000 +#define ID_FLAG_QUALIFIER2 0x00000400000000 +#define ID_FLAG_QUALIFIER3 0x00001000000000 +#define ID_FLAG_QUALIFIER4 0x00004000000000 +#define ID_FLAG_QUALIFIER5 0x00010000000000 +#define ID_FLAG_QUALIFIER6 0x00040000000000 +#define ID_FLAG_QUALIFIER7 0x00100000000000 +#define ID_FLAG_QUALIFIER8 0x00400000000000 +#define ID_FLAG_QUALIFIER_SPECIAL 0x01000000000000 +#define ID_FLAG_QUALIFIER_SPECIAL_R 0x02000000000000 +#define ID_FLAG_QUALIFIER_SHIFT 0x04000000000000 +#define ID_FLAG_QUALIFIER_CONTROL 0x10000000000000 +#define ID_FLAG_QUALIFIER_ALT 0x40000000000000 +#define ID_FLAG_QUALIFIER_MASK 0xffffff00000000 +#define ID_FLAG_QUALIFIER_MASK_R 0xaaaaaa00000000 #define IDEV_WIDGET_NONE 0 #define IDEV_WIDGET_BUTTON 1 @@ -110,19 +113,19 @@ struct inputevent { #define IDEV_MAPPED_INVERTTOGGLE 8 #define IDEV_MAPPED_GAMEPORTSCUSTOM1 16 #define IDEV_MAPPED_GAMEPORTSCUSTOM2 32 -#define IDEV_MAPPED_QUALIFIER1 0x00010000 -#define IDEV_MAPPED_QUALIFIER2 0x00020000 -#define IDEV_MAPPED_QUALIFIER3 0x00040000 -#define IDEV_MAPPED_QUALIFIER4 0x00080000 -#define IDEV_MAPPED_QUALIFIER5 0x00100000 -#define IDEV_MAPPED_QUALIFIER6 0x00200000 -#define IDEV_MAPPED_QUALIFIER7 0x00400000 -#define IDEV_MAPPED_QUALIFIER8 0x00800000 -#define IDEV_MAPPED_QUALIFIER_SPECIAL 0x01000000 -#define IDEV_MAPPED_QUALIFIER_SHIFT 0x02000000 -#define IDEV_MAPPED_QUALIFIER_CONTROL 0x04000000 -#define IDEV_MAPPED_QUALIFIER_ALT 0x08000000 -#define IDEV_MAPPED_QUALIFIER_MASK 0x0fff0000 +#define IDEV_MAPPED_QUALIFIER1 0x00000100000000 +#define IDEV_MAPPED_QUALIFIER2 0x00000400000000 +#define IDEV_MAPPED_QUALIFIER3 0x00001000000000 +#define IDEV_MAPPED_QUALIFIER4 0x00004000000000 +#define IDEV_MAPPED_QUALIFIER5 0x00010000000000 +#define IDEV_MAPPED_QUALIFIER6 0x00040000000000 +#define IDEV_MAPPED_QUALIFIER7 0x00100000000000 +#define IDEV_MAPPED_QUALIFIER8 0x00400000000000 +#define IDEV_MAPPED_QUALIFIER_SPECIAL 0x01000000000000 +#define IDEV_MAPPED_QUALIFIER_SHIFT 0x04000000000000 +#define IDEV_MAPPED_QUALIFIER_CONTROL 0x10000000000000 +#define IDEV_MAPPED_QUALIFIER_ALT 0x40000000000000 +#define IDEV_MAPPED_QUALIFIER_MASK 0xffffff00000000 #define ID_BUTTON_OFFSET 0 #define ID_BUTTON_TOTAL 32 @@ -130,9 +133,9 @@ struct inputevent { #define ID_AXIS_TOTAL 32 extern int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af); -extern bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, int flags, int port); -extern int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, int flags, int port, int sub); -extern int inputdevice_get_mapping (int devnum, int num, int *pflags, int *port, TCHAR *name, TCHAR *custom, int sub); +extern bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, uae_u64 flags, int port); +extern int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, uae_u64 flags, int port, int sub); +extern int inputdevice_get_mapping (int devnum, int num, uae_u64 *pflags, int *port, TCHAR *name, TCHAR *custom, int sub); extern void inputdevice_copyconfig (const struct uae_prefs *src, struct uae_prefs *dst); extern void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum, int selectedwidget); extern void inputdevice_swap_ports (struct uae_prefs *p, int devnum); @@ -253,7 +256,7 @@ extern void inputdevice_tablet (int x, int y, int z, extern void inputdevice_tablet_info (int maxx, int maxy, int maxz, int maxax, int maxay, int maxaz, int xres, int yres); extern void inputdevice_tablet_strobe (void); -extern int input_getqualifiers (void); +extern uae_u64 input_getqualifiers (void); extern void setsystime (void); diff --git a/include/options.h b/include/options.h index 9c348c9f..65a5c320 100644 --- a/include/options.h +++ b/include/options.h @@ -48,7 +48,7 @@ struct uae_input_device { TCHAR *configname; uae_s16 eventid[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; TCHAR *custom[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; - uae_u32 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; + uae_u64 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; uae_s8 port[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; uae_s16 extra[MAX_INPUT_DEVICE_EVENTS]; uae_s8 enabled; @@ -296,7 +296,7 @@ struct uae_prefs { int gfx_filter_autoscale; bool immediate_blits; - bool waiting_blits; + int waiting_blits; unsigned int chipset_mask; bool ntscmode; bool genlock; diff --git a/inputdevice.cpp b/inputdevice.cpp index 16d1c70b..6c7821f3 100644 --- a/inputdevice.cpp +++ b/inputdevice.cpp @@ -68,7 +68,7 @@ int inputdevice_logging = 0; #define ID_FLAG_CUSTOMEVENT_TOGGLED1 0x4000 #define ID_FLAG_CUSTOMEVENT_TOGGLED2 0x8000 -#define ID_FLAG_SAVE_MASK_CONFIG 0xff +#define ID_FLAG_SAVE_MASK_CONFIG 0x000000ff #define ID_FLAG_SAVE_MASK_QUALIFIERS ID_FLAG_QUALIFIER_MASK #define ID_FLAG_SAVE_MASK_FULL (ID_FLAG_SAVE_MASK_CONFIG | ID_FLAG_SAVE_MASK_QUALIFIERS) @@ -116,7 +116,8 @@ struct uae_input_device2 { static struct uae_input_device2 joysticks2[MAX_INPUT_DEVICES]; static struct uae_input_device2 mice2[MAX_INPUT_DEVICES]; static uae_u8 scancodeused[MAX_INPUT_DEVICES][256]; -static int qualifiers; +static uae_u64 qualifiers, qualifiers_r; +static uae_s16 *qualifiers_evt[MAX_INPUT_QUALIFIERS]; // fire/left mouse button pullup resistors enabled? static bool mouse_pullup = true; @@ -345,7 +346,7 @@ static bool write_config_head (struct zfile *f, int idnum, int devnum, TCHAR *na static bool write_slot (TCHAR *p, struct uae_input_device *uid, int i, int j) { bool ok = false; - int flags = uid->flags[i][j]; + uae_u64 flags = uid->flags[i][j]; if (uid->custom[i][j] && _tcslen (uid->custom[i][j]) > 0) { _stprintf (p, _T("'%s'.%d"), uid->custom[i][j], flags & ID_FLAG_SAVE_MASK_CONFIG); ok = true; @@ -358,9 +359,12 @@ static bool write_slot (TCHAR *p, struct uae_input_device *uid, int i, int j) if (ok && (flags & ID_FLAG_SAVE_MASK_QUALIFIERS)) { TCHAR *p2 = p + _tcslen (p); *p2++ = '.'; - for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) { + for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) { if ((ID_FLAG_QUALIFIER1 << i) & flags) { - _stprintf (p2, _T("%c"), 'A' + i); + if (i & 1) + _stprintf (p2, _T("%c"), 'a' + i / 2); + else + _stprintf (p2, _T("%c"), 'A' + i / 2); p2++; } } @@ -580,13 +584,23 @@ void write_inputdevice_config (struct uae_prefs *p, struct zfile *f) } } -static int getqual (const TCHAR **pp) +static uae_u64 getqual (const TCHAR **pp) { const TCHAR *p = *pp; - int mask = 0; + uae_u64 mask = 0; + + while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) { + bool press = (*p >= 'A' && *p <= 'Z'); + int shift, inc; - while (*p >= 'A' && *p <= 'Z') { - mask |= ID_FLAG_QUALIFIER1 << (*p - 'A'); + if (press) { + shift = *p - 'A'; + inc = 0; + } else { + shift = *p - 'a'; + inc = 1; + } + mask |= ID_FLAG_QUALIFIER1 << (shift * 2 + inc); p++; } while (*p != 0 && *p !='.' && *p != ',') @@ -747,7 +761,7 @@ static void inputdevice_default_kb_all (struct uae_prefs *p) inputdevice_default_kb (p, i); } -static bool read_slot (TCHAR *parm, int num, int joystick, int button, struct uae_input_device *id, int keynum, int subnum, struct inputevent *ie, int flags, int port, TCHAR *custom) +static bool read_slot (TCHAR *parm, int num, int joystick, int button, struct uae_input_device *id, int keynum, int subnum, struct inputevent *ie, uae_u64 flags, int port, TCHAR *custom) { int mask; @@ -989,7 +1003,8 @@ void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR * custom = NULL; for (subnum = 0; subnum < MAX_INPUT_SUB_EVENT; subnum++) { - int flags, port; + uae_u64 flags; + int port; xfree (custom); custom = NULL; p2 = getstring (&p); @@ -1001,7 +1016,7 @@ void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR * if (p[-1] == '.') flags = getnum (&p) & ID_FLAG_SAVE_MASK_CONFIG; if (p[-1] == '.') { - if (p[0] >= 'A' && p[0] <= 'Z') + if ((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) flags |= getqual (&p); if (p[-1] == '.') port = getnum (&p) + 1; @@ -1014,7 +1029,7 @@ void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR * int flags2 = 0; if (p[-1] == '.') flags2 = getnum (&p) & ID_FLAG_SAVE_MASK_CONFIG; - if (p[-1] == '.' && p[0] >= 'A' && p[0] <= 'Z') + if (p[-1] == '.' && (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) flags |= getqual (&p); TCHAR *custom2 = NULL; struct inputevent *ie2 = readevent (p2, &custom2); @@ -1834,6 +1849,11 @@ static void joymousecounter (int joy) else if (cnty == 0 && ocnty == 3) mouse_y[joy] += 4; mouse_y[joy] = (mouse_y[joy] & 0xfc) | cnty; + + if (!left || !right || !top || !bot) { + mouse_frame_x[joy] = mouse_x[joy]; + mouse_frame_y[joy] = mouse_y[joy]; + } } static uae_u16 getjoystate (int joy) @@ -2756,11 +2776,19 @@ end: } } -static int isqual (int evt) +static int getqualid (int evt) { if (evt > INPUTEVENT_SPC_QUALIFIER_START && evt < INPUTEVENT_SPC_QUALIFIER_END) - return ID_FLAG_QUALIFIER1 << (evt - INPUTEVENT_SPC_QUALIFIER1); - return 0; + return evt - INPUTEVENT_SPC_QUALIFIER1; + return -1; +} + +static uae_u64 isqual (int evt) +{ + int num = getqualid (evt); + if (num < 0) + return 0; + return ID_FLAG_QUALIFIER1 << (num * 2); } static int handle_input_event (int nr, int state, int max, int autofire, bool canstopplayback, bool playbackevent) @@ -2794,7 +2822,7 @@ static int handle_input_event (int nr, int state, int max, int autofire, bool ca } if ((inputdevice_logging & 1) || input_record || input_play) - write_log (_T("STATE=%05d MAX=%05d AF=%d QUAL=%08x '%s' \n"), state, max, autofire, qualifiers, ie->name); + write_log (_T("STATE=%05d MAX=%05d AF=%d QUAL=%06x '%s' \n"), state, max, autofire, (uae_u32)(qualifiers >> 32), ie->name); if (autofire) { if (state) queue_input_event (nr, NULL, state, max, currprefs.input_autofire_linecnt, 1); @@ -3304,26 +3332,62 @@ static int switchdevice (struct uae_input_device *id, int num, bool buttonmode) return 0; } -int input_getqualifiers (void) +uae_u64 input_getqualifiers (void) { return qualifiers; } -static bool checkqualifiers (int evt, int flags, int qualmask) +static bool checkqualifiers (int evt, uae_u64 flags, uae_u64 *qualmask, uae_s16 events[MAX_INPUT_SUB_EVENT_ALL]) { + int i, j; + int qualid = getqualid (evt); + int nomatch = 0; + flags &= ID_FLAG_QUALIFIER_MASK; + if (qualid >= 0 && events) + qualifiers_evt[qualid] = events; /* special set and new qualifier pressed? do not sent it to Amiga-side */ - if ((qualifiers & ID_FLAG_QUALIFIER_SPECIAL) && isqual (evt)) + if ((qualifiers & (ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SPECIAL_R)) && qualid >= 0) return false; - if (!qualmask) // no qualifiers in any slot - return true; - if (flags == qualifiers || (flags && flags == (qualifiers & ~ID_FLAG_QUALIFIER_SPECIAL))) - return true; - return false; + + for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) { + if (qualmask[i]) + break; + } + if (i == MAX_INPUT_SUB_EVENT) + return true; // no qualifiers in any slot = always match + + + for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) { + for (j = 0; j < MAX_INPUT_QUALIFIERS; j++) { + uae_u64 mask = (ID_FLAG_QUALIFIER1 | ID_FLAG_QUALIFIER1_R) << (j * 2); + bool isqualmask = (qualmask[i] & mask) != 0; + bool isqual = ((qualifiers & ~(ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SPECIAL_R)) & mask) != 0; + if (isqualmask != isqual) { + nomatch++; + break; + } + } + } + if (nomatch == MAX_INPUT_SUB_EVENT) { + // no matched qualifiers in any slot + // allow all slots without qualifiers + return flags ? false : true; + } + + for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) { + uae_u64 mask = (ID_FLAG_QUALIFIER1 | ID_FLAG_QUALIFIER1_R) << (i * 2); + bool isflags = (flags & mask) != 0; + bool isqual = (qualifiers & mask) != 0; + if (isflags != isqual) + return false; + } + return true; } + static void setqualifiers (int evt, int state) { - int mask = isqual (evt); + uae_u64 mask = isqual (evt); if (!mask) return; if (state) @@ -3331,12 +3395,14 @@ static void setqualifiers (int evt, int state) else qualifiers &= ~mask; } -static int getqualmask (struct uae_input_device *id, int num, bool *qualonly) + +static uae_u64 getqualmask (uae_u64 *qualmask, struct uae_input_device *id, int num, bool *qualonly) { - int mask = 0, mask2 = 0; + uae_u64 mask = 0, mask2 = 0; for (int i = 0; i < MAX_INPUT_SUB_EVENT; i++) { int evt = id->eventid[num][i]; mask |= id->flags[num][i]; + qualmask[i] = id->flags[num][i] & ID_FLAG_QUALIFIER_MASK; mask2 |= isqual (evt); } mask &= ID_FLAG_QUALIFIER_MASK; @@ -3349,10 +3415,11 @@ static int getqualmask (struct uae_input_device *id, int num, bool *qualonly) } -static bool process_custom_event (struct uae_input_device *id, int offset, int state, int qualmask, int autofire, int sub) +static bool process_custom_event (struct uae_input_device *id, int offset, int state, uae_u64 *qualmask, int autofire, int sub) { - int idx, slotoffset, flags, custompos, qual; + int idx, slotoffset, custompos; TCHAR *custom; + uae_u64 flags, qual; if (!id) return false; @@ -3367,7 +3434,7 @@ static bool process_custom_event (struct uae_input_device *id, int offset, int s (id->custom[offset][slotoffset] == NULL && id->custom[offset][slotoffset + 2] == NULL) || (id->flags[offset][slotoffset + 2] & ID_FLAG_AUTOFIRE_MASK) || (af & ID_FLAG_AUTOFIRE_MASK)) { id->flags[offset][slotoffset] &= ~(ID_FLAG_CUSTOMEVENT_TOGGLED1 | ID_FLAG_CUSTOMEVENT_TOGGLED2); - if (checkqualifiers (id->eventid[offset][slotoffset + sub], id->flags[offset][slotoffset + sub], qualmask)) { + if (checkqualifiers (id->eventid[offset][slotoffset + sub], id->flags[offset][slotoffset + sub], qualmask, NULL)) { custom = id->custom[offset][slotoffset + sub]; if (state && custom) { if (autofire) @@ -3383,9 +3450,9 @@ static bool process_custom_event (struct uae_input_device *id, int offset, int s return false; slotoffset = 0; - if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask)) { + if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask, NULL)) { slotoffset = 4; - if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask)) + if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask, NULL)) return false; } @@ -3432,7 +3499,7 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev uae_u32 mask = 1 << button; uae_u32 omask = id2 ? id2->buttonmask & mask : 0; uae_u32 nmask = (state ? 1 : 0) << button; - int qualmask; + uae_u64 qualmask[MAX_INPUT_SUB_EVENT]; bool qualonly; if (input_play && state) @@ -3454,14 +3521,14 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev if (button >= ID_BUTTON_TOTAL) return; - qualmask = getqualmask (id, ID_BUTTON_OFFSET + button, &qualonly); + getqualmask (qualmask, id, ID_BUTTON_OFFSET + button, &qualonly); bool didcustom = false; for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) { - uae_u32 *flagsp = &id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]]; - int evt = evt = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]]; - int flags = flagsp[0]; + uae_u64 *flagsp = &id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]]; + int evt = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]]; + uae_u64 flags = flagsp[0]; int autofire = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0; int toggle = (flags & ID_FLAG_TOGGLE) ? 1 : 0; int inverttoggle = (flags & ID_FLAG_INVERTTOGGLE) ? 1 : 0; @@ -3470,12 +3537,12 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, state, qualmask, autofire, i); } - setqualifiers (flags, state > 0); + setqualifiers (evt, state > 0); if (qualonly) continue; if (state < 0) { - if (!checkqualifiers (evt, flags, qualmask)) + if (!checkqualifiers (evt, flags, qualmask, NULL)) continue; handle_input_event (evt, 1, 1, 0, true, false); queue_input_event (evt, NULL, 0, 1, 1, 0); /* send release event next frame */ @@ -3494,14 +3561,14 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev continue; if (omask & mask) continue; - if (!checkqualifiers (evt, flags, qualmask)) + if (!checkqualifiers (evt, flags, qualmask, NULL)) continue; *flagsp ^= ID_FLAG_TOGGLED; int toggled = (*flagsp & ID_FLAG_TOGGLED) ? 1 : 0; handle_input_event (evt, toggled, 1, autofire, true, false); didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, toggled, qualmask, autofire, i); } else { - if (!checkqualifiers (evt, flags, qualmask)) { + if (!checkqualifiers (evt, flags, qualmask, NULL)) { if (!state && !(flags & ID_FLAG_CANRELEASE)) { continue; } else if (state) { @@ -4751,7 +4818,7 @@ static void matchdevices_all (struct uae_prefs *prefs) } } -bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, int flags, int port) +bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, uae_u64 flags, int port) { TCHAR name[256]; struct inputevent *ie; @@ -4779,7 +4846,8 @@ bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int keyboards = prefs->keyboard_settings[prefs->input_selected_setting]; if (prefs->input_selected_setting != GAMEPORT_INPUT_SETTINGS) { - int xflags, xport; + int xport; + uae_u64 xflags; TCHAR xname[MAX_DPATH], xcustom[MAX_DPATH]; inputdevice_get_mapping (devnum, num, &xflags, &xport, xname, xcustom, 0); if (xport == 0) @@ -5002,6 +5070,39 @@ int inputdevice_synccapslock (int oldcaps, int *capstable) return -1; } +static void rqualifiers (uae_u64 flags, bool release) +{ + uae_u64 mask = ID_FLAG_QUALIFIER1 << 1; + for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) { + if ((flags & mask) && (mask & (qualifiers << 1))) { + if (release) { + if (!(mask & qualifiers_r)) { + qualifiers_r |= mask; + for (int ii = 0; ii < MAX_INPUT_SUB_EVENT; ii++) { + int qevt = qualifiers_evt[i][ii]; + if (qevt > 0) { + write_log (_T("Released %d '%s'\n"), qevt, events[qevt].name); + inputdevice_do_keyboard (events[qevt].data, 0); + } + } + } + } else { + if ((mask & qualifiers_r)) { + qualifiers_r &= ~mask; + for (int ii = 0; ii < MAX_INPUT_SUB_EVENT; ii++) { + int qevt = qualifiers_evt[i][ii]; + if (qevt > 0) { + write_log (_T("Pressed %d '%s'\n"), qevt, events[qevt].name); + inputdevice_do_keyboard (events[qevt].data, 1); + } + } + } + } + } + mask <<= 2; + } +} + static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state, bool qualifiercheckonly) { struct uae_input_device *na = &keyboards[keyboard]; @@ -5019,13 +5120,15 @@ static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state while (j < MAX_INPUT_DEVICE_EVENTS && na->extra[j] >= 0) { if (na->extra[j] == scancode) { bool qualonly; - int qualmask = getqualmask (na, j, &qualonly); + uae_u64 qualmask[MAX_INPUT_SUB_EVENT]; + getqualmask (qualmask, na, j, &qualonly); + if (qualonly) qualifiercheckonly = true; for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {/* send key release events in reverse order */ - uae_u32 *flagsp = &na->flags[j][sublevdir[state == 0 ? 1 : 0][k]]; + uae_u64 *flagsp = &na->flags[j][sublevdir[state == 0 ? 1 : 0][k]]; int evt = na->eventid[j][sublevdir[state == 0 ? 1 : 0][k]]; - int flags = *flagsp; + uae_u64 flags = *flagsp; int autofire = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0; int toggle = (flags & ID_FLAG_TOGGLE) ? 1 : 0; int inverttoggle = (flags & ID_FLAG_INVERTTOGGLE) ? 1 : 0; @@ -5066,7 +5169,7 @@ static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state } else if (toggle) { if (!state) continue; - if (!checkqualifiers (evt, flags, qualmask)) + if (!checkqualifiers (evt, flags, qualmask, na->eventid[j])) continue; *flagsp ^= ID_FLAG_TOGGLED; toggled = (*flagsp & ID_FLAG_TOGGLED) ? 1 : 0; @@ -5074,12 +5177,14 @@ static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state if (k == 0) didcustom |= process_custom_event (na, j, state, qualmask, autofire, k); } else { - if (!checkqualifiers (evt, flags, qualmask)) { + rqualifiers (flags, state ? true : false); + if (!checkqualifiers (evt, flags, qualmask, na->eventid[j])) { if (!state && !(flags & ID_FLAG_CANRELEASE)) continue; else if (state) continue; } + if (state) *flagsp |= ID_FLAG_CANRELEASE; else @@ -5244,7 +5349,7 @@ static struct uae_input_device *get_uid (const struct inputdevice_functions *id, return uid; } -static int get_event_data (const struct inputdevice_functions *id, int devnum, int num, int *eventid, TCHAR **custom, int *flags, int *port, int sub) +static int get_event_data (const struct inputdevice_functions *id, int devnum, int num, int *eventid, TCHAR **custom, uae_u64 *flags, int *port, int sub) { const struct uae_input_device *uid = get_uid (id, devnum); int type = id->get_widget_type (devnum, num, 0, 0); @@ -5295,12 +5400,19 @@ static TCHAR *stripstrdup (const TCHAR *s) return out; } -static int put_event_data (const struct inputdevice_functions *id, int devnum, int num, int eventid, TCHAR *custom, int flags, int port, int sub) +static int put_event_data (const struct inputdevice_functions *id, int devnum, int num, int eventid, TCHAR *custom, uae_u64 flags, int port, int sub) { struct uae_input_device *uid = get_uid (id, devnum); int type = id->get_widget_type (devnum, num, 0, 0); int i, ret; + for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) { + uae_u64 mask1 = ID_FLAG_QUALIFIER1 << (i * 2); + uae_u64 mask2 = mask1 << 1; + if ((flags & (mask1 | mask2)) == (mask1 | mask2)) + flags &= ~mask2; + } + ret = -1; if (type == IDEV_WIDGET_BUTTON || type == IDEV_WIDGET_BUTTONAXIS) { i = num - id->get_widget_first (devnum, IDEV_WIDGET_BUTTON) + ID_BUTTON_OFFSET; @@ -5484,7 +5596,8 @@ int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af) const struct inputdevice_functions *idf = getidf (devnum); static int id_iterator; struct inputevent *ie; - int mask, data, flags, type; + int mask, data, type; + uae_u64 flags; int devindex = inputdevice_get_device_index (devnum); *af = 0; @@ -5536,11 +5649,12 @@ int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af) } // return mapped event from devnum/num/sub -int inputdevice_get_mapping (int devnum, int num, int *pflags, int *pport, TCHAR *name, TCHAR *custom, int sub) +int inputdevice_get_mapping (int devnum, int num, uae_u64 *pflags, int *pport, TCHAR *name, TCHAR *custom, int sub) { const struct inputdevice_functions *idf = getidf (devnum); const struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); - int flags = 0, flag, port, data; + int port, data; + uae_u64 flags = 0, flag; int devindex = inputdevice_get_device_index (devnum); TCHAR *customp = NULL; @@ -5585,11 +5699,12 @@ int inputdevice_get_mapping (int devnum, int num, int *pflags, int *pport, TCHAR } // set event name/custom/flags to devnum/num/sub -int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, int flags, int port, int sub) +int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, uae_u64 flags, int port, int sub) { const struct inputdevice_functions *idf = getidf (devnum); const struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); - int eid, data, flag, portp, amask; + int eid, data, portp, amask; + uae_u64 flag; TCHAR ename[256]; int devindex = inputdevice_get_device_index (devnum); TCHAR *customp = NULL; diff --git a/od-win32/keyboard_win32.cpp b/od-win32/keyboard_win32.cpp index 5db2a20a..16286797 100644 --- a/od-win32/keyboard_win32.cpp +++ b/od-win32/keyboard_win32.cpp @@ -326,21 +326,21 @@ static int *kbmaps[] = { kb_xa1, kb_xa2, kb_arcadia, kb_arcadiaxa, kb_cdtv }; -static int specialpressed (void) +static bool specialpressed (void) { - return input_getqualifiers () & ID_FLAG_QUALIFIER_SPECIAL; + return (input_getqualifiers () & ID_FLAG_QUALIFIER_SPECIAL) != 0; } -static int shiftpressed (void) +static bool shiftpressed (void) { - return input_getqualifiers () & ID_FLAG_QUALIFIER_SHIFT; + return (input_getqualifiers () & ID_FLAG_QUALIFIER_SHIFT) != 0; } -static int altpressed (void) +static bool altpressed (void) { - return input_getqualifiers () & ID_FLAG_QUALIFIER_ALT; + return (input_getqualifiers () & ID_FLAG_QUALIFIER_ALT) != 0; } -static int ctrlpressed (void) +static bool ctrlpressed (void) { - return input_getqualifiers () & ID_FLAG_QUALIFIER_CONTROL; + return (input_getqualifiers () & ID_FLAG_QUALIFIER_CONTROL) != 0; } static int capslockstate; diff --git a/od-win32/resources/resource b/od-win32/resources/resource index 4314520e..54d07991 100644 --- a/od-win32/resources/resource +++ b/od-win32/resources/resource @@ -425,7 +425,6 @@ #define IDC_MBRAM2 1051 #define IDC_Z3CHIPMEM 1052 #define IDC_Z3CHIPRAM 1053 -#define IDC_Z3CHIPRAM2 1054 #define IDC_MAX32RAM 1054 #define IDC_UAEHOME 1070 #define IDC_PICASSOHOME 1071 @@ -443,6 +442,8 @@ #define IDC_CONTRIBUTORS 1124 #define IDC_BLACKER_THAN_BLACK 1170 #define IDC_BLITIMM 1174 +#define IDC_BLITIMM2 1175 +#define IDC_BLITWAIT 1175 #define IDC_LORES 1176 #define IDC_RATE2BOX 1177 #define IDC_LORES_SMOOTHED 1179 diff --git a/od-win32/resources/winuae.rc b/od-win32/resources/winuae.rc index 69657767..47e0246e 100644 --- a/od-win32/resources/winuae.rc +++ b/od-win32/resources/winuae.rc @@ -605,9 +605,9 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,100,58,50,10 GROUPBOX "Options",IDC_STATIC,168,11,114,111 CONTROL "Immediate Blitter [] Faster but less compatible blitter emulation.",IDC_BLITIMM, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,33,96,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,27,96,10 CONTROL "Cycle-exact [] The most compatible A500 emulation mode. Very fast PC recommended.",IDC_CYCLEEXACT, - "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,46,100,10 + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,53,100,10 GROUPBOX "Collision Level",IDC_STATIC,14,128,267,48 CONTROL "None [] Collision hardware emulation disabled.",IDC_COLLISION0, "Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,37,144,59,10 @@ -618,11 +618,13 @@ BEGIN CONTROL "Full [] 100% collision hardware emulation. Only very few games need this option. Slowest.",IDC_COLLISION3, "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,100,160,119,10 CONTROL "Genlock connected [] Allow boot sequence to detect genlock. Genlock is not emulated.",IDC_GENLOCK, - "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,59,100,10 + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,66,100,10 COMBOBOX IDC_CS_EXT,100,80,49,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP RTEXT "Chipset Extra",IDC_STATIC,25,79,52,15,SS_CENTERIMAGE - COMBOBOX IDC_MONITOREMU,178,99,98,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - RTEXT "External display hardware:",IDC_STATIC,174,78,100,15,SS_CENTERIMAGE + COMBOBOX IDC_MONITOREMU,178,102,98,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + RTEXT "External display hardware:",IDC_STATIC,174,82,100,15,SS_CENTERIMAGE + CONTROL "Wait for Blitter [] Pauses the CPU if blitter is active and CPU attempted to modify blitter registers.",IDC_BLITWAIT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,40,96,10 END IDD_CHIPSET2 DIALOGEX 0, 65490, 300, 247 diff --git a/od-win32/rp.cpp b/od-win32/rp.cpp index 5931cd0c..20b4e531 100644 --- a/od-win32/rp.cpp +++ b/od-win32/rp.cpp @@ -239,7 +239,8 @@ bool port_get_custom (int inputmap_port, TCHAR *out) for (int i = 0; eventorder[i]; i++) { int evtnum = events[i]; for (int j = 0; j < inputdevicefunc_keyboard.get_widget_num (kbnum); j++) { - int flags, port; + int port; + uae_u64 flags; if (inputdevice_get_mapping (kb + kbnum, j, &flags, &port, NULL, NULL, 0) == evtnum) { if (port == inputmap_port + 1) { uae_u32 kc = 0; diff --git a/od-win32/win32.h b/od-win32/win32.h index d5a2737d..579fcefb 100644 --- a/od-win32/win32.h +++ b/od-win32/win32.h @@ -19,8 +19,8 @@ #define LANG_DLL 1 //#define WINUAEBETA _T("") -#define WINUAEBETA _T("9") -#define WINUAEDATE MAKEBD(2012, 8, 1) +#define WINUAEBETA _T("10") +#define WINUAEDATE MAKEBD(2012, 8, 6) #define WINUAEEXTRA _T("") //#define WINUAEEXTRA _T("AmiKit Preview") #define WINUAEREV _T("") diff --git a/od-win32/win32_scaler.cpp b/od-win32/win32_scaler.cpp index a5774283..46acb13e 100644 --- a/od-win32/win32_scaler.cpp +++ b/od-win32/win32_scaler.cpp @@ -229,7 +229,7 @@ void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height } } - set_custom_limits (-1, -1, -1, -1); + bool scl = false; if (scalemode) { int cw, ch, cx, cy, cv; @@ -258,6 +258,7 @@ void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height ch -= 25 << currprefs.gfx_vresolution; } set_custom_limits (cw, ch, cx, cy); + scl = true; } if (scalemode == AUTOSCALE_INTEGER || scalemode == AUTOSCALE_INTEGER_AUTOSCALE) { @@ -321,19 +322,29 @@ void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height getmanualpos (&cx, &cy, &cw, &ch); set_custom_limits (cw, ch, cx, cy); + scl = true; //write_log (_T("%dx%d %dx%d %dx%d\n"), currprefs.gfx_xcenter_pos, currprefs.gfx_ycenter_pos, cx, cy, cw, ch); cv = 1; + } else if (scalemode == AUTOSCALE_CENTER || scalemode == AUTOSCALE_RESIZE) { + + cv = get_custom_limits (&cw, &ch, &cx, &cy); + } else { cv = get_custom_limits (&cw, &ch, &cx, &cy); - if (cv) + if (cv) { set_custom_limits (cw, ch, cx, cy); + scl = true; + } } + if (!scl) + set_custom_limits (-1, -1, -1, -1); + if (currprefs.gfx_api == 0) { if (cx < 0) cx = 0; diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index c7895b09..ac4d77bd 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -3327,32 +3327,43 @@ static int input_selected_device, input_selected_widget, input_total_devices; static int input_selected_event, input_selected_sub_num; static int input_copy_from; -static void getqualifiername (TCHAR *p, int mask) +static void getqualifiername (TCHAR *p, uae_u64 mask) { - int i, j; *p = 0; if (mask == IDEV_MAPPED_QUALIFIER_SPECIAL) { _tcscpy (p, _T("*")); + } else if (mask == (IDEV_MAPPED_QUALIFIER_SPECIAL << 1)) { + _tcscpy (p, _T("* [R]")); } else if (mask == IDEV_MAPPED_QUALIFIER_SHIFT) { _tcscpy (p, _T("Shift")); + } else if (mask == (IDEV_MAPPED_QUALIFIER_SHIFT << 1)) { + _tcscpy (p, _T("Shift [R]")); } else if (mask == IDEV_MAPPED_QUALIFIER_CONTROL) { _tcscpy (p, _T("Ctrl")); + } else if (mask == (IDEV_MAPPED_QUALIFIER_CONTROL << 1)) { + _tcscpy (p, _T("Ctrl [R]")); } else if (mask == IDEV_MAPPED_QUALIFIER_ALT) { _tcscpy (p, _T("Alt")); + } else if (mask == (IDEV_MAPPED_QUALIFIER_ALT << 1)) { + _tcscpy (p, _T("Alt [R]")); } else { - for (i = IDEV_MAPPED_QUALIFIER1, j = 0; i <= IDEV_MAPPED_QUALIFIER8; i <<= 1, j++) { - if (i == mask) - _stprintf (p, _T("%d"), j + 1); + int j; + uae_u64 i; + for (i = IDEV_MAPPED_QUALIFIER1, j = 0; i <= (IDEV_MAPPED_QUALIFIER8 << 1); i <<= 1, j++) { + if (i == mask) { + _stprintf (p, _T("%d%s"), j / 2 + 1, (j & 1) ? _T(" [R]") : _T("")); + } } } } static void set_lventry_input (HWND list, int index) { - int flags, i, sub, port; + int i, sub, port; TCHAR name[256]; TCHAR custom[MAX_DPATH]; TCHAR af[32], toggle[32]; + uae_u64 flags; inputdevice_get_mapping (input_selected_device, index, &flags, &port, name, custom, input_selected_sub_num); if (flags & IDEV_MAPPED_AUTOFIRE_SET) { @@ -3383,8 +3394,8 @@ static void set_lventry_input (HWND list, int index) if (flags & IDEV_MAPPED_QUALIFIER_MASK) { TCHAR *p; p = name; - for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) { - int mask = IDEV_MAPPED_QUALIFIER1 << i; + for (i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) { + uae_u64 mask = IDEV_MAPPED_QUALIFIER1 << i; if (flags & mask) { if (p != name) *p++ = ','; @@ -3430,12 +3441,13 @@ static int inputmap_handle (HWND list, int currentdevnum, int currentwidgetnum, struct inputevent *evt = inputdevice_get_eventinfo (evtnum); LV_ITEM lvstruct; int devnum; - int flags, status; + int status; TCHAR name[256]; int *atp = axistable; int atpidx; int item; bool found = false; + uae_u64 flags; if (list) { LVGROUP group; @@ -6264,6 +6276,7 @@ static void values_to_chipsetdlg (HWND hDlg) CheckDlgButton (hDlg, IDC_NTSC, workprefs.ntscmode); CheckDlgButton (hDlg, IDC_GENLOCK, workprefs.genlock); CheckDlgButton (hDlg, IDC_BLITIMM, workprefs.immediate_blits); + CheckDlgButton (hDlg, IDC_BLITWAIT, workprefs.waiting_blits); CheckRadioButton (hDlg, IDC_COLLISION0, IDC_COLLISION3, IDC_COLLISION0 + workprefs.collision_level); CheckDlgButton (hDlg, IDC_CYCLEEXACT, workprefs.cpu_cycle_exact); SendDlgItemMessage (hDlg, IDC_CS_EXT, CB_SETCURSEL, workprefs.cs_compatible, 0); @@ -6279,6 +6292,7 @@ static void values_from_chipsetdlg (HWND hDlg, UINT msg, WPARAM wParam, LPARAM l workprefs.genlock = ischecked (hDlg, IDC_GENLOCK); workprefs.immediate_blits = ischecked (hDlg, IDC_BLITIMM); + workprefs.waiting_blits = ischecked (hDlg, IDC_BLITWAIT) ? 1 : 0; n = ischecked (hDlg, IDC_CYCLEEXACT); if (workprefs.cpu_cycle_exact != n) { workprefs.cpu_cycle_exact = workprefs.blitter_cycle_exact = n; @@ -11761,7 +11775,8 @@ static void clearinputlistview (HWND hDlg) static void doinputcustom (HWND hDlg, int newcustom) { TCHAR custom1[MAX_DPATH]; - int flags; + uae_u64 flags; + custom1[0] = 0; inputdevice_get_mapping (input_selected_device, input_selected_widget, &flags, NULL, NULL, custom1, input_selected_sub_num); @@ -11843,7 +11858,7 @@ static void values_from_inputdlg (HWND hDlg, int inputchange) } if (inputchange && doselect && input_selected_device >= 0 && input_selected_event >= 0) { - int flags; + uae_u64 flags; bool iscustom = false; TCHAR custom[MAX_DPATH]; @@ -12320,9 +12335,11 @@ static void handlerawinput (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) static void input_toggleautofire (void) { - int flags, evt; + int evt; + uae_u64 flags; TCHAR name[256]; TCHAR custom[MAX_DPATH]; + if (input_selected_device < 0 || input_selected_widget < 0) return; evt = inputdevice_get_mapping (input_selected_device, input_selected_widget, @@ -12370,11 +12387,12 @@ static int genericpopupmenu (HWND hwnd, TCHAR **items, int *flags, int num) static void input_qualifiers (HWND hDlg) { - int flags, evt, item; + uae_u64 flags; + int evt, item; TCHAR name[256]; TCHAR custom[MAX_DPATH]; - TCHAR *names[MAX_INPUT_QUALIFIERS]; - int mflags[MAX_INPUT_QUALIFIERS]; + TCHAR *names[MAX_INPUT_QUALIFIERS * 2]; + int mflags[MAX_INPUT_QUALIFIERS * 2]; TCHAR tmp[MAX_DPATH]; if (input_selected_device < 0 || input_selected_widget < 0) @@ -12384,29 +12402,31 @@ static void input_qualifiers (HWND hDlg) if (evt <= 0) name[0] = 0; - for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) { + for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) { getqualifiername (tmp, IDEV_MAPPED_QUALIFIER1 << i); mflags[i] = 0; if (flags & (IDEV_MAPPED_QUALIFIER1 << i)) mflags[i] = 1; names[i] = my_strdup (tmp); } - item = genericpopupmenu (hDlg, names, mflags, MAX_INPUT_QUALIFIERS); + item = genericpopupmenu (hDlg, names, mflags, MAX_INPUT_QUALIFIERS * 2); if (item >= 0) flags ^= IDEV_MAPPED_QUALIFIER1 << item; inputdevice_set_mapping (input_selected_device, input_selected_widget, name, custom, flags, -1, input_selected_sub_num); - for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) { + for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) { xfree (names[i]); } } static void input_toggletoggle (void) { - int flags, evt; + int evt; + uae_u64 flags; TCHAR name[256]; TCHAR custom[MAX_DPATH]; + if (input_selected_device < 0 || input_selected_widget < 0) return; evt = inputdevice_get_mapping (input_selected_device, input_selected_widget, diff --git a/od-win32/winuaechangelog.txt b/od-win32/winuaechangelog.txt index 3d47a0f5..2e11a298 100644 --- a/od-win32/winuaechangelog.txt +++ b/od-win32/winuaechangelog.txt @@ -1,6 +1,27 @@ - restore only single input target to default. +Beta 10: + +- BPLxDAT CPU/Copper writes are now accurately emulated. (Blerkenwiegel/Scoopex) +- COPJMPx triggered second cycle is special, does not need to be free but if it is free, it is allocated for copper. + (EyeQlazer/Scoopex is now 100% correct) +- Emulate copper waiting + CPU write to COPJMPx slightly different copper cycle usage. +- Fixed chipset emulation infinite loop if program crashed and wrote totally bogus values to programmable display + refresh rate registers. +- Both mouse and joystick enabled in same port: moving joystick does not cause mouse big cursor jumps anymore. +- Automatic center option incorrectly set display limits to autoscale limits (black borders). +- "Release" key qualifier support. When [R] qualifier is selected, qualifier key is released before sending mapped + keycode and then immediately pressed again. Qualifier selection GUI is currently ugly. +- Modified Input Qualifier support, now non-matched qualifier combinations (one or more qualifiers pressed but no + match in any 8 slots) always trigger non-qualifier input target(s), previously nothing was triggered. +- Added "Wait for Blitter" GUI option, when enabled, CPU is paused if blitter is active and CPU attempted to modify + blitter registers. Previously was always enabled if fastest possible CPU (and still is), now it can be manually + enabled in other modes, can be useful when running 68020/AGA programs that run badly in non-ce modes but also have + some display problems in ce modes. (because of not accurate enough CPU speed) +- Fixed flickering graphics corruption in some programs (for example Disposable Hero), also could have caused + reduced performance. (b1 display limit feature) + Beta 9: - Replaced readpu.c 68020+ special case TST An/PC-rel and CMP #imm,PC-rel variants with proper table68k entries.