--- uae/src/drawing.c 2018/04/24 16:58:25 1.1.1.12 +++ uae/src/drawing.c 2018/04/24 17:02:03 1.1.1.14 @@ -5,6 +5,7 @@ * * Copyright 1995-2000 Bernd Schmidt * Copyright 1995 Alessandro Bissacco + * Copyright 2000,2001 Toni Wilen */ /* There are a couple of concepts of "coordinates" in this file. @@ -33,7 +34,7 @@ #include "config.h" #include "options.h" -#include "threaddep/penguin.h" +#include "threaddep/thread.h" #include "uae.h" #include "memory.h" #include "custom.h" @@ -43,6 +44,7 @@ #include "gui.h" #include "picasso96.h" #include "drawing.h" +#include "savestate.h" int lores_factor, lores_shift; @@ -68,7 +70,6 @@ static int dblpf_ind1[256], dblpf_ind2[2 static int dblpf_2nd1[256], dblpf_2nd2[256]; static int dblpf_ind1_aga[256], dblpf_ind2_aga[256]; - static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 }; static int sprite_offs[256]; @@ -94,17 +95,17 @@ union { /* Let's try to align this thing. */ double uupzuq; long int cruxmedo; - uae_u8 apixels[MAX_PIXELS_PER_LINE*2]; - uae_u16 apixels_w[MAX_PIXELS_PER_LINE*2/2]; - uae_u32 apixels_l[MAX_PIXELS_PER_LINE*2/4]; + uae_u8 apixels[MAX_PIXELS_PER_LINE * 2]; + uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / 2]; + uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / 4]; } pixdata; uae_u16 spixels[2 * MAX_SPR_PIXELS]; /* Eight bits for every pixel. */ union sps_union spixstate; -static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE]; -static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE]; /* AGA dualplayfield sprite */ +static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2]; +static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE * 2]; /* AGA dualplayfield sprite */ char *xlinebuffer; @@ -151,7 +152,7 @@ static int first_block_line, last_block_ /* These are generated by the drawing code from the line_decisions array for each line that needs to be drawn. These are basically extracted out of bit fields in the hardware registers. */ -static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, bplres, sprres; +static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, bplres; static uae_u32 plf_sprite_mask; static int sbasecol[2]; @@ -501,9 +502,7 @@ static void pfield_do_linetoscr (int sta } else abort (); - } else { - if (res_shift == 0) switch (gfxvidinfo.pixbytes) { case 1: src_pixel = linetoscr_8 (src_pixel, start, stop); break; @@ -604,7 +603,7 @@ static void init_ham_decoding (void) static void decode_ham (int pix, int stoppos) { int todraw_amiga = res_shift_from_window (stoppos - pix); - if (!bplham || (bplplanecnt != 6 && bplplanecnt != 8)) + if (!bplham) abort (); if (currprefs.chipset_mask & CSMASK_AGA) { @@ -688,28 +687,36 @@ static void gen_pfield_tables (void) what an optimizing compiler will do with this code. All callers of this function only pass in constant arguments (except for E). This means that many of the if statements will go away completely after inlining. */ -STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int ham, int dualpf, int shift, int has_attach) +STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int ham, int dualpf, + int doubling, int skip, int has_attach, int aga) { int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; uae_u16 *buf = spixels + e->first_pixel; uae_u8 *stbuf = spixstate.bytes + e->first_pixel; - int pos, last; + int pos, window_pos; + uae_u8 xor_val = (uae_u8)(dp_for_drawing->bplcon4 >> 8); buf -= e->pos; stbuf -= e->pos; - for (pos = e->pos; pos < e->max; pos++) { + window_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (aga ? 1 : 0)); + if (skip) + window_pos >>= 1; + else if (doubling) + window_pos <<= 1; + window_pos += pixels_offset; + for (pos = e->pos; pos < e->max; pos += 1 << skip) { int maskshift, plfmask; unsigned int v = buf[pos]; /* The value in the shift lookup table is _half_ the shift count we need. This is because we can't shift 32 bits at once (undefined behaviour in C). */ - maskshift = shift_lookup[pixdata.apixels[(pos << shift) + pixels_offset]]; + maskshift = shift_lookup[pixdata.apixels[window_pos]]; plfmask = (plf_sprite_mask >> maskshift) >> maskshift; v &= ~plfmask; if (v != 0) { - unsigned int vlo, vhi, col, col_off; + unsigned int vlo, vhi, col; unsigned int v1 = v & 255; /* OFFS determines the sprite pair with the highest priority that has any bits set. E.g. if we have 0xFF00 in the buffer, we have sprite @@ -729,6 +736,10 @@ STATIC_INLINE void draw_sprites_1 (struc if (has_attach && (stbuf[pos] & (1 << offs))) { col = v; + if (aga) + col += sbasecol[1]; + else + col += 16; } else { /* This sequence computes the correct color value. We have to select either the lower-numbered or the higher-numbered sprite in the pair. @@ -741,42 +752,78 @@ STATIC_INLINE void draw_sprites_1 (struc This is _probably_ more efficient than doing it with branches. */ vlo = v & 3; vhi = (v & (vlo - 1)) >> 2; - col = vlo | vhi; + col = (vlo | vhi); + if (aga) { + if (vhi > 0) + col += sbasecol[1]; + else + col += sbasecol[0]; + } else { + col += 16; + } col += (offs * 2); } - col += dualpf ? 128 + 16 : 16; - if (ham) { - col = color_reg_get (&colors_for_drawing, col); - ham_linebuf[(pos << shift) + pixels_offset] = col; - if (shift == 1) { - ham_linebuf[(pos << shift) + pixels_offset + 1] = col; + if (dualpf) { + if (aga) { + spriteagadpfpixels[window_pos] = col; + if (doubling) + spriteagadpfpixels[window_pos + 1] = col; + } else { + col += 128; + if (doubling) + pixdata.apixels_w[window_pos >> 1] = col | (col << 8); + else + pixdata.apixels[window_pos] = col; } + } else if (ham) { + col = color_reg_get (&colors_for_drawing, col); + if (aga) + col ^= xor_val; + ham_linebuf[window_pos] = col; + if (doubling) + ham_linebuf[window_pos + 1] = col; } else { - if (shift == 1) - pixdata.apixels_w[pos + (pixels_offset >> 1)] = col | (col << 8); + if (aga) + col ^= xor_val; + if (doubling) + pixdata.apixels_w[window_pos >> 1] = col | (col << 8); else - pixdata.apixels[(pos << shift) + pixels_offset] = col; + pixdata.apixels[window_pos] = col; } } + window_pos += 1 << doubling; } } /* See comments above. Do not touch if you don't know what's going on. * (We do _not_ want the following to be inlined themselves). */ -static void draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0); } -static void draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0); } -static void draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0); } -static void draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0); } -static void draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0); } -static void draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0); } -static void draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 1); } -static void draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 1); } -static void draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 1); } -static void draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 1); } -static void draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 1); } -static void draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 1); } +/* lores bitplane, lores sprites */ +static void draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 0, 0); } +static void draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 0, 0); } +static void draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 0, 0); } +static void draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 1, 0); } +static void draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 1, 0); } +static void draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 1, 0); } +/* hires bitplane, lores sprites */ +static void draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 0, 0); } +static void draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 0, 0); } +static void draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 0, 0); } +static void draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 1, 0); } +static void draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 1, 0); } +static void draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 1, 0); } + +/* not very optimized */ +STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e) +{ + int diff = RES_HIRES - bplres; + if (diff > 0) + draw_sprites_1 (e, bplham, bpldualpf, 0, diff, e->has_attached, 1); + else + draw_sprites_1 (e, bplham, bpldualpf, -diff, 0, e->has_attached, 1); +} -STATIC_INLINE void draw_sprites (struct sprite_entry *e) + +STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e) { if (e->has_attached) if (bplres == 1) @@ -814,6 +861,7 @@ STATIC_INLINE void draw_sprites (struct draw_sprites_normal_sp_lo_nat (e); } + #define MERGE(a,b,mask,shift) do {\ uae_u32 tmp = mask & (a ^ (b >> shift)); \ a ^= tmp; \ @@ -1130,7 +1178,9 @@ static void pfield_expand_dp_bplcon (voi int plf1pri, plf2pri; bplres = dp_for_drawing->bplres; bplplanecnt = dp_for_drawing->nr_planes; - bplham = (dp_for_drawing->bplcon0 & 0x800) == 0x800; + bplham = ((dp_for_drawing->bplcon0 & 0x800) == 0x800 + && (bplplanecnt == 6 + || ((currprefs.chipset_mask & CSMASK_AGA) != 0 && bplplanecnt == 8))); if (currprefs.chipset_mask & CSMASK_AGA) { /* The KILLEHB bit exists in ECS, but is apparently meant for Genlock * stuff, and it's set by some demos (e.g. Andromeda Seven Seas) */ @@ -1218,10 +1268,10 @@ STATIC_INLINE void pfield_draw_line (int if (border == 0) { pfield_expand_dp_bplcon (); - if (bplres == RES_LORES && !currprefs.gfx_lores) + if (bplres == RES_LORES && ! currprefs.gfx_lores) currprefs.gfx_lores = 2; - pfield_init_linetoscr (); + pfield_init_linetoscr (); pfield_doline (lineno); adjust_drawing_colors (dp_for_drawing->ctable, bplham || bplehb); @@ -1242,21 +1292,24 @@ STATIC_INLINE void pfield_draw_line (int { int i; - for (i = 0; i < dip_for_drawing->nr_sprites; i++) - draw_sprites (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + for (i = 0; i < dip_for_drawing->nr_sprites; i++) { + if (currprefs.chipset_mask & CSMASK_AGA) + draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + else + draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + } } do_color_changes (pfield_do_fill_line, pfield_do_linetoscr); - if (dh == dh_emerg) - memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); do_flush_line (gfx_ypos); if (do_double) { if (dh == dh_emerg) - memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); else if (dh == dh_buf) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width); do_flush_line (follow_ypos); } if (currprefs.gfx_lores == 2) @@ -1289,14 +1342,14 @@ STATIC_INLINE void pfield_draw_line (int do_color_changes (pfield_do_fill_line, pfield_do_fill_line); if (dh == dh_emerg) - memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); do_flush_line (gfx_ypos); if (do_double) { if (dh == dh_emerg) - memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); else if (dh == dh_buf) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width); /* If dh == dh_line, do_flush_line will re-use the rendered line * from linemem. */ do_flush_line (follow_ypos); @@ -1416,6 +1469,120 @@ static void init_drawing_frame (void) drawing_color_matches = -1; } +/* + * Some code to put status information on the screen. + */ + +#define TD_PADX 10 +#define TD_PADY 2 +#define TD_WIDTH 32 +#define TD_LED_WIDTH 24 +#define TD_LED_HEIGHT 4 + +#define TD_RIGHT 1 +#define TD_BOTTOM 2 + +static int td_pos = (TD_RIGHT|TD_BOTTOM); + +#define TD_NUM_WIDTH 7 +#define TD_NUM_HEIGHT 7 + +#define TD_TOTAL_HEIGHT (TD_PADY * 2 + TD_NUM_HEIGHT) + +static char *numbers = { /* ugly */ +"------ ------ ------ ------ ------ ------ ------ ------ ------ ------ " +"-xxxxx ---xx- -xxxxx -xxxxx -x---x -xxxxx -xxxxx -xxxxx -xxxxx -xxxxx " +"-x---x ----x- -----x -----x -x---x -x---- -x---- -----x -x---x -x---x " +"-x---x ----x- -xxxxx -xxxxx -xxxxx -xxxxx -xxxxx ----x- -xxxxx -xxxxx " +"-x---x ----x- -x---- -----x -----x -----x -x---x ---x-- -x---x -----x " +"-xxxxx ----x- -xxxxx -xxxxx -----x -xxxxx -xxxxx ---x-- -xxxxx -xxxxx " +"------ ------ ------ ------ ------ ------ ------ ------ ------ ------ " +}; + +STATIC_INLINE void putpixel (int x, xcolnr c8) +{ + switch(gfxvidinfo.pixbytes) + { + case 1: + xlinebuffer[x] = (uae_u8)c8; + break; + case 2: + { + uae_u16 *p = (uae_u16 *)xlinebuffer + x; + *p = c8; + break; + } + case 3: + /* no 24 bit yet */ + break; + case 4: + { + uae_u32 *p = (uae_u32 *)xlinebuffer + x; + *p = c8; + break; + } + } +} + +static void write_tdnumber (int x, int y, int num) +{ + int j; + uae_u8 *numptr; + + numptr = numbers + num * TD_NUM_WIDTH + 10 * TD_NUM_WIDTH * y; + for (j = 0; j < TD_NUM_WIDTH; j++) { + putpixel (x + j, *numptr == 'x' ? xcolors[0xfff] : xcolors[0x000]); + numptr++; + } +} + +static void draw_status_line (int line) +{ + int x, y, i, j, led, on; + int on_rgb, off_rgb, c; + uae_u8 *buf; + + if (td_pos & TD_RIGHT) + x = gfxvidinfo.width - TD_PADX - 5*TD_WIDTH; + else + x = TD_PADX; + + y = line - (gfxvidinfo.height - TD_TOTAL_HEIGHT); + xlinebuffer = gfxvidinfo.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + + memset (xlinebuffer, 0, gfxvidinfo.width * gfxvidinfo.pixbytes); + + for (led = 0; led < 5; led++) { + int track; + if (led > 0) { + track = gui_data.drive_track[led-1]; + on = gui_data.drive_motor[led-1]; + on_rgb = 0x0f0; + off_rgb = 0x040; + } else { + track = -1; + on = gui_data.powerled; + on_rgb = 0xf00; + off_rgb = 0x400; + } + c = xcolors[on ? on_rgb : off_rgb]; + + for (j = 0; j < TD_LED_WIDTH; j++) + putpixel (x + j, c); + + if (y >= TD_PADY && y - TD_PADY < TD_NUM_HEIGHT) { + if (track >= 0) { + int offs = (TD_WIDTH - 2 * TD_NUM_WIDTH) / 2; + write_tdnumber (x + offs, y - TD_PADY, track / 10); + write_tdnumber (x + offs + TD_NUM_WIDTH, y - TD_PADY, track % 10); + } + } + x += TD_WIDTH; + } +} + void finish_drawing_frame (void) { int i; @@ -1433,19 +1600,26 @@ void finish_drawing_frame (void) } for (i = 0; i < max_ypos_thisframe; i++) { int where; + int i1 = i + min_ypos_for_screen; int line = i + thisframe_y_adjust_real; if (linestate[line] == LINE_UNDECIDED) break; - where = amiga2aspect_line_map[i+min_ypos_for_screen]; - if (where >= gfxvidinfo.height) + where = amiga2aspect_line_map[i1]; + if (where >= gfxvidinfo.height - TD_TOTAL_HEIGHT) break; if (where == -1) continue; - pfield_draw_line (line, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); + pfield_draw_line (line, where, amiga2aspect_line_map[i1 + 1]); } + for (i = 0; i < TD_TOTAL_HEIGHT; i++) { + int line = gfxvidinfo.height - TD_TOTAL_HEIGHT + i; + draw_status_line (line); + do_flush_line (line); + } + unlockscr (); do_flush_screen (first_drawn_line, last_drawn_line); } @@ -1507,6 +1681,20 @@ void vsync_handle_redraw (int long_frame * done at other times. */ + if (savestate_state == STATE_DOSAVE) { + custom_prepare_savestate (); + savestate_state = STATE_SAVE; + save_state (savestate_filename, "Description!"); + savestate_state = 0; + } else if (savestate_state == STATE_DORESTORE) { + savestate_state = STATE_RESTORE; + uae_reset (); + restore_state (savestate_filename); +#if 0 + activate_debugger (); +#endif + } + if (quit_program < 0) { quit_program = -quit_program; set_inhibit_frame (IHF_QUIT_PROGRAM);