kegs/src/video.c

3491 lines
85 KiB
C

/************************************************************************/
/* KEGS: Apple //gs Emulator */
/* Copyright 2002 by Kent Dickey */
/* */
/* This code is covered by the GNU GPL */
/* */
/* The KEGS web page is kegs.sourceforge.net */
/* You may contact the author at: kadickey@alumni.princeton.edu */
/************************************************************************/
const char rcsid_video_c[] = "@(#)$KmKId: video.c,v 1.135 2004-11-12 23:09:44-05 kentd Exp $";
#include <time.h>
#include "defc.h"
extern int Verbose;
int g_a2_line_stat[200];
int g_a2_line_left_edge[200];
int g_a2_line_right_edge[200];
Kimage *g_a2_line_kimage[200];
int g_mode_text[2][200];
int g_mode_hires[2][200];
int g_mode_superhires[200];
int g_mode_border[200];
byte g_cur_border_colors[270];
byte g_new_special_border[64][64];
byte g_cur_special_border[64][64];
word32 g_a2_screen_buffer_changed = (word32)-1;
word32 g_full_refresh_needed = (word32)-1;
word32 g_cycs_in_40col = 0;
word32 g_cycs_in_xredraw = 0;
word32 g_refresh_bytes_xfer = 0;
extern byte *g_slow_memory_ptr;
extern int g_screen_depth;
extern int g_screen_mdepth;
extern double g_cur_dcycs;
extern int g_line_ref_amt;
extern int g_c034_val;
extern int g_config_control_panel;
typedef byte Change;
word32 slow_mem_changed[SLOW_MEM_CH_SIZE];
word32 g_font40_even_bits[0x100][8][16/4];
word32 g_font40_odd_bits[0x100][8][16/4];
word32 g_font80_off0_bits[0x100][8][12/4];
word32 g_font80_off1_bits[0x100][8][12/4];
word32 g_font80_off2_bits[0x100][8][12/4];
word32 g_font80_off3_bits[0x100][8][12/4];
word32 g_superhires_scan_save[256];
Kimage g_kimage_text[2];
Kimage g_kimage_hires[2];
Kimage g_kimage_superhires;
Kimage g_kimage_border_special;
Kimage g_kimage_border_sides;
Kimage g_mainwin_kimage;
extern double g_last_vbl_dcycs;
double g_video_dcycs_check_input = 0.0;
int g_video_extra_check_inputs = 0;
int g_video_act_margin_left = BASE_MARGIN_LEFT;
int g_video_act_margin_right = BASE_MARGIN_RIGHT;
int g_video_act_margin_top = BASE_MARGIN_TOP;
int g_video_act_margin_bottom = BASE_MARGIN_BOTTOM;
int g_video_act_width = X_A2_WINDOW_WIDTH;
int g_video_act_height = X_A2_WINDOW_HEIGHT;
int g_need_redraw = 1;
int g_palette_change_summary = 0;
word32 g_palette_change_cnt[16];
int g_border_sides_refresh_needed = 1;
int g_border_special_refresh_needed = 1;
int g_border_line24_refresh_needed = 1;
int g_status_refresh_needed = 1;
int g_vbl_border_color = 0;
int g_border_last_vbl_changes = 0;
int g_use_dhr140 = 0;
int g_use_bw_hires = 0;
int g_a2_new_all_stat[200];
int g_a2_cur_all_stat[200];
int g_new_a2_stat_cur_line = 0;
int g_vid_update_last_line = 0;
int g_expanded_col_0[16];
int g_expanded_col_1[16];
int g_expanded_col_2[16];
int g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 |
(0xf << BIT_ALL_STAT_TEXT_COLOR);
extern int g_save_cur_a2_stat; /* from config.c */
int g_a2vid_palette = 0xe;
int g_installed_full_superhires_colormap = 0;
int Max_color_size = 256;
word32 g_palette_8to1624[256];
word32 g_a2palette_8to1624[256];
word32 g_saved_line_palettes[200][8];
int g_saved_a2vid_palette = -1;
word32 g_a2vid_palette_remap[16];
word32 g_cycs_in_refresh_line = 0;
word32 g_cycs_in_refresh_ximage = 0;
int g_num_lines_superhires = 0;
int g_num_lines_superhires640 = 0;
int g_num_lines_prev_superhires = 0;
int g_num_lines_prev_superhires640 = 0;
word32 g_red_mask = 0xff;
word32 g_green_mask = 0xff;
word32 g_blue_mask = 0xff;
int g_red_left_shift = 16;
int g_green_left_shift = 8;
int g_blue_left_shift = 0;
int g_red_right_shift = 0;
int g_green_right_shift = 0;
int g_blue_right_shift = 0;
char g_status_buf[MAX_STATUS_LINES][STATUS_LINE_LENGTH + 1];
char *g_status_ptrs[MAX_STATUS_LINES] = { 0 };
const int g_dbhires_colors[] = {
/* rgb */
0x000, /* 0x0 black */
0xd03, /* 0x1 deep red */
0x852, /* 0x2 brown */
0xf60, /* 0x3 orange */
0x070, /* 0x4 dark green */
0x555, /* 0x5 dark gray */
0x0d0, /* 0x6 green */
0xff0, /* 0x7 yellow */
0x009, /* 0x8 dark blue */
0xd0d, /* 0x9 purple */
0xaaa, /* 0xa light gray */
0xf98, /* 0xb pink */
0x22f, /* 0xc medium blue */
0x6af, /* 0xd light blue */
0x0f9, /* 0xe aquamarine */
0xfff /* 0xf white */
};
word32 g_dhires_convert[4096]; /* look up table of 7 bits (concat): */
/* { 4 bits, |3 prev bits| } */
const byte g_dhires_colors_16[] = {
0x00, /* 0x0 black */
0x02, /* 0x1 dark blue */
0x04, /* 0x2 dark green */
0x06, /* 0x3 medium blue */
0x08, /* 0x4 brown */
0x0a, /* 0x5 light gray */
0x0c, /* 0x6 green */
0x0e, /* 0x7 aquamarine */
0x01, /* 0x8 deep red */
0x03, /* 0x9 purple */
0x05, /* 0xa dark gray */
0x07, /* 0xb light blue */
0x09, /* 0xc orange */
0x0b, /* 0xd pink */
0x0d, /* 0xe yellow */
0x0f/* 0xf white */
};
const int g_lores_colors[] = {
/* rgb */
0x000, /* 0x0 black */
0xd03, /* 0x1 deep red */
0x009, /* 0x2 dark blue */
0xd0d, /* 0x3 purple */
0x070, /* 0x4 dark green */
0x555, /* 0x5 dark gray */
0x22f, /* 0x6 medium blue */
0x6af, /* 0x7 light blue */
0x852, /* 0x8 brown */
0xf60, /* 0x9 orange */
0xaaa, /* 0xa light gray */
0xf98, /* 0xb pink */
0x0d0, /* 0xc green */
0xff0, /* 0xd yellow */
0x0f9, /* 0xe aquamarine */
0xfff /* 0xf white */
};
const word32 g_bw_hires_convert[4] = {
BIGEND(0x00000000),
BIGEND(0x0f0f0000),
BIGEND(0x00000f0f),
BIGEND(0x0f0f0f0f)
};
const word32 g_bw_dhires_convert[16] = {
BIGEND(0x00000000),
BIGEND(0x0f000000),
BIGEND(0x000f0000),
BIGEND(0x0f0f0000),
BIGEND(0x00000f00),
BIGEND(0x0f000f00),
BIGEND(0x000f0f00),
BIGEND(0x0f0f0f00),
BIGEND(0x0000000f),
BIGEND(0x0f00000f),
BIGEND(0x000f000f),
BIGEND(0x0f0f000f),
BIGEND(0x00000f0f),
BIGEND(0x0f000f0f),
BIGEND(0x000f0f0f),
BIGEND(0x0f0f0f0f),
};
const word32 g_hires_convert[64] = {
BIGEND(0x00000000), /* 00,0000 = black, black, black, black */
BIGEND(0x00000000), /* 00,0001 = black, black, black, black */
BIGEND(0x03030000), /* 00,0010 = purp , purp , black, black */
BIGEND(0x0f0f0000), /* 00,0011 = white, white, black, black */
BIGEND(0x00000c0c), /* 00,0100 = black, black, green, green */
BIGEND(0x0c0c0c0c), /* 00,0101 = green, green, green, green */
BIGEND(0x0f0f0f0f), /* 00,0110 = white, white, white, white */
BIGEND(0x0f0f0f0f), /* 00,0111 = white, white, white, white */
BIGEND(0x00000000), /* 00,1000 = black, black, black, black */
BIGEND(0x00000000), /* 00,1001 = black, black, black, black */
BIGEND(0x03030303), /* 00,1010 = purp , purp , purp , purp */
BIGEND(0x0f0f0303), /* 00,1011 = white ,white, purp , purp */
BIGEND(0x00000f0f), /* 00,1100 = black ,black, white, white */
BIGEND(0x0c0c0f0f), /* 00,1101 = green ,green, white, white */
BIGEND(0x0f0f0f0f), /* 00,1110 = white ,white, white, white */
BIGEND(0x0f0f0f0f), /* 00,1111 = white ,white, white, white */
BIGEND(0x00000000), /* 01,0000 = black, black, black, black */
BIGEND(0x00000000), /* 01,0001 = black, black, black, black */
BIGEND(0x06060000), /* 01,0010 = blue , blue , black, black */
BIGEND(0x0f0f0000), /* 01,0011 = white, white, black, black */
BIGEND(0x00000c0c), /* 01,0100 = black, black, green, green */
BIGEND(0x09090c0c), /* 01,0101 = orang, orang, green, green */
BIGEND(0x0f0f0f0f), /* 01,0110 = white, white, white, white */
BIGEND(0x0f0f0f0f), /* 01,0111 = white, white, white, white */
BIGEND(0x00000000), /* 01,1000 = black, black, black, black */
BIGEND(0x00000000), /* 01,1001 = black, black, black, black */
BIGEND(0x06060303), /* 01,1010 = blue , blue , purp , purp */
BIGEND(0x0f0f0303), /* 01,1011 = white ,white, purp , purp */
BIGEND(0x00000f0f), /* 01,1100 = black ,black, white, white */
BIGEND(0x09090f0f), /* 01,1101 = orang ,orang, white, white */
BIGEND(0x0f0f0f0f), /* 01,1110 = white ,white, white, white */
BIGEND(0x0f0f0f0f), /* 01,1111 = white ,white, white, white */
BIGEND(0x00000000), /* 10,0000 = black, black, black, black */
BIGEND(0x00000000), /* 10,0001 = black, black, black, black */
BIGEND(0x03030000), /* 10,0010 = purp , purp , black, black */
BIGEND(0x0f0f0000), /* 10,0011 = white, white, black, black */
BIGEND(0x00000909), /* 10,0100 = black, black, orang, orang */
BIGEND(0x0c0c0909), /* 10,0101 = green, green, orang, orang */
BIGEND(0x0f0f0f0f), /* 10,0110 = white, white, white, white */
BIGEND(0x0f0f0f0f), /* 10,0111 = white, white, white, white */
BIGEND(0x00000000), /* 10,1000 = black, black, black, black */
BIGEND(0x00000000), /* 10,1001 = black, black, black, black */
BIGEND(0x03030606), /* 10,1010 = purp , purp , blue , blue */
BIGEND(0x0f0f0606), /* 10,1011 = white ,white, blue , blue */
BIGEND(0x00000f0f), /* 10,1100 = black ,black, white, white */
BIGEND(0x0c0c0f0f), /* 10,1101 = green ,green, white, white */
BIGEND(0x0f0f0f0f), /* 10,1110 = white ,white, white, white */
BIGEND(0x0f0f0f0f), /* 10,1111 = white ,white, white, white */
BIGEND(0x00000000), /* 11,0000 = black, black, black, black */
BIGEND(0x00000000), /* 11,0001 = black, black, black, black */
BIGEND(0x06060000), /* 11,0010 = blue , blue , black, black */
BIGEND(0x0f0f0000), /* 11,0011 = white, white, black, black */
BIGEND(0x00000909), /* 11,0100 = black, black, orang, orang */
BIGEND(0x09090909), /* 11,0101 = orang, orang, orang, orang */
BIGEND(0x0f0f0f0f), /* 11,0110 = white, white, white, white */
BIGEND(0x0f0f0f0f), /* 11,0111 = white, white, white, white */
BIGEND(0x00000000), /* 11,1000 = black, black, black, black */
BIGEND(0x00000000), /* 11,1001 = black, black, black, black */
BIGEND(0x06060606), /* 11,1010 = blue , blue , blue , blue */
BIGEND(0x0f0f0606), /* 11,1011 = white ,white, blue , blue */
BIGEND(0x00000f0f), /* 11,1100 = black ,black, white, white */
BIGEND(0x09090f0f), /* 11,1101 = orang ,orang, white, white */
BIGEND(0x0f0f0f0f), /* 11,1110 = white ,white, white, white */
BIGEND(0x0f0f0f0f), /* 11,1111 = white ,white, white, white */
};
const int g_screen_index[] = {
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380,
0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8,
0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0
};
void
video_init()
{
word32 col[4];
Kimage *kimage_ptr;
word32 *ptr;
word32 val0, val1, val2, val3;
word32 match_col;
word32 next_col, next2_col, next3_col;
word32 val;
word32 cur_col;
int width, height;
int total_bytes;
int i, j;
/* Initialize video system */
for(i = 0; i < 200; i++) {
g_a2_line_kimage[i] = (void *)0;
g_a2_line_stat[i] = -1;
g_a2_line_left_edge[i] = 0;
g_a2_line_right_edge[i] = 0;
}
for(i = 0; i < 200; i++) {
g_a2_new_all_stat[i] = 0;
g_a2_cur_all_stat[i] = 1;
for(j = 0; j < 8; j++) {
g_saved_line_palettes[i][j] = (word32)-1;
}
}
for(i = 0; i < 262; i++) {
g_cur_border_colors[i] = -1;
}
g_new_a2_stat_cur_line = 0;
dev_video_init();
read_a2_font();
vid_printf("Zeroing out video memory\n");
for(i = 0; i < 7; i++) {
switch(i) {
case 0:
kimage_ptr = &(g_kimage_text[0]);
break;
case 1:
kimage_ptr = &(g_kimage_text[1]);
break;
case 2:
kimage_ptr = &(g_kimage_hires[0]);
break;
case 3:
kimage_ptr = &(g_kimage_hires[1]);
break;
case 4:
kimage_ptr = &g_kimage_superhires;
break;
case 5:
kimage_ptr = &g_kimage_border_sides;
break;
case 6:
kimage_ptr = &g_kimage_border_special;
break;
default:
printf("i: %d, unknown\n", i);
exit(3);
}
ptr = (word32 *)kimage_ptr->data_ptr;
width = kimage_ptr->width_act;
height = kimage_ptr->height;
total_bytes = (kimage_ptr->mdepth >> 3) * width * height;
for(j = 0; j < total_bytes >> 2; j++) {
*ptr++ = 0;
}
}
for(i = 0; i < SLOW_MEM_CH_SIZE; i++) {
slow_mem_changed[i] = (word32)-1;
}
/* create g_expanded_col_* */
for(i = 0; i < 16; i++) {
val = (g_lores_colors[i] >> 0) & 0xf;
g_expanded_col_0[i] = val;
val = (g_lores_colors[i] >> 4) & 0xf;
g_expanded_col_1[i] = val;
val = (g_lores_colors[i] >> 8) & 0xf;
g_expanded_col_2[i] = val;
}
/* create g_dhires_convert[] array */
for(i = 0; i < 4096; i++) {
/* Convert index bits 11:0 where 3:0 is the previous color */
/* and 7:4 is the current color to translate */
/* Bit 4 will be the first pixel displayed on the screen */
match_col = i & 0xf;
for(j = 0; j < 4; j++) {
cur_col = (i >> (1 + j)) & 0xf;
next_col = (i >> (2 + j)) & 0xf;
next2_col = (i >> (3 + j)) & 0xf;
next3_col = (i >> (4 + j)) & 0xf;
cur_col = (((cur_col << 4) + cur_col) >> (3 - j)) & 0xf;
if((cur_col == 0xf) || (next_col == 0xf) ||
(next2_col == 0xf) ||
(next3_col == 0xf)) {
cur_col = 0xf;
col[j] = cur_col;
match_col = cur_col;
} else if((cur_col == 0) || (next_col == 0) ||
(next2_col == 0) || (next3_col == 0)) {
cur_col = 0;
col[j] = cur_col;
match_col = cur_col;
} else {
col[j] = cur_col;
match_col = cur_col;
}
}
if(g_use_dhr140) {
for(j = 0; j < 4; j++) {
col[j] = (i >> 4) & 0xf;
}
}
val0 = g_dhires_colors_16[col[0] & 0xf];
val1 = g_dhires_colors_16[col[1] & 0xf];
val2 = g_dhires_colors_16[col[2] & 0xf];
val3 = g_dhires_colors_16[col[3] & 0xf];
#ifdef KEGS_LITTLE_ENDIAN
val = (val3 << 24) + (val2 << 16) + (val1 << 8) + val0;
#else
val = (val0 << 24) + (val1 << 16) + (val2 << 8) + val3;
#endif
g_dhires_convert[i] = val;
}
change_display_mode(g_cur_dcycs);
video_reset();
display_screen();
fflush(stdout);
}
void
show_a2_line_stuff()
{
int i;
for(i = 0; i < 200; i++) {
printf("line: %d: stat: %04x, ptr: %p, "
"left_edge:%d, right_edge:%d\n",
i, g_a2_line_stat[i], g_a2_line_kimage[i],
g_a2_line_left_edge[i],
g_a2_line_right_edge[i]);
}
printf("new_a2_stat_cur_line: %d, cur_a2_stat:%04x\n",
g_new_a2_stat_cur_line, g_cur_a2_stat);
for(i = 0; i < 200; i++) {
printf("cur_all[%d]: %03x new_all: %03x\n", i,
g_a2_cur_all_stat[i], g_a2_new_all_stat[i]);
}
}
int g_flash_count = 0;
void
video_reset()
{
int stat;
int i;
g_installed_full_superhires_colormap = (g_screen_depth != 8);
stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 |
(0xf << BIT_ALL_STAT_TEXT_COLOR);
if(g_use_bw_hires) {
stat |= ALL_STAT_COLOR_C021;
}
if(g_config_control_panel) {
/* Don't update cur_a2_stat when in configuration panel */
g_save_cur_a2_stat = stat;
} else {
g_cur_a2_stat = stat;
}
g_palette_change_summary = 0;
for(i = 0; i < 16; i++) {
g_palette_change_cnt[i] = 0;
}
/* install_a2vid_colormap(); */
video_update_colormap();
}
int g_screen_redraw_skip_count = 0;
int g_screen_redraw_skip_amt = -1;
word32 g_cycs_in_check_input = 0;
void
video_update()
{
int did_video;
update_border_info();
video_check_input_events();
g_screen_redraw_skip_count--;
did_video = 0;
if(g_screen_redraw_skip_count < 0) {
did_video = 1;
video_update_event_line(262);
g_screen_redraw_skip_count = g_screen_redraw_skip_amt;
}
/* update flash */
g_flash_count++;
if(g_flash_count >= 30) {
g_flash_count = 0;
g_cur_a2_stat ^= ALL_STAT_FLASH_STATE;
change_display_mode(g_cur_dcycs);
}
check_a2vid_palette();
if(did_video) {
g_new_a2_stat_cur_line = 0;
g_a2_new_all_stat[0] = g_cur_a2_stat;
g_vid_update_last_line = 0;
video_update_through_line(0);
}
}
int
video_all_stat_to_line_stat(int line, int new_all_stat)
{
int page, color, dbl;
int st80, hires, annunc3, mix_t_gr;
int altchar, text_color, bg_color, flash_state;
int mode;
st80 = new_all_stat & ALL_STAT_ST80;
hires = new_all_stat & ALL_STAT_HIRES;
annunc3 = new_all_stat & ALL_STAT_ANNUNC3;
mix_t_gr = new_all_stat & ALL_STAT_MIX_T_GR;
page = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_PAGE2, 1) && !st80;
color = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_COLOR_C021, 1);
dbl = EXTRU(new_all_stat, 31 - BIT_ALL_STAT_VID80, 1);
altchar = 0; text_color = 0; bg_color = 0; flash_state = 0;
if(new_all_stat & ALL_STAT_SUPER_HIRES) {
mode = MODE_SUPER_HIRES;
page = 0; dbl = 0; color = 0;
} else {
if(line >= 192) {
mode = MODE_BORDER;
page = 0; dbl = 0; color = 0;
} else if((new_all_stat & ALL_STAT_TEXT) ||
(line >= 160 && mix_t_gr)) {
mode = MODE_TEXT;
color = 0;
altchar = EXTRU(new_all_stat,
31 - BIT_ALL_STAT_ALTCHARSET, 1);
text_color = EXTRU(new_all_stat,
31 - BIT_ALL_STAT_TEXT_COLOR, 4);
bg_color = EXTRU(new_all_stat,
31 - BIT_ALL_STAT_BG_COLOR, 4);
flash_state = EXTRU(new_all_stat,
31 - BIT_ALL_STAT_FLASH_STATE, 1);
if(altchar) {
/* don't bother flashing if altchar on */
flash_state = 0;
}
} else {
/* obey the graphics mode */
dbl = dbl && !annunc3;
if(hires) {
color = color | EXTRU(new_all_stat,
31 - BIT_ALL_STAT_DIS_COLOR_DHIRES, 1);
mode = MODE_HGR;
} else {
mode = MODE_GR;
}
}
}
return((text_color << 12) + (bg_color << 8) + (altchar << 7) +
(mode << 4) + (flash_state << 3) + (page << 2) +
(color << 1) + dbl);
}
int *
video_update_kimage_ptr(int line, int new_stat)
{
Kimage *kimage_ptr;
int *mode_ptr;
int page;
int mode;
page = (new_stat >> 2) & 1;
mode = (new_stat >> 4) & 7;
switch(mode) {
case MODE_TEXT:
case MODE_GR:
kimage_ptr = &(g_kimage_text[page]);
mode_ptr = &(g_mode_text[page][0]);
break;
case MODE_HGR:
kimage_ptr = &(g_kimage_hires[page]);
mode_ptr = &(g_mode_hires[page][0]);
/* arrange to force superhires reparse since we use the */
/* same memory */
g_mode_superhires[line] = -1;
break;
case MODE_SUPER_HIRES:
kimage_ptr = &g_kimage_superhires;
mode_ptr = &(g_mode_superhires[0]);
/* arrange to force hires reparse since we use the */
/* same memory */
g_mode_hires[0][line] = -1;
g_mode_hires[1][line] = -1;
break;
case MODE_BORDER:
/* Hack: reuse text page last line as the special border */
kimage_ptr = &(g_kimage_text[0]);
mode_ptr = &(g_mode_border[0]);
break;
default:
halt_printf("update_a2_ptrs: mode: %d unknown!\n", mode);
return &(g_mode_superhires[0]);
}
g_a2_line_kimage[line] = kimage_ptr;
return mode_ptr;
}
void
change_a2vid_palette(int new_palette)
{
int i;
for(i = 0; i < 200; i++) {
g_mode_text[0][i] = -1;
g_mode_text[1][i] = -1;
g_mode_hires[0][i] = -1;
g_mode_hires[1][i] = -1;
g_mode_superhires[i] = -1;
g_mode_border[i] = -1;
}
printf("Changed a2vid_palette to %x\n", new_palette);
g_a2vid_palette = new_palette;
g_cur_a2_stat = (g_cur_a2_stat & (~ALL_STAT_A2VID_PALETTE)) +
(new_palette << BIT_ALL_STAT_A2VID_PALETTE);
change_display_mode(g_cur_dcycs);
g_border_sides_refresh_needed = 1;
g_border_special_refresh_needed = 1;
g_status_refresh_needed = 1;
g_palette_change_cnt[new_palette]++;
g_border_last_vbl_changes = 1;
for(i = 0; i < 262; i++) {
g_cur_border_colors[i] = -1;
}
}
int g_num_a2vid_palette_checks = 1;
int g_shr_palette_used[16];
void
check_a2vid_palette()
{
int sum;
int min;
int val;
int min_pos;
int count_cur;
int i;
/* determine if g_a2vid_palette should change */
/* This is the palette of least use on superhires so that the */
/* borders don't change when all 256 superhires colors are used */
g_num_a2vid_palette_checks--;
if(g_num_a2vid_palette_checks || g_installed_full_superhires_colormap){
return;
}
g_num_a2vid_palette_checks = 60;
sum = 0;
min = 0x100000;
min_pos = -1;
count_cur = g_shr_palette_used[g_a2vid_palette];
for(i = 0; i < 16; i++) {
val = g_shr_palette_used[i];
g_shr_palette_used[i] = 0;
if(val < min) {
min = val;
min_pos = i;
}
sum += val;
}
if(g_a2vid_palette != min_pos && (count_cur > min)) {
change_a2vid_palette(min_pos);
}
}
void
change_display_mode(double dcycs)
{
int line, tmp_line;
line = ((get_lines_since_vbl(dcycs) + 0xff) >> 8);
if(line < 0) {
line = 0;
halt_printf("Line < 0!\n");
}
tmp_line = MIN(199, line);
video_update_all_stat_through_line(tmp_line);
if(line < 200) {
g_a2_new_all_stat[line] = g_cur_a2_stat;
}
/* otherwise, g_cur_a2_stat is covered at the end of vbl */
}
void
video_update_all_stat_through_line(int line)
{
int start_line;
int prev_stat;
int max_line;
int i;
start_line = g_new_a2_stat_cur_line;
prev_stat = g_a2_new_all_stat[start_line];
max_line = MIN(199, line);
for(i = start_line + 1; i <= max_line; i++) {
g_a2_new_all_stat[i] = prev_stat;
}
g_new_a2_stat_cur_line = max_line;
}
#define MAX_BORDER_CHANGES 16384
STRUCT(Border_changes) {
float fcycs;
int val;
};
Border_changes g_border_changes[MAX_BORDER_CHANGES];
int g_num_border_changes = 0;
void
change_border_color(double dcycs, int val)
{
int pos;
pos = g_num_border_changes;
g_border_changes[pos].fcycs = dcycs - g_last_vbl_dcycs;
g_border_changes[pos].val = val;
pos++;
g_num_border_changes = pos;
if(pos >= MAX_BORDER_CHANGES) {
halt_printf("num border changes: %d\n", pos);
g_num_border_changes = 0;
}
}
void
update_border_info()
{
double dlines_per_dcyc;
double dcycs, dline, dcyc_line_start;
int offset;
int new_line_offset, last_line_offset;
int new_line;
int new_val;
int limit;
int color_now;
int i;
/* to get this routine to redraw the border, change */
/* g_vbl_border_color, set g_border_last_vbl_changes = 1 */
/* and change the cur_border_colors[] array */
color_now = g_vbl_border_color;
dlines_per_dcyc = (double)(1.0 / 65.0);
limit = g_num_border_changes;
if(g_border_last_vbl_changes || limit) {
/* add a dummy entry */
g_border_changes[limit].fcycs = DCYCS_IN_16MS + 21.0;
g_border_changes[limit].val = (g_c034_val & 0xf);
limit++;
}
last_line_offset = (-1 << 8) + 44;
for(i = 0; i < limit; i++) {
dcycs = g_border_changes[i].fcycs;
dline = dcycs * dlines_per_dcyc;
new_line = (int)dline;
dcyc_line_start = (double)new_line * 65.0;
offset = ((int)(dcycs - dcyc_line_start)) & 0xff;
/* here comes the tricky part */
/* offset is from 0 to 65, where 0-3 is the right border of */
/* the previous line, 4-20 is horiz blanking, 21-24 is the */
/* left border and 25-64 is the main window */
/* Convert this to a new notation which is 0-3 is the left */
/* border, 4-43 is the main window, and 44-47 is the right */
/* basically, add -21 to offset, and wrap < 0 to previous ln */
/* note this makes line -1 offset 44-47 the left hand border */
/* for true line 261 on the screen */
offset -= 21;
if(offset < 0) {
new_line--;
offset += 64;
}
new_val = g_border_changes[i].val;
new_line_offset = (new_line << 8) + offset;
if(new_line_offset < -256 || new_line_offset >(262*256 + 0x80)){
printf("new_line_offset: %05x\n", new_line_offset);
new_line_offset = last_line_offset;
}
while(last_line_offset < new_line_offset) {
/* see if this will finish it */
if((last_line_offset & -256)==(new_line_offset & -256)){
update_border_line(last_line_offset,
new_line_offset, color_now);
last_line_offset = new_line_offset;
} else {
update_border_line(last_line_offset,
(last_line_offset & -256) + 65,
color_now);
last_line_offset =(last_line_offset & -256)+256;
}
}
color_now = new_val;
}
#if 0
if(g_num_border_changes) {
printf("Border changes: %d\n", g_num_border_changes);
}
#endif
if(limit > 1) {
g_border_last_vbl_changes = 1;
} else {
g_border_last_vbl_changes = 0;
}
g_num_border_changes = 0;
g_vbl_border_color = (g_c034_val & 0xf);
}
void
update_border_line(int st_line_offset, int end_line_offset, int color)
{
word32 val;
int st_offset, end_offset;
int left, right;
int line;
line = st_line_offset >> 8;
if(line != (end_line_offset >> 8)) {
halt_printf("ubl, %04x %04x %02x!\n", st_line_offset,
end_line_offset, color);
}
if(line < -1 || line >= 262) {
halt_printf("ubl-b, mod line is %d\n", line);
line = 0;
}
if(line < 0 || line >= 262) {
line = 0;
}
st_offset = st_line_offset & 0xff;
end_offset = end_line_offset & 0xff;
if((st_offset == 0) && (end_offset >= 0x41)) {
/* might be the same as last time, save some work */
if(g_cur_border_colors[line] == color) {
return;
}
g_cur_border_colors[line] = color;
} else {
g_cur_border_colors[line] = -1;
}
val = (color + (g_a2vid_palette << 4));
val = (val << 24) + (val << 16) + (val << 8) + val;
/* 0-3: left border, 4-43: main window, 44-47: right border */
/* 48-65: horiz blanking */
/* first, do the sides from line 0 to line 199 */
if((line < 200) || (line >= 262)) {
if(line >= 262) {
line = 0;
}
if(st_offset < 4) {
/* left side */
left = st_offset;
right = MIN(4, end_offset);
video_border_pixel_write(&g_kimage_border_sides,
2*line, 2, val, (left * BORDER_WIDTH)/4,
(right * BORDER_WIDTH) / 4);
g_border_sides_refresh_needed = 1;
}
if((st_offset < 48) && (end_offset >= 44)) {
/* right side */
left = MAX(0, st_offset - 44);
right = MIN(4, end_offset - 44);
video_border_pixel_write(&g_kimage_border_sides,
2*line, 2, val,
BORDER_WIDTH + (left * EFF_BORDER_WIDTH/4),
BORDER_WIDTH + (right * EFF_BORDER_WIDTH/4));
g_border_sides_refresh_needed = 1;
}
}
if((line >= 192) && (line < 200)) {
if(st_offset < 44 && end_offset > 4) {
left = MAX(0, st_offset - 4);
right = MIN(40, end_offset - 4);
video_border_pixel_write(&g_kimage_text[0],
2*line, 2, val, left * 640 / 40,
right * 640 / 40);
g_border_line24_refresh_needed = 1;
}
}
/* now do the bottom, lines 200 to 215 */
if((line >= 200) && (line < (200 + BASE_MARGIN_BOTTOM/2)) ) {
line -= 200;
left = st_offset;
right = MIN(48, end_offset);
video_border_pixel_write(&g_kimage_border_special, 2*line, 2,
val, (left * X_A2_WINDOW_WIDTH / 48),
(right * X_A2_WINDOW_WIDTH / 48));
g_border_special_refresh_needed = 1;
}
/* and top, lines 236 to 262 */
if((line >= (262 - BASE_MARGIN_TOP/2)) && (line < 262)) {
line -= (262 - BASE_MARGIN_TOP/2);
left = st_offset;
right = MIN(48, end_offset);
video_border_pixel_write(&g_kimage_border_special,
BASE_MARGIN_BOTTOM + 2*line, 2, val,
(left * X_A2_WINDOW_WIDTH / 48),
(right * X_A2_WINDOW_WIDTH / 48));
g_border_special_refresh_needed = 1;
}
}
void
video_border_pixel_write(Kimage *kimage_ptr, int starty, int num_lines,
word32 val, int st_off, int end_off)
{
word32 *ptr;
int width;
int width_act;
int mdepth;
int num_words, num_bytes;
int bytes_per_pix;
int i, j;
if(end_off <= st_off) {
return;
}
width = end_off - st_off;
width_act = kimage_ptr->width_act;
mdepth = kimage_ptr->mdepth;
bytes_per_pix = mdepth >> 3;
num_bytes = width * bytes_per_pix;
num_words = num_bytes >> 2;
if(width > width_act) {
halt_printf("border write but width %d > act %d\n", width,
width_act);
}
if(mdepth == 16) {
val = g_a2palette_8to1624[val & 0xff];
val = (val << 16) + val;
} else if(mdepth == 32) {
/* 32-bit pixels */
val = g_a2palette_8to1624[val & 0xff];
}
for(i = 0; i < num_lines; i++) {
ptr = (word32 *)&(kimage_ptr->data_ptr[
(starty + i)*width_act*bytes_per_pix]);
ptr += ((st_off * bytes_per_pix) / 4);
/* HACK: the above isn't really right when bytes_per_pix is */
/* less than four... */
for(j = 0; j < num_words; j++) {
*ptr++ = val;
}
}
}
#define CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, do_clear) \
ch_ptr = &(slow_mem_changed[mem_ptr >> CHANGE_SHIFT]); \
ch_bitpos = 0; \
bits_per_line = 40 >> SHIFT_PER_CHANGE; \
ch_shift_amount = (mem_ptr >> SHIFT_PER_CHANGE) & 0x1f; \
mask_per_line = (-(1 << (32 - bits_per_line))); \
mask_per_line = mask_per_line >> ch_shift_amount; \
ch_mask = *ch_ptr & mask_per_line; \
if(do_clear) { \
*ch_ptr = *ch_ptr & (~ch_mask); \
} \
ch_mask = ch_mask << ch_shift_amount; \
\
if(reparse) { \
ch_mask = - (1 << (32 - bits_per_line)); \
}
#define CH_LOOP_A2_VID(ch_mask, ch_tmp) \
ch_tmp = ch_mask & 0x80000000; \
ch_mask = ch_mask << 1; \
\
if(!ch_tmp) { \
continue; \
}
void
redraw_changed_text_40(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val,
int pixels_per_line)
{
register word32 start_time, end_time;
word32 *img_ptr, *img_ptr2;
word32 *save_img_ptr, *save_img_ptr2;
word32 *ch_ptr;
const word32 *font_ptr1;
const word32 *font_ptr2;
byte *slow_mem_ptr;
byte *b_ptr;
word32 ch_mask;
word32 ch_tmp;
word32 line_mask;
word32 mask_per_line;
word32 mem_ptr;
word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
word32 palette_add;
word32 diff_val;
word32 and_val;
word32 add_val;
word32 ff_val;
word32 val0, val1;
int flash_state;
int y;
int x1, x2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line_mod8, st_line;
int i;
/* always redraws to the next multiple of 8 lines due to redraw */
/* issues: char changed on one screen redraw at line 0 with */
/* num_lines=1. We need to have drawn lines 1-7 also since line 1 */
/* will not see any changed bytes */
st_line_mod8 = start_line & 7;
st_line = start_line;
start_line = start_line >> 3;
y = start_line;
line_mask = 1 << (y);
mem_ptr = 0x400 + g_screen_index[y] + start_offset;
if(mem_ptr < 0x400 || mem_ptr >= 0xc00) {
halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr);
}
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0));
/* avoid clearing changed bits unless we are line 0 (mod 8) */
if(ch_mask == 0) {
return;
}
GET_ITIMER(start_time);
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
diff_val = (fg_val - bg_val) & 0xf;
and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24);
add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24);
ff_val = 0x0f0f0f0f;
flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE);
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(8*y + st_line_mod8)*2*pixels_per_line +
x1*14];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + pixels_per_line);
for(x2 = 0; x2 < shift_per; x2 += 2) {
val0 = *slow_mem_ptr++;
val1 = *slow_mem_ptr++;
if(!altcharset) {
if(val0 >= 0x40 && val0 < 0x80) {
if(flash_state) {
val0 += 0x40;
} else {
val0 -= 0x40;
}
}
if(val1 >= 0x40 && val1 < 0x80) {
if(flash_state) {
val1 += 0x40;
} else {
val1 -= 0x40;
}
}
}
save_img_ptr = img_ptr;
save_img_ptr2 = img_ptr2;
for(i = st_line_mod8; i < 8; i++) {
font_ptr1 = &(g_font40_even_bits[val0][i][0]);
tmp0 = (font_ptr1[0] & and_val) + add_val;
tmp1 = (font_ptr1[1] & and_val) + add_val;
tmp2 = (font_ptr1[2] & and_val) + add_val;
font_ptr2 = &(g_font40_odd_bits[val1][i][0]);
tmp3 = ((font_ptr1[3]+font_ptr2[0]) & and_val)+
add_val;
tmp4 = (font_ptr2[1] & and_val) + add_val;
tmp5 = (font_ptr2[2] & and_val) + add_val;
tmp6 = (font_ptr2[3] & and_val) + add_val;
tmp0 = (tmp0 & ff_val) + palette_add;
tmp1 = (tmp1 & ff_val) + palette_add;
tmp2 = (tmp2 & ff_val) + palette_add;
tmp3 = (tmp3 & ff_val) + palette_add;
tmp4 = (tmp4 & ff_val) + palette_add;
tmp5 = (tmp5 & ff_val) + palette_add;
tmp6 = (tmp6 & ff_val) + palette_add;
img_ptr[0] = tmp0;
img_ptr[1] = tmp1;
img_ptr[2] = tmp2;
img_ptr[3] = tmp3;
img_ptr[4] = tmp4;
img_ptr[5] = tmp5;
img_ptr[6] = tmp6;
img_ptr2[0] = tmp0;
img_ptr2[1] = tmp1;
img_ptr2[2] = tmp2;
img_ptr2[3] = tmp3;
img_ptr2[4] = tmp4;
img_ptr2[5] = tmp5;
img_ptr2[6] = tmp6;
img_ptr += (2*pixels_per_line)/4;
img_ptr2 += (2*pixels_per_line)/4;
}
img_ptr = save_img_ptr + 7;
img_ptr2 = save_img_ptr2 + 7;
}
}
GET_ITIMER(end_time);
for(i = 0; i < (8 - st_line_mod8); i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
if(left >= right || left < 0 || right < 0) {
printf("line %d, 40: left >= right: %d >= %d\n",
start_line, left, right);
}
g_cycs_in_40col += (end_time - start_time);
g_need_redraw = 0;
}
void
redraw_changed_text_80(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int altcharset, int bg_val, int fg_val,
int pixels_per_line)
{
const word32 *font_ptr0, *font_ptr1, *font_ptr2, *font_ptr3;
word32 *ch_ptr;
word32 *img_ptr, *img_ptr2;
word32 *save_img_ptr, *save_img_ptr2;
byte *b_ptr;
byte *slow_mem_ptr;
word32 ch_mask;
word32 ch_tmp;
word32 mask_per_line;
word32 mem_ptr;
word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
word32 diff_val;
word32 add_val, and_val, ff_val;
word32 palette_add;
word32 line_mask;
word32 val0, val1, val2, val3;
int st_line_mod8, st_line;
int flash_state;
int y;
int x1, x2;
int i;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
st_line_mod8 = start_line & 7;
st_line = start_line;
start_line = start_line >> 3;
y = start_line;
line_mask = 1 << (y);
mem_ptr = 0x400 + g_screen_index[y] + start_offset;
if(mem_ptr < 0x400 || mem_ptr >= 0xc00) {
halt_printf("redraw_changed_text: mem_ptr: %08x\n", mem_ptr);
}
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0));
if(ch_mask == 0) {
return;
}
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
diff_val = (fg_val - bg_val) & 0xf;
add_val = bg_val + (bg_val << 8) + (bg_val << 16) + (bg_val << 24);
and_val = diff_val + (diff_val << 8) + (diff_val << 16) +(diff_val<<24);
ff_val = 0x0f0f0f0f;
flash_state = (g_cur_a2_stat & ALL_STAT_FLASH_STATE);
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line +
x1*14];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + pixels_per_line);
for(x2 = 0; x2 < shift_per; x2 += 2) {
/* do 4 chars at once! */
val1 = slow_mem_ptr[0];
val3 = slow_mem_ptr[1];
val0 = slow_mem_ptr[0x10000];
val2 = slow_mem_ptr[0x10001];
slow_mem_ptr += 2;
if(!altcharset) {
if(val0 >= 0x40 && val0 < 0x80) {
if(flash_state) {
val0 += 0x40;
} else {
val0 -= 0x40;
}
}
if(val1 >= 0x40 && val1 < 0x80) {
if(flash_state) {
val1 += 0x40;
} else {
val1 -= 0x40;
}
}
if(val2 >= 0x40 && val2 < 0x80) {
if(flash_state) {
val2 += 0x40;
} else {
val2 -= 0x40;
}
}
if(val3 >= 0x40 && val3 < 0x80) {
if(flash_state) {
val3 += 0x40;
} else {
val3 -= 0x40;
}
}
}
save_img_ptr = img_ptr;
save_img_ptr2 = img_ptr2;
for(i = st_line_mod8; i < 8; i++) {
font_ptr0 = &(g_font80_off0_bits[val0][i][0]);
tmp0 = (font_ptr0[0] & and_val) + add_val;
font_ptr3 = &(g_font80_off3_bits[val1][i][0]);
tmp1 = ((font_ptr0[1]+font_ptr3[0]) & and_val)+
add_val;
/* 3 bytes from ptr0, 1 from ptr3 */
tmp2 = (font_ptr3[1] & and_val) + add_val;
font_ptr2 = &(g_font80_off2_bits[val2][i][0]);
tmp3 = ((font_ptr3[2]+font_ptr2[0]) & and_val)+
add_val;
/* 2 bytes from ptr3, 2 from ptr2*/
tmp4 = (font_ptr2[1] & and_val) + add_val;
font_ptr1 = &(g_font80_off1_bits[val3][i][0]);
tmp5 = ((font_ptr2[2]+font_ptr1[0]) & and_val)+
add_val;
/* 1 byte from ptr2, 3 from ptr1 */
tmp6 = (font_ptr1[1] & and_val) + add_val;
tmp0 = (tmp0 & ff_val) + palette_add;
tmp1 = (tmp1 & ff_val) + palette_add;
tmp2 = (tmp2 & ff_val) + palette_add;
tmp3 = (tmp3 & ff_val) + palette_add;
tmp4 = (tmp4 & ff_val) + palette_add;
tmp5 = (tmp5 & ff_val) + palette_add;
tmp6 = (tmp6 & ff_val) + palette_add;
img_ptr[0] = tmp0;
img_ptr[1] = tmp1;
img_ptr[2] = tmp2;
img_ptr[3] = tmp3;
img_ptr[4] = tmp4;
img_ptr[5] = tmp5;
img_ptr[6] = tmp6;
img_ptr2[0] = tmp0;
img_ptr2[1] = tmp1;
img_ptr2[2] = tmp2;
img_ptr2[3] = tmp3;
img_ptr2[4] = tmp4;
img_ptr2[5] = tmp5;
img_ptr2[6] = tmp6;
img_ptr += (2*pixels_per_line)/4;
img_ptr2 += (2*pixels_per_line)/4;
}
img_ptr = save_img_ptr + 7;
img_ptr2 = save_img_ptr2 + 7;
}
}
for(i = 0; i < (8 - st_line_mod8); i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
if(left >= right || left < 0 || right < 0) {
printf("line %d, 80: left >= right: %d >= %d\n",
start_line, left, right);
}
g_need_redraw = 0;
}
void
redraw_changed_gr(int start_offset, int start_line, int num_lines, int reparse,
byte *screen_data, int pixels_per_line)
{
word32 *img_ptr;
word32 *save_img_ptr;
word32 *ch_ptr;
byte *b_ptr;
byte *slow_mem_ptr;
word32 mask_per_line;
word32 ch_mask;
word32 ch_tmp;
word32 mem_ptr;
word32 line_mask;
word32 val0, val1;
word32 val0_wd, val1_wd;
word32 val01_wd;
word32 val_even, val_odd;
word32 palette_add;
int half;
int x1, x2;
int y;
int y2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line_mod8, st_line, eff_line, end_line;
int i;
st_line_mod8 = start_line & 7;
st_line = start_line;
end_line = 8; // st_line_mod8 + num_lines;
start_line = start_line >> 3;
y = start_line;
line_mask = 1 << y;
mem_ptr = 0x400 + g_screen_index[y] + start_offset;
if(mem_ptr < 0x400 || mem_ptr >= 0xc00) {
printf("redraw_changed_gr: mem_ptr: %08x\n", mem_ptr);
}
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0));
if(ch_mask == 0) {
return;
}
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line +
x1*14];
img_ptr = (word32 *)b_ptr;
for(x2 = 0; x2 < shift_per; x2 += 2) {
val_even = *slow_mem_ptr++;
val_odd = *slow_mem_ptr++;
save_img_ptr = img_ptr;
for(half = 0; half < 2; half++) {
val0 = val_even & 0xf;
val1 = val_odd & 0xf;
val0_wd = (val0 << 24) + (val0 << 16) +
(val0 << 8) + val0;
val1_wd = (val1 << 24) + (val1 << 16) +
(val1 << 8) + val1;
#ifdef KEGS_LITTLE_ENDIAN
val01_wd = (val1_wd << 16) + (val0_wd & 0xffff);
#else
val01_wd = (val0_wd << 16) + (val1_wd & 0xffff);
#endif
for(y2 = 0; y2 < 8; y2++) {
eff_line = half*4 + (y2 >> 1);
if((eff_line < st_line_mod8) ||
(eff_line > end_line)) {
continue;
}
img_ptr[0] = val0_wd + palette_add;
img_ptr[1] = val0_wd + palette_add;
img_ptr[2] = val0_wd + palette_add;
img_ptr[3] = val01_wd + palette_add;
img_ptr[4] = val1_wd + palette_add;
img_ptr[5] = val1_wd + palette_add;
img_ptr[6] = val1_wd + palette_add;
img_ptr += (pixels_per_line)/4;
}
val_even = val_even >> 4;
val_odd = val_odd >> 4;
}
img_ptr = save_img_ptr + 7;
}
}
for(i = 0; i < (8 - st_line_mod8); i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
g_need_redraw = 0;
}
void
redraw_changed_dbl_gr(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int pixels_per_line)
{
word32 *img_ptr;
word32 *save_img_ptr;
word32 *ch_ptr;
byte *b_ptr;
byte *slow_mem_ptr;
word32 mask_per_line;
word32 ch_mask;
word32 ch_tmp;
word32 mem_ptr;
word32 line_mask;
word32 val0, val1, val2, val3;
word32 val0_wd, val1_wd, val2_wd, val3_wd;
word32 val01_wd, val12_wd, val23_wd;
word32 val_even_main, val_odd_main;
word32 val_even_aux, val_odd_aux;
word32 palette_add;
int half;
int x1, x2;
int y;
int y2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line_mod8, st_line, eff_line, end_line;
int i;
st_line_mod8 = start_line & 7;
end_line = 8; // st_line_mod8 + num_lines
st_line = start_line;
start_line = start_line >> 3;
y = start_line;
line_mask = 1 << y;
mem_ptr = 0x400 + g_screen_index[y] + start_offset;
if(mem_ptr < 0x400 || mem_ptr >= 0xc00) {
printf("redraw_changed_dbl_gr: mem_ptr: %08x\n", mem_ptr);
}
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, (st_line_mod8 == 0));
if(ch_mask == 0) {
return;
}
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*8 + st_line_mod8)*2*pixels_per_line +
x1*14];
img_ptr = (word32 *)b_ptr;
for(x2 = 0; x2 < shift_per; x2 += 2) {
val_even_main = slow_mem_ptr[0];
val_odd_main = slow_mem_ptr[1];
val_even_aux = slow_mem_ptr[0x10000];
val_odd_aux = slow_mem_ptr[0x10001];
slow_mem_ptr += 2;
save_img_ptr = img_ptr;
for(half = 0; half < 2; half++) {
val0 = val_even_aux & 0xf;
val1 = val_even_main & 0xf;
val2 = val_odd_aux & 0xf;
val3 = val_odd_main & 0xf;
/* Handle funny pattern of dbl gr aux mem */
val0 = ((val0 << 1) & 0xf) + (val0 >> 3);
val2 = ((val2 << 1) & 0xf) + (val2 >> 3);
val0_wd = (val0 << 24) + (val0 << 16) +
(val0 << 8) + val0;
val1_wd = (val1 << 24) + (val1 << 16) +
(val1 << 8) + val1;
val2_wd = (val2 << 24) + (val2 << 16) +
(val2 << 8) + val2;
val3_wd = (val3 << 24) + (val3 << 16) +
(val3 << 8) + val3;
#ifdef KEGS_LITTLE_ENDIAN
val01_wd = (val1_wd << 24) + (val0_wd&0xffffff);
val12_wd = (val2_wd << 16) + (val1_wd & 0xffff);
val23_wd = (val3_wd << 8) + (val2_wd & 0xff);
#else
val01_wd = (val0_wd << 8) + (val1_wd & 0xff);
val12_wd = (val1_wd << 16) + (val2_wd & 0xffff);
val23_wd = (val2_wd << 24) + (val3_wd&0xffffff);
#endif
for(y2 = 0; y2 < 8; y2++) {
eff_line = half*4 + (y2 >> 1);
if((eff_line < st_line_mod8) ||
(eff_line > end_line)) {
continue;
}
img_ptr[0] = val0_wd + palette_add;
img_ptr[1] = val01_wd + palette_add;
img_ptr[2] = val1_wd + palette_add;
img_ptr[3] = val12_wd + palette_add;
img_ptr[4] = val2_wd + palette_add;
img_ptr[5] = val23_wd + palette_add;
img_ptr[6] = val3_wd + palette_add;
img_ptr += (pixels_per_line)/4;
}
val_even_aux = val_even_aux >> 4;
val_even_main = val_even_main >> 4;
val_odd_aux = val_odd_aux >> 4;
val_odd_main = val_odd_main >> 4;
}
img_ptr = save_img_ptr + 7;
}
}
for(i = 0; i < (8 - st_line_mod8); i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
g_need_redraw = 0;
}
void
redraw_changed_hires(int start_offset, int start_line, int num_lines,
int color, int reparse, byte *screen_data, int pixels_per_line)
{
if(!color) {
redraw_changed_hires_color(start_offset, start_line, num_lines,
reparse, screen_data, pixels_per_line);
} else {
redraw_changed_hires_bw(start_offset, start_line, num_lines,
reparse, screen_data, pixels_per_line);
}
}
void
redraw_changed_hires_bw(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int pixels_per_line)
{
word32 *img_ptr, *img_ptr2;
word32 *ch_ptr;
byte *b_ptr;
byte *slow_mem_ptr;
word32 mask_per_line;
word32 ch_mask;
word32 ch_tmp;
word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
word32 mem_ptr;
word32 val0, val1;
word32 val_whole;
word32 line_mask;
word32 palette_add;
int y;
int x1, x2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line;
int i;
st_line = start_line;
start_line = start_line >> 3;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
for(y = st_line; y < (st_line + num_lines); y++) {
line_mask = 1 << (y >> 3);
mem_ptr = 0x2000 + (((y & 7) * 0x400) +
g_screen_index[y >> 3]) + start_offset;
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1);
if(ch_mask == 0) {
continue;
}
/* Hires depends on adjacent bits, so also reparse adjacent */
/* regions so that if bits on the edge change, redrawing is */
/* correct */
ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1);
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + pixels_per_line);
for(x2 = 0; x2 < shift_per; x2 += 2) {
val0 = *slow_mem_ptr++;
val1 = *slow_mem_ptr++;
val_whole = ((val1 & 0x7f) << 7) +(val0 & 0x7f);
tmp0 = g_bw_hires_convert[val_whole & 3];
val_whole = val_whole >> 2;
tmp1 = g_bw_hires_convert[val_whole & 3];
val_whole = val_whole >> 2;
tmp2 = g_bw_hires_convert[val_whole & 3];
val_whole = val_whole >> 2;
tmp3 = g_bw_hires_convert[val_whole & 3];
val_whole = val_whole >> 2;
tmp4 = g_bw_hires_convert[val_whole & 3];
val_whole = val_whole >> 2;
tmp5 = g_bw_hires_convert[val_whole & 3];
val_whole = val_whole >> 2;
tmp6 = g_bw_hires_convert[val_whole & 3];
img_ptr[0] = tmp0 + palette_add;
img_ptr[1] = tmp1 + palette_add;
img_ptr[2] = tmp2 + palette_add;
img_ptr[3] = tmp3 + palette_add;
img_ptr[4] = tmp4 + palette_add;
img_ptr[5] = tmp5 + palette_add;
img_ptr[6] = tmp6 + palette_add;
img_ptr2[0] = tmp0 + palette_add;
img_ptr2[1] = tmp1 + palette_add;
img_ptr2[2] = tmp2 + palette_add;
img_ptr2[3] = tmp3 + palette_add;
img_ptr2[4] = tmp4 + palette_add;
img_ptr2[5] = tmp5 + palette_add;
img_ptr2[6] = tmp6 + palette_add;
img_ptr += 7;
img_ptr2 += 7;
}
}
}
for(i = 0; i < num_lines; i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
g_need_redraw = 0;
}
void
redraw_changed_hires_color(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int pixels_per_line)
{
word32 *img_ptr, *img_ptr2;
word32 *ch_ptr;
byte *b_ptr;
byte *slow_mem_ptr;
word32 mask_per_line;
word32 ch_mask;
word32 ch_tmp;
word32 mem_ptr;
word32 val0, val1;
word32 val_whole;
word32 pix_val;
word32 line_mask;
word32 prev_pixel;
word32 prev_hi;
word32 loc_hi;
word32 val_hi;
word32 tmp_val;
word32 palette_add;
int y;
int x1, x2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line;
int i, j;
st_line = start_line;
start_line = start_line >> 3;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
for(y = st_line; y < (st_line + num_lines); y++) {
line_mask = 1 << (y >> 3);
mem_ptr = 0x2000 + (((y & 7) * 0x400) +
g_screen_index[y >> 3]) + start_offset;
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1);
if(ch_mask == 0) {
continue;
}
/* Hires depends on adjacent bits, so also reparse adjacent */
/* regions so that if bits on the edge change, redrawing is */
/* correct */
ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1);
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + pixels_per_line);
prev_pixel = 0;
prev_hi = 0;
if(x1 > 0) {
tmp_val = slow_mem_ptr[-1];
prev_pixel = (tmp_val >> 6) & 1;
prev_hi = (tmp_val >> 7) & 0x1;
}
for(x2 = 0; x2 < shift_per; x2 += 2) {
val0 = *slow_mem_ptr++;
val1 = *slow_mem_ptr++;
val_whole = ((val1 & 0x7f) << 8) +
((val0 & 0x7f) << 1) +
prev_pixel;
loc_hi = prev_hi;
if(((val1 >> 7) & 1) != 0) {
loc_hi += 0x7f00;
}
if(((val0 >> 7) & 1) != 0) {
loc_hi += 0xfe;
}
prev_pixel = (val1 >> 6) & 1;
prev_hi = (val1 >> 7) & 1;
if((x1 + x2 + 2) < 40) {
tmp_val = slow_mem_ptr[0];
if(tmp_val & 1) {
val_whole |= 0x8000;
}
if(tmp_val & 0x80) {
loc_hi |= 0x8000;
}
}
loc_hi = loc_hi >> 1;
for(j = 0; j < 7; j++) {
tmp_val = val_whole & 0xf;
val_hi = loc_hi & 0x3;
pix_val = g_hires_convert[(val_hi<<4) +
tmp_val];
*img_ptr++ = pix_val + palette_add;
*img_ptr2++ = pix_val + palette_add;
val_whole = val_whole >> 2;
loc_hi = loc_hi >> 2;
}
}
}
}
for(i = 0; i < num_lines; i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
g_need_redraw = 0;
}
void
redraw_changed_dbl_hires(int start_offset, int start_line, int num_lines,
int color, int reparse, byte *screen_data, int pixels_per_line)
{
if(!color) {
redraw_changed_dbl_hires_color(start_offset, start_line,
num_lines, reparse, screen_data, pixels_per_line);
} else {
redraw_changed_dbl_hires_bw(start_offset, start_line,
num_lines, reparse, screen_data, pixels_per_line);
}
}
void
redraw_changed_dbl_hires_bw(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int pixels_per_line)
{
word32 *img_ptr, *img_ptr2;
word32 *ch_ptr;
byte *b_ptr;
byte *slow_mem_ptr;
word32 mask_per_line;
word32 ch_mask;
word32 ch_tmp;
word32 mem_ptr;
word32 val0, val1, val2, val3;
word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
word32 val_whole;
word32 line_mask;
word32 palette_add;
int y;
int x1, x2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line;
int i;
st_line = start_line;
start_line = start_line >> 3;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
for(y = st_line; y < (st_line + num_lines); y++) {
line_mask = 1 << (y >> 3);
mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] +
start_offset);
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1);
if(ch_mask == 0) {
continue;
}
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + pixels_per_line);
for(x2 = 0; x2 < shift_per; x2 += 2) {
val0 = slow_mem_ptr[0x10000];
val1 = slow_mem_ptr[0];
val2 = slow_mem_ptr[0x10001];
val3 = slow_mem_ptr[1];
slow_mem_ptr += 2;
val_whole = ((val3 & 0x7f) << 21) +
((val2 & 0x7f) << 14) +
((val1 & 0x7f) << 7) +
(val0 & 0x7f);
tmp0 = g_bw_dhires_convert[val_whole & 0xf];
val_whole = val_whole >> 4;
tmp1 = g_bw_dhires_convert[val_whole & 0xf];
val_whole = val_whole >> 4;
tmp2 = g_bw_dhires_convert[val_whole & 0xf];
val_whole = val_whole >> 4;
tmp3 = g_bw_dhires_convert[val_whole & 0xf];
val_whole = val_whole >> 4;
tmp4 = g_bw_dhires_convert[val_whole & 0xf];
val_whole = val_whole >> 4;
tmp5 = g_bw_dhires_convert[val_whole & 0xf];
val_whole = val_whole >> 4;
tmp6 = g_bw_dhires_convert[val_whole & 0xf];
img_ptr[0] = tmp0 + palette_add;
img_ptr[1] = tmp1 + palette_add;
img_ptr[2] = tmp2 + palette_add;
img_ptr[3] = tmp3 + palette_add;
img_ptr[4] = tmp4 + palette_add;
img_ptr[5] = tmp5 + palette_add;
img_ptr[6] = tmp6 + palette_add;
img_ptr2[0] = tmp0 + palette_add;
img_ptr2[1] = tmp1 + palette_add;
img_ptr2[2] = tmp2 + palette_add;
img_ptr2[3] = tmp3 + palette_add;
img_ptr2[4] = tmp4 + palette_add;
img_ptr2[5] = tmp5 + palette_add;
img_ptr2[6] = tmp6 + palette_add;
img_ptr += 7;
img_ptr2 += 7;
}
}
}
for(i = 0; i < num_lines; i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
g_need_redraw = 0;
}
void
redraw_changed_dbl_hires_color(int start_offset, int start_line, int num_lines,
int reparse, byte *screen_data, int pixels_per_line)
{
word32 *ch_ptr;
word32 *img_ptr, *img_ptr2;
byte *slow_mem_ptr;
byte *b_ptr;
word32 mask_per_line;
word32 ch_mask;
word32 ch_tmp;
word32 mem_ptr;
word32 val0, val1, val2, val3;
word32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
word32 val_whole;
word32 prev_val;
word32 line_mask;
word32 palette_add;
int y;
int x1, x2;
int ch_bitpos;
int bits_per_line;
int ch_shift_amount;
int shift_per;
int left, right;
int st_line;
int i;
st_line = start_line;
start_line = start_line >> 3;
palette_add = (g_a2vid_palette << 4);
palette_add = palette_add + (palette_add << 8) + (palette_add << 16) +
(palette_add << 24);
left = 40;
right = 0;
for(y = st_line; y < (st_line + num_lines); y++) {
line_mask = 1 << (y >> 3);
mem_ptr = 0x2000 + (((y & 7) * 0x400) + g_screen_index[y >> 3] +
start_offset);
CH_SETUP_A2_VID(mem_ptr, ch_mask, reparse, 1);
if(ch_mask == 0) {
continue;
}
/* dbl-hires also depends on adjacent bits, so reparse */
/* adjacent regions so that if bits on the edge change, */
/* redrawing is correct */
ch_mask = ch_mask | (ch_mask >> 1) | (ch_mask << 1);
ch_mask = -1;
shift_per = (1 << SHIFT_PER_CHANGE);
g_a2_screen_buffer_changed |= line_mask;
for(x1 = 0; x1 < 40; x1 += shift_per) {
CH_LOOP_A2_VID(ch_mask, ch_tmp);
left = MIN(x1, left);
right = MAX(x1 + shift_per, right);
slow_mem_ptr = &(g_slow_memory_ptr[mem_ptr + x1]);
b_ptr = &screen_data[(y*2)*pixels_per_line + x1*14];
img_ptr = (word32 *)b_ptr;
img_ptr2 = (word32 *)(b_ptr + pixels_per_line);
for(x2 = 0; x2 < shift_per; x2 += 2) {
val0 = slow_mem_ptr[0x10000];
val1 = slow_mem_ptr[0];
val2 = slow_mem_ptr[0x10001];
val3 = slow_mem_ptr[1];
prev_val = 0;
if((x1 + x2) > 0) {
prev_val = (slow_mem_ptr[-1] >> 3) &0xf;
}
val_whole = ((val3 & 0x7f) << 25) +
((val2 & 0x7f) << 18) +
((val1 & 0x7f) << 11) +
((val0 & 0x7f) << 4) + prev_val;
tmp0 = g_dhires_convert[val_whole & 0xfff];
val_whole = val_whole >> 4;
tmp1 = g_dhires_convert[val_whole & 0xfff];
val_whole = val_whole >> 4;
tmp2 = g_dhires_convert[val_whole & 0xfff];
val_whole = val_whole >> 4;
tmp3 = g_dhires_convert[val_whole & 0xfff];
val_whole = val_whole >> 4;
tmp4 = g_dhires_convert[val_whole & 0xfff];
val_whole = val_whole >> 4;
tmp5 = g_dhires_convert[val_whole & 0xfff];
val_whole = val_whole >> 4;
if((x1 + x2 + 2) < 40) {
val_whole += (slow_mem_ptr[0x10002]<<8);
}
tmp6 = g_dhires_convert[val_whole & 0xfff];
img_ptr[0] = tmp0 + palette_add;
img_ptr[1] = tmp1 + palette_add;
img_ptr[2] = tmp2 + palette_add;
img_ptr[3] = tmp3 + palette_add;
img_ptr[4] = tmp4 + palette_add;
img_ptr[5] = tmp5 + palette_add;
img_ptr[6] = tmp6 + palette_add;
img_ptr2[0] = tmp0 + palette_add;
img_ptr2[1] = tmp1 + palette_add;
img_ptr2[2] = tmp2 + palette_add;
img_ptr2[3] = tmp3 + palette_add;
img_ptr2[4] = tmp4 + palette_add;
img_ptr2[5] = tmp5 + palette_add;
img_ptr2[6] = tmp6 + palette_add;
slow_mem_ptr += 2;
img_ptr += 7;
img_ptr2 += 7;
}
}
}
for(i = 0; i < num_lines; i++) {
g_a2_line_left_edge[st_line + i] = (left*14);
g_a2_line_right_edge[st_line + i] = (right*14);
}
g_need_redraw = 0;
}
int
video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse)
{
word32 *word_ptr;
word32 *ch_ptr;
byte *byte_ptr;
word32 ch_mask, mask_per_line;
word32 tmp;
word32 scan, old_scan;
int palette_changed;
int diff0, diff1, diff2;
int val0, val1, val2;
int diffs;
int low_delta, low_color;
int delta;
int full;
int ch_bit_offset, ch_word_offset;
int bits_per_line;
int palette;
int j, k;
palette_changed = 0;
palette = scan_info & 0xf;
ch_ptr = &(slow_mem_changed[0x9e00 >> CHANGE_SHIFT]);
ch_bit_offset = (palette << 5) >> SHIFT_PER_CHANGE;
ch_word_offset = ch_bit_offset >> 5;
ch_bit_offset = ch_bit_offset & 0x1f;
bits_per_line = (0x20 >> SHIFT_PER_CHANGE);
mask_per_line = -(1 << (32 - bits_per_line));
mask_per_line = mask_per_line >> ch_bit_offset;
ch_mask = ch_ptr[ch_word_offset] & mask_per_line;
ch_ptr[ch_word_offset] &= ~mask_per_line; /* clear the bits */
old_scan = g_superhires_scan_save[line];
scan = (scan_info & 0xfaf) + (g_palette_change_cnt[palette] << 12);
g_superhires_scan_save[line] = scan;
#if 0
if(line == 1) {
word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00+palette*0x20]);
printf("y1vrshp, ch:%08x, s:%08x,os:%08x %d = %08x %08x %08x %08x %08x %08x %08x %08x\n",
ch_mask, scan, old_scan, reparse,
word_ptr[0], word_ptr[1], word_ptr[2], word_ptr[3],
word_ptr[4], word_ptr[5], word_ptr[6], word_ptr[7]);
}
#endif
diffs = reparse | ((scan ^ old_scan) & 0xf0f);
/* we must do full reparse if palette changed for this line */
if(!diffs && (ch_mask == 0) && (((scan ^ old_scan) & (~0xf0)) == 0)) {
/* nothing changed, get out fast */
return 0;
}
if(ch_mask) {
/* indicates the palette has changed, and other scan lines */
/* using this palette need to do a full 32-byte compare to */
/* decide if they need to update or not */
g_palette_change_cnt[palette]++;
}
word_ptr = (word32 *)&(g_slow_memory_ptr[0x19e00 + palette*0x20]);
for(j = 0; j < 8; j++) {
if(word_ptr[j] != g_saved_line_palettes[line][j]) {
diffs = 1;
break;
}
}
if(diffs == 0) {
return 0;
}
/* first, save this word_ptr into saved_line_palettes */
byte_ptr = (byte *)word_ptr;
for(j = 0; j < 8; j++) {
g_saved_line_palettes[line][j] = word_ptr[j];
}
full = g_installed_full_superhires_colormap;
if(!full && palette == g_a2vid_palette) {
/* construct new color approximations from lores */
for(j = 0; j < 16; j++) {
tmp = *byte_ptr++;
val2 = (*byte_ptr++) & 0xf;
val0 = tmp & 0xf;
val1 = (tmp >> 4) & 0xf;
low_delta = 0x1000;
low_color = 0x0;
for(k = 0; k < 16; k++) {
diff0 = g_expanded_col_0[k] - val0;
diff1 = g_expanded_col_1[k] - val1;
diff2 = g_expanded_col_2[k] - val2;
if(diff0 < 0) {
diff0 = -diff0;
}
if(diff1 < 0) {
diff1 = -diff1;
}
if(diff2 < 0) {
diff2 = -diff2;
}
delta = diff0 + diff1 + diff2;
if(delta < low_delta) {
low_delta = delta;
low_color = k;
}
}
g_a2vid_palette_remap[j] = low_color;
}
}
byte_ptr = (byte *)word_ptr;
/* this palette has changed */
for(j = 0; j < 16; j++) {
val0 = *byte_ptr++;
val1 = *byte_ptr++;
video_update_color_array(palette*16 + j, (val1<<8) + val0);
}
g_palette_change_summary = 1;
return 1;
}
#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_8
#define SUPER_FILL 0
#define SUPER_PIXEL_SIZE 8
#include "superhires.h"
#undef SUPER_TYPE
#undef SUPER_FILL
#undef SUPER_PIXEL_SIZE
#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_16
#define SUPER_FILL 0
#define SUPER_PIXEL_SIZE 16
#include "superhires.h"
#undef SUPER_TYPE
#undef SUPER_FILL
#undef SUPER_PIXEL_SIZE
#define SUPER_TYPE redraw_changed_super_hires_oneline_nofill_32
#define SUPER_FILL 0
#define SUPER_PIXEL_SIZE 32
#include "superhires.h"
#undef SUPER_TYPE
#undef SUPER_FILL
#undef SUPER_PIXEL_SIZE
#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_8
#define SUPER_FILL 1
#define SUPER_PIXEL_SIZE 8
#include "superhires.h"
#undef SUPER_TYPE
#undef SUPER_FILL
#undef SUPER_PIXEL_SIZE
#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_16
#define SUPER_FILL 1
#define SUPER_PIXEL_SIZE 16
#include "superhires.h"
#undef SUPER_TYPE
#undef SUPER_FILL
#undef SUPER_PIXEL_SIZE
#define SUPER_TYPE redraw_changed_super_hires_oneline_fill_32
#define SUPER_FILL 1
#define SUPER_PIXEL_SIZE 32
#include "superhires.h"
#undef SUPER_TYPE
#undef SUPER_FILL
#undef SUPER_PIXEL_SIZE
void
redraw_changed_super_hires(int start_offset, int start_line, int num_lines,
int in_reparse, byte *screen_data)
{
word32 *ch_ptr;
word32 mask_per_line;
word32 all_checks;
word32 check0, check1, mask0, mask1;
word32 this_check;
word32 tmp;
word32 line_mask;
word32 pal;
word32 scan, old_scan;
word32 kd_tmp_debug;
int y;
int bits_per_line;
int a2vid_palette;
int type;
int left, right;
int st_line;
int check_bit_pos, check_word_off;
int pixel_size, pixel_size_type;
int use_a2vid_palette, mode_640;
int pixels_per_line;
int ret;
int i;
st_line = start_line;
start_line = start_line >> 3;
pixel_size = g_kimage_superhires.mdepth;
pixels_per_line = g_kimage_superhires.width_act;
pixel_size_type = (pixel_size >> 3) - 1;
/* pixel_size_type is now: 0=8bit, 1=16bit, 3=32bit */
if(pixel_size_type >= 3) {
pixel_size_type = 2;
}
kd_tmp_debug = g_a2_screen_buffer_changed;
line_mask = 1 << (start_line);
ch_ptr = &(slow_mem_changed[(0x2000) >> CHANGE_SHIFT]);
bits_per_line = 160 >> SHIFT_PER_CHANGE;
mask_per_line = -(1 << (32 - bits_per_line));
if(SHIFT_PER_CHANGE != 3) {
halt_printf("SHIFT_PER_CHANGE must be 3!\n");
return;
}
a2vid_palette = g_a2vid_palette;
if(g_installed_full_superhires_colormap) {
a2vid_palette = -1;
} else {
/* handle palette counting for finding least-used palette */
if(pixel_size == 8) {
for(y = 8*start_line; y < 8*(start_line + 1); y++) {
scan = g_slow_memory_ptr[0x19d00 + y];
pal = scan & 0xf;
g_shr_palette_used[pal]++;
}
}
}
all_checks = 0;
check0 = 0;
check1 = 0;
for(y = st_line; y < (st_line + num_lines); y++) {
scan = g_slow_memory_ptr[0x19d00 + y];
check_bit_pos = bits_per_line * y;
check_word_off = check_bit_pos >> 5; /* 32 bits per word */
check_bit_pos = check_bit_pos & 0x1f; /* 5-bit bit_pos */
check0 = ch_ptr[check_word_off];
check1 = ch_ptr[check_word_off+1];
mask0 = mask_per_line >> check_bit_pos;
mask1 = 0;
this_check = check0 << check_bit_pos;
/* move indicated bit to MSbit position */
if((check_bit_pos + bits_per_line) > 32) {
this_check |= (check1 >> (32 - check_bit_pos));
mask1 = mask_per_line << (32 - check_bit_pos);
}
ch_ptr[check_word_off] = check0 & ~mask0;
ch_ptr[check_word_off+1] = check1 & ~mask1;
this_check = this_check & mask_per_line;
old_scan = g_superhires_scan_save[y];
use_a2vid_palette = ((scan & 0xf) == (word32)a2vid_palette);
scan = (scan + (a2vid_palette << 8)) & 0xfff;
ret = video_rebuild_super_hires_palette(scan, y, in_reparse);
#if 0
if(y == 1) {
printf("y1, ch:%08x, ret:%d, scan:%03x, os:%03x\n",
this_check, ret, scan, old_scan);
}
#endif
if(ret || in_reparse || ((scan ^ old_scan) & 0xa0)) {
/* 0x80 == mode640, 0x20 = fill */
this_check = -1;
}
if(this_check == 0) {
continue;
}
mode_640 = (scan & 0x80);
if(mode_640) {
g_num_lines_superhires640++;
}
type = ((scan >> 5) & 1) + (pixel_size_type << 1);
if(type & 1) {
/* fill mode--redraw whole line */
this_check = -1;
}
all_checks |= this_check;
g_a2_screen_buffer_changed |= line_mask;
switch(type) {
case 0: /* nofill, 8 bit pixels */
redraw_changed_super_hires_oneline_nofill_8(
screen_data, pixels_per_line, y, scan,
this_check, use_a2vid_palette, mode_640);
break;
case 1: /* fill, 8 bit pixels */
redraw_changed_super_hires_oneline_fill_8(
screen_data, pixels_per_line, y, scan,
this_check, use_a2vid_palette, mode_640);
break;
case 2: /* nofill, 16 bit pixels */
redraw_changed_super_hires_oneline_nofill_16(
screen_data, pixels_per_line, y, scan,
this_check, use_a2vid_palette, mode_640);
break;
case 3: /* fill, 16 bit pixels */
redraw_changed_super_hires_oneline_fill_16(
screen_data, pixels_per_line, y, scan,
this_check, use_a2vid_palette, mode_640);
break;
case 4: /* nofill, 32 bit pixels */
redraw_changed_super_hires_oneline_nofill_32(
screen_data, pixels_per_line, y, scan,
this_check, use_a2vid_palette, mode_640);
break;
case 5: /* fill, 32 byte pixels */
redraw_changed_super_hires_oneline_fill_32(
screen_data, pixels_per_line, y, scan,
this_check, use_a2vid_palette, mode_640);
break;
default:
halt_printf("type: %d bad!\n", type);
}
}
left = 4*40;
right = 0;
tmp = all_checks;
if(all_checks) {
for(i = 0; i < 160; i += 8) {
if(tmp & 0x80000000) {
left = MIN(i, left);
right = MAX(i + 8, right);
}
tmp = tmp << 1;
}
}
for(i = 0; i < num_lines; i++) {
g_a2_line_left_edge[st_line + i] = 4*left;
g_a2_line_right_edge[st_line + i] = 4*right;
}
#if 0
if((g_a2_screen_buffer_changed & (1 << start_line)) != 0) {
if(((g_full_refresh_needed & (1 << start_line)) == 0) &&
left >= right) {
halt_printf("shr: line: %d, left: %d, right:%d\n",
start_line, left, right);
printf("mask_per_line: %08x, all_checks: %08x\n",
mask_per_line, all_checks);
printf("check0,1 = %08x,%08x\n", check0, check1);
printf("a2_screen_chang: %08x\n", kd_tmp_debug);
#ifdef HPUX
U_STACK_TRACE();
#endif
}
}
#endif
g_need_redraw = 0;
}
void
display_screen()
{
video_update_through_line(262);
}
void
video_update_event_line(int line)
{
int new_line;
video_update_through_line(line);
new_line = line + g_line_ref_amt;
if(new_line < 200) {
if(!g_config_control_panel) {
add_event_vid_upd(new_line);
}
} else if(line >= 262) {
video_update_through_line(0);
if(!g_config_control_panel) {
add_event_vid_upd(1); /* add event for new screen */
}
}
if(g_video_extra_check_inputs) {
if(g_video_dcycs_check_input < g_cur_dcycs) {
video_check_input_events();
}
}
}
void
video_check_input_events()
{
word32 start_time, end_time;
g_video_dcycs_check_input = g_cur_dcycs + 4000.0;
GET_ITIMER(start_time);
check_input_events();
GET_ITIMER(end_time);
g_cycs_in_check_input += (end_time - start_time);
}
void
video_update_through_line(int line)
{
register word32 start_time;
register word32 end_time;
int *mode_ptr;
word32 mask;
int last_line, num_lines;
int must_reparse;
int new_all_stat, prev_all_stat;
int new_stat, prev_stat;
int i;
#if 0
vid_printf("\nvideo_upd for line %d, lines: %06x\n", line,
get_lines_since_vbl(g_cur_dcycs));
#endif
GET_ITIMER(start_time);
video_update_all_stat_through_line(line);
i = g_vid_update_last_line;
last_line = MIN(200, line+1); /* go through line, but not past 200 */
prev_stat = -2;
prev_all_stat = -2;
num_lines = 0;
must_reparse = 0;
for(i = g_vid_update_last_line; i < last_line; i++) {
new_all_stat = g_a2_new_all_stat[i];
if(new_all_stat != g_a2_cur_all_stat[i]) {
/* regen line_stat for this line */
g_a2_cur_all_stat[i] = new_all_stat;
if(new_all_stat == prev_all_stat) {
/* save a lookup */
new_stat = prev_stat;
} else {
new_stat = video_all_stat_to_line_stat(i,
new_all_stat);
}
if(new_stat != g_a2_line_stat[i]) {
/* status changed */
g_a2_line_stat[i] = new_stat;
mode_ptr = video_update_kimage_ptr(i, new_stat);
if(mode_ptr[i] != new_stat) {
must_reparse = 1;
mode_ptr[i] = new_stat;
}
mask = 1 << (line >> 3);
g_full_refresh_needed |= mask;
g_a2_screen_buffer_changed |= mask;
}
}
new_stat = g_a2_line_stat[i];
if( ((new_stat == prev_stat) && ((i & 7) != 0)) ||
(num_lines == 0) ) {
/* merge prev and this together */
prev_stat = new_stat;
num_lines++;
continue;
}
/* else, we must call refresh */
video_refresh_lines(i - num_lines, num_lines, must_reparse);
num_lines = 1;
prev_all_stat = -1;
prev_stat = new_stat;
must_reparse = 0;
}
if(num_lines > 0) {
video_refresh_lines(i - num_lines, num_lines, must_reparse);
}
g_vid_update_last_line = last_line;
/* deal with border */
if(line >= 262) {
if(g_num_lines_prev_superhires != g_num_lines_superhires) {
/* switched in/out from superhires--refresh borders */
g_border_sides_refresh_needed = 1;
}
refresh_border();
if(g_status_refresh_needed) {
g_status_refresh_needed = 0;
x_redraw_status_lines();
}
}
GET_ITIMER(end_time);
g_cycs_in_refresh_line += (end_time - start_time);
if(line >= 262) {
GET_ITIMER(start_time);
if(g_palette_change_summary) {
g_palette_change_summary = 0;
video_update_colormap();
}
video_push_kimages();
GET_ITIMER(end_time);
g_cycs_in_refresh_ximage += (end_time - start_time);
g_num_lines_prev_superhires = g_num_lines_superhires;
g_num_lines_prev_superhires640 = g_num_lines_superhires640;
g_num_lines_superhires = 0;
g_num_lines_superhires640 = 0;
}
}
void
video_refresh_lines(int st_line, int num_lines, int must_reparse)
{
byte *ptr;
int line;
int stat;
int mode;
int dbl, page, color;
int altchar, bg_color, text_color;
int pixels_per_line;
int i;
line = st_line;
/* do some basic checking, num_lines should be 1-8, and */
/* st_line+num_lines-1 cannot roll over 8 */
if((num_lines < 1) || (num_lines > 8) ||
(((st_line & 7) + num_lines) > 8) ) {
halt_printf("video_refresh_lines called with %d, %d\n",
st_line, num_lines);
return;
}
stat = g_a2_line_stat[line];
ptr = g_a2_line_kimage[line]->data_ptr;
pixels_per_line = g_a2_line_kimage[line]->width_act;
/* do not zero g_a2_line_left/right_edge here since text/gr routs */
/* need to leave stale values around for drawing to work correctly */
/* all routs force in new left/right when there are screen changes */
dbl = stat & 1;
color = (stat >> 1) & 1;
page = (stat >> 2) & 1;
mode = (stat >> 4) & 7;
#if 0
printf("refresh line: %d, stat: %04x\n", line, stat);
#endif
switch(mode) {
case MODE_TEXT:
altchar = (stat >> 7) & 1;
bg_color = (stat >> 8) & 0xf;
text_color = (stat >> 12) & 0xf;
if(dbl) {
redraw_changed_text_80(0x000 + page*0x400, st_line,
num_lines, must_reparse, ptr, altchar, bg_color,
text_color, pixels_per_line);
} else {
redraw_changed_text_40(0x000 + page*0x400, st_line,
num_lines, must_reparse, ptr, altchar, bg_color,
text_color, pixels_per_line);
}
break;
case MODE_GR:
if(dbl) {
redraw_changed_dbl_gr(0x000 + page*0x400, st_line,
num_lines, must_reparse, ptr, pixels_per_line);
} else {
redraw_changed_gr(0x000 + page*0x400, st_line,
num_lines, must_reparse, ptr, pixels_per_line);
}
break;
case MODE_HGR:
if(dbl) {
redraw_changed_dbl_hires(0x000 + page*0x2000, st_line,
num_lines, color, must_reparse, ptr,
pixels_per_line);
} else {
redraw_changed_hires(0x000 + page*0x2000, st_line,
num_lines, color, must_reparse, ptr,
pixels_per_line);
}
break;
case MODE_SUPER_HIRES:
g_num_lines_superhires++;
redraw_changed_super_hires(0, st_line, num_lines,
must_reparse, ptr);
break;
case MODE_BORDER:
if(line < 192) {
halt_printf("Border line not 192: %d\n", line);
}
for(i = 0; i < num_lines; i++) {
g_a2_line_left_edge[line + i] = 0;
g_a2_line_right_edge[line + i] = 560;
}
if(g_border_line24_refresh_needed) {
g_border_line24_refresh_needed = 0;
g_a2_screen_buffer_changed |= (1 << 24);
}
break;
default:
halt_printf("refresh screen: mode: 0x%02x unknown!\n", mode);
exit(7);
}
}
void
refresh_border()
{
/**ZZZZ***/
}
void
end_screen()
{
printf("In end_screen\n");
xdriver_end();
}
byte g_font_array[256][8] = {
#include "kegsfont.h"
};
void
read_a2_font()
{
byte *f40_e_ptr;
byte *f40_o_ptr;
byte *f80_0_ptr, *f80_1_ptr, *f80_2_ptr, *f80_3_ptr;
int char_num;
int j, k;
int val0;
int mask;
int pix;
for(char_num = 0; char_num < 0x100; char_num++) {
for(j = 0; j < 8; j++) {
val0 = g_font_array[char_num][j];
mask = 0x80;
for(k = 0; k < 3; k++) {
g_font80_off0_bits[char_num][j][k] = 0;
g_font80_off1_bits[char_num][j][k] = 0;
g_font80_off2_bits[char_num][j][k] = 0;
g_font80_off3_bits[char_num][j][k] = 0;
g_font40_even_bits[char_num][j][k] = 0;
g_font40_odd_bits[char_num][j][k] = 0;
}
g_font40_even_bits[char_num][j][3] = 0;
g_font40_odd_bits[char_num][j][3] = 0;
f40_e_ptr = (byte *)&g_font40_even_bits[char_num][j][0];
f40_o_ptr = (byte *)&g_font40_odd_bits[char_num][j][0];
f80_0_ptr = (byte *)&g_font80_off0_bits[char_num][j][0];
f80_1_ptr = (byte *)&g_font80_off1_bits[char_num][j][0];
f80_2_ptr = (byte *)&g_font80_off2_bits[char_num][j][0];
f80_3_ptr = (byte *)&g_font80_off3_bits[char_num][j][0];
for(k = 0; k < 7; k++) {
pix = 0;
if(val0 & mask) {
pix = 0xf;
}
f40_e_ptr[2*k] = pix;
f40_e_ptr[2*k+1] = pix;
f40_o_ptr[2*k+2] = pix;
f40_o_ptr[2*k+3] = pix;
f80_0_ptr[k] = pix;
f80_1_ptr[k+1] = pix;
f80_2_ptr[k+2] = pix;
f80_3_ptr[k+3] = pix;
mask = mask >> 1;
}
}
}
}
/* Helper routine for the *driver.c files */
void
video_get_kimage(Kimage *kimage_ptr, int extend_info, int depth, int mdepth)
{
int width;
int height;
width = A2_WINDOW_WIDTH;
height = A2_WINDOW_HEIGHT;
if(extend_info & 1) {
/* Border at top and bottom of screen */
width = X_A2_WINDOW_WIDTH;
height = X_A2_WINDOW_HEIGHT - A2_WINDOW_HEIGHT + 2*8;
}
if(extend_info & 2) {
/* Border at sides of screen */
width = BORDER_WIDTH + EFF_BORDER_WIDTH;
height = A2_WINDOW_HEIGHT;
}
kimage_ptr->dev_handle = 0;
kimage_ptr->dev_handle2 = 0;
kimage_ptr->data_ptr = 0;
kimage_ptr->width_req = width;
kimage_ptr->width_act = width;
kimage_ptr->height = height;
kimage_ptr->depth = depth;
kimage_ptr->mdepth = mdepth;
kimage_ptr->aux_info = 0;
x_get_kimage(kimage_ptr);
}
void
video_get_kimages()
{
video_get_kimage(&g_kimage_text[0], 0, 8, 8);
video_get_kimage(&g_kimage_text[1], 0, 8, 8);
video_get_kimage(&g_kimage_hires[0], 0, 8, 8);
video_get_kimage(&g_kimage_hires[1], 0, 8, 8);
video_get_kimage(&g_kimage_superhires, 0, g_screen_depth,
g_screen_mdepth);
video_get_kimage(&g_kimage_border_special, 1, g_screen_depth,
g_screen_mdepth);
video_get_kimage(&g_kimage_border_sides, 2, g_screen_depth,
g_screen_mdepth);
}
void
video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx,
int starty, int width, int height)
{
byte *indata, *inptr;
word32 *outdata32, *outptr32;
word16 *outdata16, *outptr16;
word32 *palptr;
int out_width, in_width;
int x, y;
indata = (byte *)kim_in->data_ptr;
outdata32 = (word32 *)kim_out->data_ptr;
outdata16 = (word16 *)kim_out->data_ptr;
if(kim_in == &g_kimage_superhires) {
palptr = &(g_palette_8to1624[0]);
} else {
palptr = &(g_a2palette_8to1624[0]);
}
if(kim_in->depth != 8) {
printf("x_convert_kimage_depth from non-8 bit depth: %p\n",
kim_in);
exit(1);
}
out_width = kim_out->width_act;
in_width = kim_in->width_act;
indata += (starty * in_width + startx);
outdata32 += (starty * out_width + startx);
outdata16 += (starty * out_width + startx);
if(kim_out->mdepth == 16) {
for(y = 0; y < height; y++) {
outptr16 = outdata16;
inptr = indata;
for(x = 0; x < width; x++) {
*outptr16++ = palptr[*inptr++];
}
outdata16 += out_width;
indata += in_width;
}
} else {
/* 32-bit depth */
for(y = 0; y < height; y++) {
outptr32 = outdata32;
inptr = indata;
for(x = 0; x < width; x++) {
*outptr32++ = palptr[*inptr++];
}
outdata32 += out_width;
indata += in_width;
}
}
}
void
video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix,
int right_pix)
{
int mdepth_mismatch;
int srcy;
if(left_pix >= right_pix || left_pix < 0 || right_pix <= 0) {
halt_printf("video_push_lines: lines %d to %d, pix %d to %d\n",
start_line, end_line, left_pix, right_pix);
printf("a2_screen_buf_ch:%08x, g_full_refr:%08x\n",
g_a2_screen_buffer_changed, g_full_refresh_needed);
}
srcy = 2*start_line;
mdepth_mismatch = (kimage_ptr->mdepth != g_screen_mdepth);
if(mdepth_mismatch) {
/* translate from 8-bit pseudo to correct visual */
video_convert_kimage_depth(kimage_ptr, &g_mainwin_kimage,
left_pix, srcy, (right_pix - left_pix),
2*(end_line - start_line));
kimage_ptr = &g_mainwin_kimage;
}
g_refresh_bytes_xfer += 2*(end_line - start_line) *
(right_pix - left_pix);
x_push_kimage(kimage_ptr, g_video_act_margin_left + left_pix,
g_video_act_margin_top + srcy, left_pix, srcy,
(right_pix - left_pix), 2*(end_line - start_line));
}
void
video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line,
int end_line)
{
Kimage *kimage_ptr;
int srcy;
if(start_line < 0 || width < 0) {
return;
}
#if 0
printf("push_border_sides lines:%d-%d from %d to %d\n",
start_line, end_line, end_x - width, end_x);
#endif
kimage_ptr = &g_kimage_border_sides;
g_refresh_bytes_xfer += 2 * (end_line - start_line) * width;
srcy = 2 * start_line;
// Adjust dext_x to accound for changed margins
dest_x = dest_x + g_video_act_margin_left - BASE_MARGIN_LEFT;
if(dest_x < BASE_MARGIN_LEFT) {
src_x = src_x + g_video_act_margin_left - BASE_MARGIN_LEFT;
// Don't adjust src_x if doing right border
}
if(dest_x < 0) {
width = width + dest_x;
src_x = src_x - dest_x;
dest_x = 0;
}
if(src_x < 0) {
width = width + src_x;
dest_x = dest_x - src_x;
src_x = 0;
}
if(dest_x + width > g_video_act_width) {
width = g_video_act_width - dest_x;
}
if(width > 0) {
x_push_kimage(kimage_ptr, dest_x, g_video_act_margin_top + srcy,
src_x, srcy, width, 2*(end_line - start_line));
}
}
void
video_push_border_sides()
{
int old_width;
int prev_line;
int width;
int mode;
int i;
#if 0
printf("refresh border sides!\n");
#endif
/* redraw left sides */
video_push_border_sides_lines(0, 0, BORDER_WIDTH, 0, 200);
/* right side--can be "jagged" */
prev_line = -1;
old_width = -1;
for(i = 0; i < 200; i++) {
mode = (g_a2_line_stat[i] >> 4) & 7;
width = EFF_BORDER_WIDTH;
if(mode == MODE_SUPER_HIRES) {
width = BORDER_WIDTH;
}
if(width != old_width) {
video_push_border_sides_lines(BORDER_WIDTH,
X_A2_WINDOW_WIDTH - old_width, old_width,
prev_line, i);
prev_line = i;
old_width = width;
}
}
video_push_border_sides_lines(BORDER_WIDTH,
X_A2_WINDOW_WIDTH - old_width, old_width, prev_line, 200);
}
void
video_push_border_special()
{
Kimage *kimage_ptr;
int width, height;
int src_x, src_y;
int dest_x, dest_y;
kimage_ptr = &g_kimage_border_special;
width = g_video_act_width;
g_refresh_bytes_xfer += width * (BASE_MARGIN_TOP + BASE_MARGIN_BOTTOM);
// First do bottom border: dest_x from 0 to 640+MARGIN_LEFT+MARGIN_RIGHT
// and dest_y of BASE_MARGIN_BOTTOM starting at TOP+A2_HEIGHT
// src_x is dest_x, and src_y is 0.
dest_y = g_video_act_margin_top + A2_WINDOW_HEIGHT;
height = g_video_act_margin_bottom;
src_y = BASE_MARGIN_BOTTOM - height;
dest_x = 0;
src_x = BASE_MARGIN_LEFT - g_video_act_margin_left;
if(width > 0 && height > 0) {
x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y,
width, height);
}
// Then fix top border: dest_x from 0 to 640+LEFT+RIGHT and
// dest_y from 0 to TOP. src_x is dest_x, but src_y is
// BOTTOM to BOTTOM+TOP
// Just use src_x and dest_x from earlier.
height = g_video_act_margin_top;
dest_y = 0;
src_y = BASE_MARGIN_BOTTOM;
if(width > 0 && height > 0) {
x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y,
width, height);
}
}
void
video_push_kimages()
{
register word32 start_time;
register word32 end_time;
Kimage *last_kim, *cur_kim;
word32 mask;
int start;
int line;
int left_pix, right_pix;
int left, right;
int line_div8;
if(g_border_sides_refresh_needed) {
g_border_sides_refresh_needed = 0;
video_push_border_sides();
}
if(g_border_special_refresh_needed) {
g_border_special_refresh_needed = 0;
video_push_border_special();
}
if(g_a2_screen_buffer_changed == 0) {
return;
}
GET_ITIMER(start_time);
start = -1;
last_kim = (Kimage *)-1;
cur_kim = (Kimage *)0;
left_pix = 640;
right_pix = 0;
for(line = 0; line < 200; line++) {
line_div8 = line >> 3;
mask = 1 << (line_div8);
cur_kim = g_a2_line_kimage[line];
if((g_full_refresh_needed & mask) != 0) {
left = 0;
right = 560;
if(cur_kim == &g_kimage_superhires) {
right = 640;
}
} else {
left = g_a2_line_left_edge[line];
right = g_a2_line_right_edge[line];
}
if(!(g_a2_screen_buffer_changed & mask) || (left > right)) {
/* No need to update this line */
/* Refresh previous chunks of lines, if any */
if(start >= 0) {
video_push_lines(last_kim, start, line,
left_pix, right_pix);
start = -1;
left_pix = 640;
right_pix = 0;
}
} else {
/* Need to update this line */
if(start < 0) {
start = line;
last_kim = cur_kim;
}
if(cur_kim != last_kim) {
/* do the refresh */
video_push_lines(last_kim, start, line,
left_pix, right_pix);
last_kim = cur_kim;
start = line;
left_pix = left;
right_pix = right;
}
left_pix = MIN(left, left_pix);
right_pix = MAX(right, right_pix);
}
}
if(start >= 0) {
video_push_lines(last_kim, start, 200, left_pix, right_pix);
}
g_a2_screen_buffer_changed = 0;
g_full_refresh_needed = 0;
x_push_done();
GET_ITIMER(end_time);
g_cycs_in_xredraw += (end_time - start_time);
}
void
video_update_color_raw(int col_num, int a2_color)
{
word32 tmp;
int red, green, blue;
int newred, newgreen, newblue;
red = (a2_color >> 8) & 0xf;
green = (a2_color >> 4) & 0xf;
blue = (a2_color) & 0xf;
red = ((red << 4) + red);
green = ((green << 4) + green);
blue = ((blue << 4) + blue);
newred = red >> g_red_right_shift;
newgreen = green >> g_green_right_shift;
newblue = blue >> g_blue_right_shift;
tmp = ((newred & g_red_mask) << g_red_left_shift) +
((newgreen & g_green_mask) << g_green_left_shift) +
((newblue & g_blue_mask) << g_blue_left_shift);
g_palette_8to1624[col_num] = tmp;
x_update_color(col_num, red, green, blue, tmp);
}
void
video_update_color_array(int col_num, int a2_color)
{
int palette;
int full;
if(col_num >= 256 || col_num < 0) {
halt_printf("video_update_color_array: col: %03x\n", col_num);
return;
}
full = g_installed_full_superhires_colormap;
palette = col_num >> 4;
if(!full && palette == g_a2vid_palette) {
return;
}
#if 0
if(g_screen_depth != 8) {
/* redraw whole superhires for now */
g_full_refresh_needed = -1;
}
#endif
video_update_color_raw(col_num, a2_color);
}
void
video_update_colormap()
{
int palette;
int full;
int i;
full = g_installed_full_superhires_colormap;
if(!full) {
palette = g_a2vid_palette << 4;
for(i = 0; i < 16; i++) {
video_update_color_raw(palette + i, g_lores_colors[i]);
}
x_update_physical_colormap();
}
}
void
video_update_status_line(int line, const char *string)
{
char *buf;
const char *ptr;
int i;
if(line >= MAX_STATUS_LINES || line < 0) {
printf("update_status_line: line: %d!\n", line);
exit(1);
}
ptr = string;
buf = &(g_status_buf[line][0]);
g_status_ptrs[line] = buf;
for(i = 0; i < STATUS_LINE_LENGTH; i++) {
if(*ptr) {
buf[i] = *ptr++;
} else {
buf[i] = ' ';
}
}
buf[STATUS_LINE_LENGTH] = 0;
}
void
video_show_debug_info()
{
word32 tmp1;
printf("g_cur_dcycs: %f, last_vbl: %f\n", g_cur_dcycs,
g_last_vbl_dcycs);
tmp1 = get_lines_since_vbl(g_cur_dcycs);
printf("lines since vbl: %06x\n", tmp1);
printf("Last line updated: %d\n", g_vid_update_last_line);
}
word32
float_bus(double dcycs)
{
word32 val;
int lines_since_vbl;
int line, eff_line, line24;
int all_stat;
int byte_offset;
int hires, page2;
int addr;
lines_since_vbl = get_lines_since_vbl(dcycs);
/* For floating bus, model hires style: Visible lines 0-191 are simply the */
/* data being displayed at that time. Lines 192-255 are lines 0 - 63 again */
/* and lines 256-261 are lines 58-63 again */
/* For each line, figure out starting byte at -25 mod 128 bytes from this */
/* line's start */
/* This emulates an Apple II style floating bus. A reall IIgs does not */
/* drive anything meaningful during the 25 horizontal blanking lines, */
/* nor during veritical blanking. The data seems to be 0 or related to */
/* the instruction fetches on a real IIgs during blankings */
line = lines_since_vbl >> 8;
byte_offset = lines_since_vbl & 0xff;
/* byte offset is from 0 to 65, where the visible screen is drawn */
/* from 25 to 65 */
eff_line = line;
if(line >= 192) {
eff_line = line - 192;
if(line >= 256) {
eff_line = line - 262 + 64;
}
}
all_stat = g_cur_a2_stat;
hires = all_stat & ALL_STAT_HIRES;
if((all_stat & ALL_STAT_MIX_T_GR) && (line >= 160)) {
hires = 0;
}
page2 = EXTRU(all_stat, 31 - BIT_ALL_STAT_PAGE2, 1);
if(all_stat & ALL_STAT_ST80) {
page2 = 0;
}
line24 = (eff_line >> 3) & 0x1f;
addr = g_screen_index[line24] & 0x3ff;
addr = (addr & 0x380) + (((addr & 0x7f) - 25 + byte_offset) & 0x7f);
if(hires) {
addr = 0x2000 + addr + ((eff_line & 7) << 10) + (page2 << 13);
} else {
addr = 0x400 + addr + (page2 << 10);
}
val = g_slow_memory_ptr[addr];
if(byte_offset < 10) {
/* Bob Bishop's sample program seems to get confused by */
/* these bytes--so mask some off to prevent seeing some */
val = 0;
}
#if 0
printf("For %04x (%d) addr=%04x, val=%02x, dcycs:%9.2f\n",
lines_since_vbl, eff_line, addr, val, dcycs - g_last_vbl_dcycs);
#endif
return val;
}