/* * Apple // emulator for Linux: Video support * * Copyright 1994 Alexander Jean-Claude Bottema * Copyright 1995 Stephen Lee * Copyright 1997, 1998 Aaron Culliney * Copyright 1998, 1999, 2000 Michael Deutschmann * * This software package is subject to the GNU General Public License * version 2 or later (your choice) as published by the Free Software * Foundation. * * THERE ARE NO WARRANTIES WHATSOEVER. * */ #include "common.h" #ifdef _640x400 unsigned char video__wider_font[0x8000]; #endif /* _640x400 */ unsigned char video__font[0x4000]; /* --- Precalculated hi-res page offsets given addr --- */ unsigned int video__screen_addresses[8192]; unsigned char video__columns[8192]; unsigned char *video__fb1,*video__fb2; #ifdef _640x400 unsigned char video__wider_hires_even[0x1000]; unsigned char video__wider_hires_odd[0x1000]; #endif unsigned char video__hires_even[0x800]; unsigned char video__hires_odd[0x800]; unsigned char video__dhires1[256]; unsigned char video__dhires2[256]; // Interface font static unsigned char video__int_font[3][0x4000]; int video__current_page; /* Current visual page */ int video__strictcolors = 1;// 0 is deprecated void video_loadfont(int first, int quantity, const unsigned char *data, int mode) { int i,j; unsigned char x,y,fg,bg; switch (mode) { case 2: fg = COLOR_BLACK; bg = COLOR_LIGHT_WHITE; break; case 3: fg = COLOR_FLASHING_WHITE; bg = COLOR_FLASHING_BLACK; break; default: fg = COLOR_LIGHT_WHITE; bg = COLOR_BLACK; break; } i = quantity * 8; while (i--) { j = 8; x = data[i]; while (j--) { y = (x & 128) ? fg : bg; #ifdef _640x400 video__wider_font[(first << 7) + (i << 4) + (j << 1)] = video__wider_font[(first << 7) + (i << 4) + (j << 1) + 1] = #endif /* _640x400 */ video__font[(first << 6) + (i << 3) + j] = y; x <<= 1; } } } unsigned char video__odd_colors[2] = { COLOR_LIGHT_PURPLE, COLOR_LIGHT_BLUE }; unsigned char video__even_colors[2] = { COLOR_LIGHT_GREEN, COLOR_LIGHT_RED }; /* 40col/80col/lores/hires/dhires line offsets */ unsigned short video__line_offset[24] = { 0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x028, 0x0A8, 0x128, 0x1A8, 0x228, 0x2A8, 0x328, 0x3A8, 0x050, 0x0D0, 0x150, 0x1D0, 0x250, 0x2D0, 0x350, 0x3D0 }; unsigned char video__dhires1[256] = { 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, 0x0,0x1,0x3,0x3,0x5,0x5,0x7,0x7,0x9,0x9,0xb,0xb,0xd,0xd,0xf,0xf, 0x0,0x1,0x2,0x3,0x6,0x5,0x6,0x7,0xa,0x9,0xa,0xb,0xe,0xd,0xe,0xf, 0x0,0x1,0x3,0x3,0x7,0x5,0x7,0x7,0xb,0x9,0xb,0xb,0xf,0xd,0xf,0xf, 0x0,0x1,0x2,0x3,0x4,0x4,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, 0x0,0x1,0x3,0x3,0x5,0x5,0x7,0x7,0xd,0x9,0xb,0xb,0xd,0xd,0xf,0xf, 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0xe,0x9,0xa,0xb,0xe,0xd,0xe,0xf, 0x0,0x1,0x7,0x3,0x7,0x5,0x7,0x7,0xf,0x9,0xb,0xb,0xf,0xd,0xf,0xf, }; unsigned char video__dhires2[256] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x8,0x0,0xb,0x8,0xd,0x0,0x0, 0x1,0x1,0x1,0x1,0x0,0x5,0x1,0x1,0x0,0x9,0xb,0xb,0x0,0xd,0xf,0xf, 0x0,0x1,0x2,0x2,0x2,0x5,0x2,0x2,0x0,0xa,0xa,0xa,0xe,0xd,0x2,0x2, 0x3,0x3,0x3,0x3,0x7,0x5,0x7,0x7,0x0,0xb,0xb,0xb,0xf,0xd,0xf,0xf, 0x0,0x0,0x4,0x0,0x4,0x4,0x4,0x4,0xc,0x8,0x4,0x8,0xc,0xd,0x4,0x4, 0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0xd,0x4,0x4,0x4,0xd,0xd,0x4,0x4, 0x6,0x6,0x6,0x2,0xe,0x6,0x6,0x6,0xe,0xe,0xa,0xa,0xe,0x6,0xe,0x6, 0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0xf,0xf,0xb,0xb,0xf,0xf,0xf,0xf, }; /* ------------------------------------------------------------------------- c_initialize_dhires_values() ------------------------------------------------------------------------- */ static void c_initialize_dhires_values(void) { int i; /* int value, v; */ /* unsigned char locolor, hicolor; */ /* precalculate the colors for all the 256*8 bit combinations. */ /* for (value = 0x00, v = 0; value <= 0xFF; value++) { */ /* locolor = (value & 0x0F) | 0x10; */ /* hicolor = (value << 4) | 0x10; */ /* dhires_colors[v++] = locolor; */ /* dhires_colors[v++] = locolor; */ /* dhires_colors[v++] = locolor; */ /* dhires_colors[v++] = locolor; */ /* dhires_colors[v++] = hicolor; */ /* dhires_colors[v++] = hicolor; */ /* dhires_colors[v++] = hicolor; */ /* dhires_colors[v++] = hicolor; */ /* } */ for (i = 0; i < 0x80; i++) { video__dhires1[i+0x80] = video__dhires1[i]; video__dhires2[i+0x80] = video__dhires2[i]; } } /* ------------------------------------------------------------------------- c_initialize_hires_values() ------------------------------------------------------------------------- */ static void c_initialize_hires_values(void) { int value, b, v, e, /*color_toggle,*/ last_not_black; /* precalculate the colors for all the 256*8 bit combinations. */ for (value = 0x00; value <= 0xFF; value++) { for (e = value * 8, last_not_black = 0, v = value, b = 0; b < 7; b++, v >>= 1, e++) { if (v & 1) { video__hires_even[ e ] = last_not_black ? COLOR_LIGHT_WHITE : ((b & 1) ? ((value & 0x80) ? COLOR_LIGHT_RED : COLOR_LIGHT_GREEN) : ((value & 0x80) ? COLOR_LIGHT_BLUE : COLOR_LIGHT_PURPLE)); video__hires_odd[ e ] = last_not_black ? COLOR_LIGHT_WHITE : ((b & 1) ? ((value & 0x80) ? COLOR_LIGHT_BLUE : COLOR_LIGHT_PURPLE) : ((value & 0x80) ? COLOR_LIGHT_RED : COLOR_LIGHT_GREEN)); if (last_not_black && b > 0) { video__hires_even[ e - 1 ] = COLOR_LIGHT_WHITE, video__hires_odd[ e - 1 ] = COLOR_LIGHT_WHITE; } last_not_black = 1; } else { video__hires_even[ e ] = COLOR_BLACK, video__hires_odd[ e ] = COLOR_BLACK, last_not_black = 0; } } } if (color_mode == COLOR_NONE) /* Black and White */ { for (value = 0x00; value <= 0xFF; value++) { for (b = 0, e = value * 8; b < 7; b++, e++) { if (video__hires_even[ e ] != COLOR_BLACK) { video__hires_even[ e ] = COLOR_LIGHT_WHITE; } if (video__hires_odd[ e ] != COLOR_BLACK) { video__hires_odd[ e ] = COLOR_LIGHT_WHITE; } } } } #if 0 else if (color_mode == LAZY_INTERP) /* Lazy Interpolated color */ { for (value = 0x00; value <= 0xFF; value++) { for (b = 1, e = value * 8 + 1; b <= 5; b += 2, e += 2) { if (video__hires_even[ e ] == COLOR_BLACK && video__hires_even[ e - 1 ] != COLOR_BLACK && video__hires_even[ e + 1 ] != COLOR_BLACK) { video__hires_even[ e ] = video__hires_even[ e - 1 ]; } if (video__hires_odd[ e ] == COLOR_BLACK && video__hires_odd[ e - 1 ] != COLOR_BLACK && video__hires_odd[ e + 1 ] != COLOR_BLACK) { video__hires_odd[ e ] = video__hires_odd[ e - 1 ]; } } for (b = 0, e = value * 8; b <= 6; b += 2, e += 2) { if (video__hires_odd[ e ] == COLOR_BLACK) { if (b > 0 && b < 6) { if (video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_LIGHT_WHITE && video__hires_even[e-1] != COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e-1]; } } else if (b == 0) { if (video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e+1]; } } else { if (video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e-1] != COLOR_LIGHT_WHITE) { video__hires_even[ e ] = video__hires_even[ e - 1 ]; } } } if (video__hires_odd[ e ] == COLOR_BLACK) { if (b > 0 && b < 6) { if (video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_LIGHT_WHITE && video__hires_odd[e-1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e-1]; } } else if (b == 0) { if (video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e+1]; } } else if (video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e-1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e-1]; } } } } } #endif else if (color_mode == COLOR_INTERP) /* Color and strict interpolation */ { for (value = 0x00; value <= 0xFF; value++) { for (b = 1, e = value * 8 + 1; b <= 5; b += 2, e += 2) { if (video__hires_even[e] == COLOR_BLACK) { if (video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] != COLOR_LIGHT_WHITE && video__hires_even[e+1] != COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e-1]; } else if ( video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] != COLOR_LIGHT_WHITE && video__hires_even[e+1] == COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e-1]; } else if ( video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] == COLOR_LIGHT_WHITE && video__hires_even[e+1] != COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e+1]; } else if ( video__hires_even[e-1] == COLOR_LIGHT_WHITE && video__hires_even[e+1] == COLOR_LIGHT_WHITE) { video__hires_even[e] = (value & 0x80) ? COLOR_LIGHT_BLUE : COLOR_LIGHT_PURPLE; } } if (video__hires_odd[e] == COLOR_BLACK) { if (video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] != COLOR_LIGHT_WHITE && video__hires_odd[e+1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e-1]; } else if ( video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] != COLOR_LIGHT_WHITE && video__hires_odd[e+1] == COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e-1]; } else if ( video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] == COLOR_LIGHT_WHITE && video__hires_odd[e+1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e+1]; } else if ( video__hires_odd[e-1] == COLOR_LIGHT_WHITE && video__hires_odd[e+1] == COLOR_LIGHT_WHITE) { video__hires_odd[e] = (value & 0x80) ? COLOR_LIGHT_RED : COLOR_LIGHT_GREEN; } } } for (b = 0, e = value * 8; b <= 6; b += 2, e += 2) { if (video__hires_even[ e ] == COLOR_BLACK) { if (b > 0 && b < 6) { if (video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] != COLOR_LIGHT_WHITE && video__hires_even[e+1] != COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e-1]; } else if ( video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] != COLOR_LIGHT_WHITE && video__hires_even[e+1] == COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e-1]; } else if ( video__hires_even[e-1] != COLOR_BLACK && video__hires_even[e+1] != COLOR_BLACK && video__hires_even[e-1] == COLOR_LIGHT_WHITE && video__hires_even[e+1] != COLOR_LIGHT_WHITE) { video__hires_even[e] = video__hires_even[e+1]; } else if ( video__hires_even[e-1] == COLOR_LIGHT_WHITE && video__hires_even[e+1] == COLOR_LIGHT_WHITE) { video__hires_even[e] = (value & 0x80) ? COLOR_LIGHT_RED : COLOR_LIGHT_GREEN; } } } if (video__hires_odd[e] == COLOR_BLACK) { if (b > 0 && b < 6) { if (video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] != COLOR_LIGHT_WHITE && video__hires_odd[e+1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e-1]; } else if ( video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] != COLOR_LIGHT_WHITE && video__hires_odd[e+1] == COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e-1]; } else if ( video__hires_odd[e-1] != COLOR_BLACK && video__hires_odd[e+1] != COLOR_BLACK && video__hires_odd[e-1] == COLOR_LIGHT_WHITE && video__hires_odd[e+1] != COLOR_LIGHT_WHITE) { video__hires_odd[e] = video__hires_odd[e+1]; } else if ( video__hires_odd[e-1] == COLOR_LIGHT_WHITE && video__hires_odd[e+1] == COLOR_LIGHT_WHITE) { video__hires_odd[e] = (value & 0x80) ? COLOR_LIGHT_BLUE : COLOR_LIGHT_PURPLE; } } } } } } #ifdef _640x400 /* *2 for 640x400 */ for (b=0, e=0; b<4096; b++, e++) { video__wider_hires_even[b] = video__hires_even[e]; video__wider_hires_odd[b] = video__hires_odd[e]; b++; video__wider_hires_even[b] = video__hires_even[e]; video__wider_hires_odd[b] = video__hires_odd[e]; } #endif } /* ------------------------------------------------------------------------- c_initialize_row_col_tables() ------------------------------------------------------------------------- */ static void c_initialize_row_col_tables(void) { int x, y, off, i; /* hires page offsets. initialize to invalid values. */ for (i = 0; i < 8192; i++) { video__screen_addresses[i] = -1; } for (y = 0; y < 24; y++) { for (off = 0; off < 8; off++) { for (x = 0; x < 40; x++) { #ifdef _640x400 video__screen_addresses[video__line_offset[y] + 0x400*off + x ] = (y*16 + 2*off /* + 8*/) * SCANWIDTH + x*14 + 4; #else video__screen_addresses[video__line_offset[y] + 0x400*off + x ] = (y*8 + off + 4) * 320 + x*7 + 20; #endif video__columns[video__line_offset[y] + 0x400*off + x] = (unsigned char)x; } } } } static void c_initialize_tables_video(void) { int x, y, i; /* initialize text/lores & hires graphics */ for (y = 0; y < 24; y++) /* 24 rows */ { for (x = 0; x < 40; x++) /* 40 cols */ { if (apple_mode == IIE_MODE) { /* //e mode: text/lores page 0 */ cpu65_vmem[ video__line_offset[ y ] + x + 0x400].w = (y < 20) ? video__write_2e_text0 : video__write_2e_text0_mixed; } else { /* ][+ modes: text/lores page 0 */ cpu65_vmem[ video__line_offset[ y ] + x + 0x400].w = (y < 20) ? video__write_text0 : video__write_text0_mixed; } if (apple_mode == IIE_MODE) { cpu65_vmem[ video__line_offset[ y ] + x + 0x800].w = (y < 20) ? video__write_2e_text1 : video__write_2e_text1_mixed; } else { /* ][+ modes: text/lores page 1 in main memory */ cpu65_vmem[ video__line_offset[ y ] + x + 0x800].w = (y < 20) ? video__write_text1 : video__write_text1_mixed; } for (i = 0; i < 8; i++) { /* //e mode: hires/double hires page 0 */ if (apple_mode == IIE_MODE) { cpu65_vmem[ 0x2000 + video__line_offset[ y ] + 0x400 * i + x ].w = (y < 20) ? ((x & 1) ? video__write_2e_odd0 : video__write_2e_even0) : ((x & 1) ? video__write_2e_odd0_mixed : video__write_2e_even0_mixed); } /* ][+ modes: hires page 0 */ else { cpu65_vmem[ 0x2000 + video__line_offset[ y ] + 0x400 * i + x ].w = (y < 20) ? ((x & 1) ? video__write_odd0 : video__write_even0) : ((x & 1) ? video__write_odd0_mixed : video__write_even0_mixed); } if (apple_mode == IIE_MODE) { cpu65_vmem[ 0x4000 + video__line_offset[ y ] + 0x400 * i + x ].w = (y < 20) ? ((x & 1) ? video__write_2e_odd1 : video__write_2e_even1) : ((x & 1) ? video__write_2e_odd1_mixed : video__write_2e_even1_mixed); } /* ][+ modes: hires page 1 */ else { cpu65_vmem[ 0x4000 + video__line_offset[ y ] + 0x400 * i + x ].w = (y < 20) ? ((x & 1) ? video__write_odd1 : video__write_even1) : ((x & 1) ? video__write_odd1_mixed : video__write_even1_mixed); } } } } } void video_set(int flags) { video__strictcolors = (color_mode == COLOR_INTERP) ? 2 : 1; c_initialize_hires_values(); /* precalculate hires values */ c_initialize_row_col_tables(); /* precalculate hires offsets */ c_initialize_tables_video(); /* memory jump tables for video */ c_initialize_dhires_values(); /* set up dhires colors */ } void video_loadfont_int(int first, int quantity, const unsigned char *data) { int i,j; unsigned char x; int y; i = quantity * 8; while (i--) { j = 8; x = data[i]; while (j--) { y = (first << 6) + (i << 3) + j; if (x & 128) { video__int_font[0][y] = video__int_font[1][y] = COLOR_LIGHT_GREEN; video__int_font[2][y] = COLOR_LIGHT_RED; } else { video__int_font[0][y] = video__int_font[2][y] = COLOR_BLACK; video__int_font[1][y] = COLOR_MEDIUM_BLUE; } x <<= 1; } } } static void c_interface_print_char80_line( unsigned char **d, unsigned char **s) { #ifdef _640x400 *((unsigned int *)(*d)) = *((unsigned int *)(*s)); /*32bits*/ *d += 4, *s += 4; *((unsigned short *)(*d)) = *((unsigned short *)(*s)); /*16bits*/ *d += 2, *s += 2; *((unsigned char *)(*d)) = *((unsigned char *)(*s)); /*8bits*/ *d += SCANWIDTH-6, *s -= 6; #endif *((unsigned int *)(*d)) = *((unsigned int *)(*s)); /*32bits*/ *d += 4, *s += 4; *((unsigned short *)(*d)) = *((unsigned short *)(*s)); /*16bits*/ *d += 2, *s += 2; *((unsigned char *)(*d)) = *((unsigned char *)(*s)); /*8bits*/ *d += SCANWIDTH-6, *s += 2; } void video_plotchar( int x, int y, int scheme, unsigned char c ) { int off; unsigned char *d; unsigned char *s; #ifdef _640x400 off = y * SCANWIDTH * 16 + x * 7 + 4; s = video__int_font[scheme] + c * 64; #else off = y * SCANWIDTH * 8 + x * 7 + /*WtF?*/1300; s = video__int_font[scheme] + c * 64; #endif d = video__fb1 + off; c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); c_interface_print_char80_line(&d,&s); }