Annotation of uae/src/drawing.c, revision 1.1.1.8

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.