diff --git a/config.template b/config.template index a71d1ec..200e88d 100644 --- a/config.template +++ b/config.template @@ -1,9 +1,9 @@ -# GSport configuration file - -s5d1 = -s5d2 = - -s6d1 = -s6d2 = - -s7d1 = NoBoot.po +# GSport configuration file + +s5d1 = +s5d2 = + +s6d1 = +s6d2 = + +s7d1 = NoBoot.po diff --git a/src/GSport.bat b/src/GSport.bat index b5bc5d8..6afe9ff 100644 --- a/src/GSport.bat +++ b/src/GSport.bat @@ -1,16 +1,16 @@ -@echo off -REM -REM GSport - Windows startup batch file -REM - -SET GSPORT_HOME=%CD%\ -set CYGWIN=nodosfilewarning - -:add_classpath -SET CWD=%CD% -if "%GSPORT_PATH_SET%" == "1" goto start -set GSPORT_PATH_SET=1 -PATH=%PATH%;%GSPORT_HOME - -:start -GSport.exe +@echo off +REM +REM GSport - Windows startup batch file +REM + +SET GSPORT_HOME=%CD%\ +set CYGWIN=nodosfilewarning + +:add_classpath +SET CWD=%CD% +if "%GSPORT_PATH_SET%" == "1" goto start +set GSPORT_PATH_SET=1 +PATH=%PATH%;%GSPORT_HOME + +:start +GSport.exe diff --git a/src/adb.c b/src/adb.c index 31c04cc..58747af 100644 --- a/src/adb.c +++ b/src/adb.c @@ -1,1923 +1,1925 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* adb_mode bit 3 and bit 2 (faster repeats for arrows and space/del) not done*/ - -#include "adb.h" - -int g_fullscreen = 0; - -extern int Verbose; -extern word32 g_vbl_count; -extern int g_num_lines_prev_superhires640; -extern int g_num_lines_prev_superhires; -extern int g_rom_version; -extern int g_fast_disk_emul; -extern int g_limit_speed; -extern int g_irq_pending; -extern int g_swap_paddles; -extern int g_invert_paddles; -extern int g_joystick_type; -extern int g_a2vid_palette; -extern int g_config_control_panel; -extern word32 g_cfg_vbl_count; -extern double g_cur_dcycs; - -extern byte *g_slow_memory_ptr; -extern byte *g_memory_ptr; -extern word32 g_mem_size_total; - -enum { - ADB_IDLE = 0, - ADB_IN_CMD, - ADB_SENDING_DATA, -}; - -#define ADB_C027_MOUSE_DATA 0x80 -#define ADB_C027_MOUSE_INT 0x40 -#define ADB_C027_DATA_VALID 0x20 -#define ADB_C027_DATA_INT 0x10 -#define ADB_C027_KBD_VALID 0x08 -#define ADB_C027_KBD_INT 0x04 -#define ADB_C027_MOUSE_COORD 0x02 -#define ADB_C027_CMD_FULL 0x01 - -#define ADB_C027_NEG_MASK ( ~ ( \ - ADB_C027_MOUSE_DATA | ADB_C027_DATA_VALID | \ - ADB_C027_KBD_VALID | ADB_C027_MOUSE_COORD | \ - ADB_C027_CMD_FULL)) - - -int halt_on_all_c027 = 0; - -word32 g_adb_repeat_delay = 45; -word32 g_adb_repeat_rate = 3; -word32 g_adb_repeat_info = 0x23; -word32 g_adb_char_set = 0x0; -word32 g_adb_layout_lang = 0x0; - -word32 g_adb_interrupt_byte = 0; -int g_adb_state = ADB_IDLE; - -word32 g_adb_cmd = (word32)-1; -int g_adb_cmd_len = 0; -int g_adb_cmd_so_far = 0; -word32 g_adb_cmd_data[16]; - -#define MAX_ADB_DATA_PEND 16 - -word32 g_adb_data[MAX_ADB_DATA_PEND]; -int g_adb_data_pending = 0; - -word32 g_c027_val = 0; -word32 g_c025_val = 0; - -byte adb_memory[256]; - -word32 g_adb_mode = 0; /* mode set via set_modes, clear_modes */ - -int g_warp_pointer = 0; -int g_hide_pointer = 0; -int g_unhide_pointer = 0; - -int g_mouse_a2_x = 0; -int g_mouse_a2_y = 0; -int g_mouse_a2_button = 0; -int g_mouse_fifo_pos = 0; -int g_mouse_raw_x = 0; -int g_mouse_raw_y = 0; - -#define ADB_MOUSE_FIFO 8 - -STRUCT(Mouse_fifo) { - double dcycs; - int x; - int y; - int buttons; -}; - -Mouse_fifo g_mouse_fifo[ADB_MOUSE_FIFO] = { { 0, 0, 0, 0 } }; - -int g_mouse_warp_x = 0; -int g_mouse_warp_y = 0; - -int g_adb_mouse_valid_data = 0; -int g_adb_mouse_coord = 0; - -#define MAX_KBD_BUF 8 - -int g_key_down = 0; -int g_hard_key_down = 0; -int g_a2code_down = 0; -int g_kbd_read_no_update = 0; -int g_kbd_chars_buffered = 0; -int g_kbd_buf[MAX_KBD_BUF]; -word32 g_adb_repeat_vbl = 0; - -int g_kbd_dev_addr = 2; /* ADB physical kbd addr */ -int g_mouse_dev_addr = 3; /* ADB physical mouse addr */ - -int g_kbd_ctl_addr = 2; /* ADB microcontroller's kbd addr */ -int g_mouse_ctl_addr = 3; /* ADB ucontroller's mouse addr*/ - /* above are ucontroller's VIEW of where mouse/kbd */ - /* are...if they are moved, mouse/keyboard funcs */ - /* should stop (c025, c000, c024, etc). */ - -word32 g_virtual_key_up[4]; /* bitmask of all possible 128 a2codes */ - /* indicates which keys are up=1 by bit */ - -int g_keypad_key_is_down[10] = { 0 };/* List from 0-9 of which keypad */ - /* keys are currently pressed */ - - -#define SHIFT_DOWN ( (g_c025_val & 0x01) ) -#define CTRL_DOWN ( (g_c025_val & 0x02) ) -#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) -#define OPTION_DOWN ( (g_c025_val & 0x40) ) -#define CMD_DOWN ( (g_c025_val & 0x80) ) - - -#define MAX_ADB_KBD_REG3 16 - -int g_kbd_reg0_pos = 0; -int g_kbd_reg0_data[MAX_ADB_KBD_REG3]; -int g_kbd_reg3_16bit = 0x602; /* also set in adb_reset()! */ - - -int g_adb_init = 0; - -void -adb_init() -{ - int keycode; - int i; - - if(g_adb_init) { - halt_printf("g_adb_init = %d!\n", g_adb_init); - } - g_adb_init = 1; - - for(i = 0; i < 128; i++) { - keycode = a2_key_to_ascii[i][0]; - if(keycode != i) { - printf("ADB keycode lost/skipped: i=%x: keycode=%x\n", - i, keycode); - my_exit(1); - } - } - - g_c025_val = 0; - - for(i = 0; i < 4; i++) { - g_virtual_key_up[i] = -1; - } - - for(i = 0; i < 10; i++) { - g_keypad_key_is_down[i] = 0; - } - - adb_reset(); -} - -// OG Added adb_shut() -void adb_shut() -{ - g_adb_init = 0; -} - -void -adb_reset() -{ - - g_c027_val = 0; - - g_key_down = 0; - - g_kbd_dev_addr = 2; - g_mouse_dev_addr = 3; - - g_kbd_ctl_addr = 2; - g_mouse_ctl_addr = 3; - - adb_clear_data_int(); - adb_clear_mouse_int(); - adb_clear_kbd_srq(); - - g_adb_data_pending = 0; - g_adb_interrupt_byte = 0; - g_adb_state = ADB_IDLE; - g_adb_mouse_coord = 0; - g_adb_mouse_valid_data = 0; - - g_kbd_reg0_pos = 0; - g_kbd_reg3_16bit = 0x602; - -} - - -#define LEN_ADB_LOG 16 -STRUCT(Adb_log) { - word32 addr; - int val; - int state; -}; - -Adb_log g_adb_log[LEN_ADB_LOG]; -int g_adb_log_pos = 0; - -void -adb_log(word32 addr, int val) -{ - int pos; - - pos = g_adb_log_pos; - g_adb_log[pos].addr = addr; - g_adb_log[pos].val = val; - g_adb_log[pos].state = g_adb_state; - pos++; - if(pos >= LEN_ADB_LOG) { - pos = 0; - } - g_adb_log_pos = pos; -} - -void -show_adb_log(void) -{ - int pos; - int i; - - pos = g_adb_log_pos; - printf("ADB log pos: %d\n", pos); - for(i = 0; i < LEN_ADB_LOG; i++) { - pos--; - if(pos < 0) { - pos = LEN_ADB_LOG - 1; - } - printf("%d:%d: addr:%04x = %02x, st:%d\n", i, pos, - g_adb_log[pos].addr, g_adb_log[pos].val, - g_adb_log[pos].state); - } - printf("kbd: dev: %x, ctl: %x; mouse: dev: %x, ctl: %x\n", - g_kbd_dev_addr, g_kbd_ctl_addr, - g_mouse_dev_addr, g_mouse_ctl_addr); - printf("g_adb_state: %d, g_adb_interrupt_byte: %02x\n", - g_adb_state, g_adb_interrupt_byte); -} - -void -adb_error(void) -{ - halt_printf("Adb Error\n"); - - show_adb_log(); -} - - - -void -adb_add_kbd_srq() -{ - if(g_kbd_reg3_16bit & 0x200) { - /* generate SRQ */ - g_adb_interrupt_byte |= 0x08; - add_irq(IRQ_PENDING_ADB_KBD_SRQ); - } else { - printf("Got keycode but no kbd SRQ!\n"); - } -} - -void -adb_clear_kbd_srq() -{ - remove_irq(IRQ_PENDING_ADB_KBD_SRQ); - - /* kbd SRQ's are the only ones to handle now, so just clean it out */ - g_adb_interrupt_byte &= (~(0x08)); -} - -void -adb_add_data_int() -{ - if(g_c027_val & ADB_C027_DATA_INT) { - add_irq(IRQ_PENDING_ADB_DATA); - } -} - -void -adb_add_mouse_int() -{ - if(g_c027_val & ADB_C027_MOUSE_INT) { - add_irq(IRQ_PENDING_ADB_MOUSE); - } -} - -void -adb_clear_data_int() -{ - remove_irq(IRQ_PENDING_ADB_DATA); -} - -void -adb_clear_mouse_int() -{ - remove_irq(IRQ_PENDING_ADB_MOUSE); -} - - -void -adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2) -{ - word32 val; - int shift_amount; - int i; - - if((num_bytes >= 12) || (num_bytes >= MAX_ADB_DATA_PEND)) { - halt_printf("adb_send_bytes: %d is too many!\n", num_bytes); - } - - g_adb_state = ADB_SENDING_DATA; - g_adb_data_pending = num_bytes; - adb_add_data_int(); - - for(i = 0; i < num_bytes; i++) { - if(i < 4) { - val = val0; - } else if(i < 8) { - val = val1; - } else { - val = val2; - } - - shift_amount = 8*(3 - i); - g_adb_data[i] = (val >> shift_amount) & 0xff; - adb_printf("adb_send_bytes[%d] = %02x\n", i, g_adb_data[i]); - } -} - - -void -adb_send_1byte(word32 val) -{ - - if(g_adb_data_pending != 0) { - halt_printf("g_adb_data_pending: %d\n", g_adb_data_pending); - } - - adb_send_bytes(1, val << 24, 0, 0); -} - - - -void -adb_response_packet(int num_bytes, word32 val) -{ - - if(g_adb_data_pending != 0) { - halt_printf("adb_response_packet, but pending: %d\n", - g_adb_data_pending); - } - - g_adb_state = ADB_IDLE; - g_adb_data_pending = num_bytes; - g_adb_data[0] = val & 0xff; - g_adb_data[1] = (val >> 8) & 0xff; - g_adb_data[2] = (val >> 16) & 0xff; - g_adb_data[3] = (val >> 24) & 0xff; - if(num_bytes) { - g_adb_interrupt_byte |= 0x80 + num_bytes - 1; - } else { - g_adb_interrupt_byte |= 0x80; - } - - adb_printf("adb_response packet: %d: %08x\n", - num_bytes, val); - - adb_add_data_int(); -} - - -void -adb_kbd_reg0_data(int a2code, int is_up) -{ - if(g_kbd_reg0_pos >= MAX_ADB_KBD_REG3) { - /* too many keys, toss */ - halt_printf("Had to toss key: %02x, %d\n", a2code, is_up); - return; - } - - g_kbd_reg0_data[g_kbd_reg0_pos] = a2code + (is_up << 7); - - adb_printf("g_kbd_reg0_data[%d] = %02x\n", g_kbd_reg0_pos, - g_kbd_reg0_data[g_kbd_reg0_pos]); - - g_kbd_reg0_pos++; - - adb_add_kbd_srq(); -} - -void -adb_kbd_talk_reg0() -{ - word32 val0, val1; - word32 reg; - int num_bytes; - int num; - int i; - - num = 0; - val0 = g_kbd_reg0_data[0]; - val1 = g_kbd_reg0_data[1]; - - num_bytes = 0; - if(g_kbd_reg0_pos > 0) { - num_bytes = 2; - num = 1; - if((val0 & 0x7f) == 0x7f) { - /* reset */ - val1 = val0; - } else if(g_kbd_reg0_pos > 1) { - num = 2; - if((val1 & 0x7f) == 0x7f) { - /* If first byte some other key, don't */ - /* put RESET next! */ - num = 1; - val1 = 0xff; - } - } else { - val1 = 0xff; - } - } - - if(num) { - for(i = num; i < g_kbd_reg0_pos; i++) { - g_kbd_reg0_data[i-1] = g_kbd_reg0_data[i]; - } - g_kbd_reg0_pos -= num; - } - - reg = (val0 << 8) + val1; - - adb_printf("adb_kbd_talk0: %04x\n", reg); - - adb_response_packet(num_bytes, reg); - if(g_kbd_reg0_pos == 0) { - adb_clear_kbd_srq(); - } -} - -void -adb_set_config(word32 val0, word32 val1, word32 val2) -{ - int new_mouse; - int new_kbd; - int tmp1; - - new_mouse = val0 >> 4; - new_kbd = val0 & 0xf; - if(new_mouse != g_mouse_ctl_addr) { - printf("ADB config: mouse from %x to %x!\n", - g_mouse_ctl_addr, new_mouse); - adb_error(); - g_mouse_ctl_addr = new_mouse; - } - if(new_kbd != g_kbd_ctl_addr) { - printf("ADB config: kbd from %x to %x!\n", - g_kbd_ctl_addr, new_kbd); - adb_error(); - g_kbd_ctl_addr = new_kbd; - } - - - tmp1 = val2 >> 4; - if(tmp1 == 4) { - g_adb_repeat_delay = 0; - } else if(tmp1 < 4) { - g_adb_repeat_delay = (tmp1 + 1) * 15; - } else { - halt_printf("Bad ADB repeat delay: %02x\n", tmp1); - } - - tmp1 = val2 & 0xf; - if(g_rom_version >= 3) { - tmp1 = 9 - tmp1; - } - - switch(tmp1) { - case 0: - g_adb_repeat_rate = 1; - break; - case 1: - g_adb_repeat_rate = 2; - break; - case 2: - g_adb_repeat_rate = 3; - break; - case 3: - g_adb_repeat_rate = 3; - break; - case 4: - g_adb_repeat_rate = 4; - break; - case 5: - g_adb_repeat_rate = 5; - break; - case 6: - g_adb_repeat_rate = 7; - break; - case 7: - g_adb_repeat_rate = 15; - break; - case 8: - /* I don't know what this should be, ROM 03 uses it */ - g_adb_repeat_rate = 30; - break; - case 9: - /* I don't know what this should be, ROM 03 uses it */ - g_adb_repeat_rate = 60; - break; - default: - halt_printf("Bad repeat rate: %02x\n", tmp1); - } - -} - -void -adb_set_new_mode(word32 val) -{ - if(val & 0x03) { - printf("Disabling keyboard/mouse:%02x!\n", val); - } - - if(val & 0xa2) { - halt_printf("ADB set mode: %02x!\n", val); - adb_error(); - } - - g_adb_mode = val; -} - - -int -adb_read_c026() -{ - word32 ret; - int i; - - ret = 0; - switch(g_adb_state) { - case ADB_IDLE: - ret = g_adb_interrupt_byte; - g_adb_interrupt_byte = 0; - if(g_irq_pending & IRQ_PENDING_ADB_KBD_SRQ) { - g_adb_interrupt_byte |= 0x08; - } - if(g_adb_data_pending == 0) { - if(ret & 0x80) { - halt_printf("read_c026: ret:%02x, pend:%d\n", - ret, g_adb_data_pending); - } - adb_clear_data_int(); - } - if(g_adb_data_pending) { - if(g_adb_state != ADB_IN_CMD) { - g_adb_state = ADB_SENDING_DATA; - } - } - break; - case ADB_IN_CMD: - ret = 0; - break; - case ADB_SENDING_DATA: - ret = g_adb_data[0]; - for(i = 1; i < g_adb_data_pending; i++) { - g_adb_data[i-1] = g_adb_data[i]; - } - g_adb_data_pending--; - if(g_adb_data_pending <= 0) { - g_adb_data_pending = 0; - g_adb_state = ADB_IDLE; - adb_clear_data_int(); - } - break; - default: - halt_printf("Bad ADB state: %d!\n", g_adb_state); - adb_clear_data_int(); - break; - } - - adb_printf("Reading c026. Returning %02x, st: %02x, pend: %d\n", - ret, g_adb_state, g_adb_data_pending); - - adb_log(0xc026, ret); - return (ret & 0xff); -} - - -void -adb_write_c026(int val) -{ - word32 tmp; - int dev; - - adb_printf("Writing c026 with %02x\n", val); - adb_log(0x1c026, val); - - - switch(g_adb_state) { - case ADB_IDLE: - g_adb_cmd = val; - g_adb_cmd_so_far = 0; - g_adb_cmd_len = 0; - - dev = val & 0xf; - switch(val) { - case 0x01: /* Abort */ - adb_printf("Performing adb abort\n"); - /* adb_abort() */ - break; - case 0x03: /* Flush keyboard buffer */ - adb_printf("Flushing adb keyboard buffer\n"); - /* Do nothing */ - break; - case 0x04: /* Set modes */ - adb_printf("ADB set modes\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 1; - break; - case 0x05: /* Clear modes */ - adb_printf("ADB clear modes\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 1; - break; - case 0x06: /* Set config */ - adb_printf("ADB set config\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 3; - break; - case 0x07: /* Sync */ - adb_printf("Performing sync cmd!\n"); - g_adb_state = ADB_IN_CMD; - if(g_rom_version == 1) { - g_adb_cmd_len = 4; - } else { - g_adb_cmd_len = 8; - } - break; - case 0x08: /* Write mem */ - adb_printf("Starting write_mem cmd\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - break; - case 0x09: /* Read mem */ - adb_printf("Performing read_mem cmd!\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - break; - case 0x0a: /* Read modes byte */ - printf("Performing read_modes cmd!\n"); - /* set_halt(1); */ - adb_send_1byte(g_adb_mode); - break; - case 0x0b: /* Read config bytes */ - printf("Performing read_configs cmd!\n"); - tmp = (g_mouse_ctl_addr << 20) + - (g_kbd_ctl_addr << 16) + - (g_adb_char_set << 12) + - (g_adb_layout_lang << 8) + - (g_adb_repeat_info << 0); - tmp = (0x82U << 24) + tmp; - adb_send_bytes(4, tmp, 0, 0); - break; - case 0x0d: /* Get Version */ - adb_printf("Performing get_version cmd!\n"); - val = 0; - if(g_rom_version == 1) { - /* ROM 01 = revision 5 */ - val = 5; - } else { - /* ROM 03 checks for rev >= 6 */ - val = 6; - } - adb_send_1byte(val); - break; - case 0x0e: /* Read avail char sets */ - adb_printf("Performing read avail char sets cmd!\n"); - adb_send_bytes(2, /* just 2 bytes */ - 0x08000000, /* number of ch sets=0x8 */ - 0, 0); - /* set_halt(1); */ - break; - case 0x0f: /* Read avail kbd layouts */ - adb_printf("Performing read avail kbd layouts cmd!\n"); - adb_send_bytes(0x2, /* number of kbd layouts=0xa */ - 0x0a000000, 0, 0); - /* set_halt(1); */ - break; - case 0x10: /* Reset */ - printf("ADB reset, cmd 0x10\n"); - do_reset(); - break; - case 0x11: /* Send ADB keycodes */ - adb_printf("Sending ADB keycodes\n"); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 1; - break; - case 0x12: /* ADB cmd 12: ROM 03 only! */ - if(g_rom_version >= 3) { - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - } else { - printf("ADB cmd 12, but not ROM 3!\n"); - adb_error(); - } - break; - case 0x13: /* ADB cmd 13: ROM 03 only! */ - if(g_rom_version >= 3) { - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - } else { - printf("ADB cmd 13, but not ROM 3!\n"); - adb_error(); - } - break; - case 0x73: /* Disable SRQ device 3: mouse */ - adb_printf("Disabling Mouse SRQ's (device 3)\n"); - /* HACK HACK...should deal with SRQs on mouse */ - break; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: - case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - /* Listen dev x reg 3 */ - adb_printf("Sending data to dev %x reg 3\n", dev); - g_adb_state = ADB_IN_CMD; - g_adb_cmd_len = 2; - break; - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - /* Talk dev x reg 0 */ - adb_printf("Performing talk dev %x reg 0\n", dev); - if(dev == g_kbd_dev_addr) { - adb_kbd_talk_reg0(); - } else { - printf("Unknown talk dev %x reg 0!\n", dev); - /* send no data, on SRQ, system polls devs */ - /* so we don't want to send anything */ - adb_error(); - } - break; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: - /* Talk dev x reg 3 */ - adb_printf("Performing talk dev %x reg 3\n", dev); - if(dev == g_kbd_dev_addr) { - adb_response_packet(2, g_kbd_reg3_16bit); - } else { - printf("Performing talk dev %x reg 3!!\n", dev); - adb_error(); - } - break; - default: - /* The Gog's says ACS Demo 2 has a bug and writes to */ - /* c026 */ - // OG - if (val==0x84) - printf("ACS Demo2 (3: Colum& Music scroll) : discarding unknown controller command\n"); - else - halt_printf("ADB ucontroller cmd %02x unknown!\n", val); - - break; - } - break; - case ADB_IN_CMD: - adb_printf("Setting byte %d of cmd %02x to %02x\n", - g_adb_cmd_so_far, g_adb_cmd, val); - - g_adb_cmd_data[g_adb_cmd_so_far] = val; - g_adb_cmd_so_far++; - if(g_adb_cmd_so_far >= g_adb_cmd_len) { - adb_printf("Finished cmd %02x\n", g_adb_cmd); - do_adb_cmd(); - } - - break; - default: - printf("adb_state: %02x is unknown! Setting it to ADB_IDLE\n", - g_adb_state); - g_adb_state = ADB_IDLE; - adb_error(); - halt_on_all_c027 = 1; - break; - } - return; -} - -void -do_adb_cmd() -{ - int dev; - int new_kbd; - int addr; - int val; - - dev = g_adb_cmd & 0xf; - - g_adb_state = ADB_IDLE; - - switch(g_adb_cmd) { - case 0x04: /* Set modes */ - adb_printf("Performing ADB set mode: OR'ing in %02x\n", - g_adb_cmd_data[0]); - - val = g_adb_cmd_data[0] | g_adb_mode; - adb_set_new_mode(val); - - break; - case 0x05: /* clear modes */ - adb_printf("Performing ADB clear mode: AND'ing in ~%02x\n", - g_adb_cmd_data[0]); - - val = g_adb_cmd_data[0]; - val = g_adb_mode & (~val); - adb_set_new_mode(val); - break; - case 0x06: /* Set config */ - adb_printf("Set ADB config to %02x %02x %02x\n", - g_adb_cmd_data[0], g_adb_cmd_data[1],g_adb_cmd_data[2]); - - adb_set_config(g_adb_cmd_data[0], g_adb_cmd_data[1], - g_adb_cmd_data[2]); - - break; - case 0x07: /* SYNC */ - adb_printf("Performing ADB SYNC\n"); - adb_printf("data: %02x %02x %02x %02x\n", - g_adb_cmd_data[0], g_adb_cmd_data[1], g_adb_cmd_data[2], - g_adb_cmd_data[3]); - - adb_set_new_mode(g_adb_cmd_data[0]); - adb_set_config(g_adb_cmd_data[1], g_adb_cmd_data[2], - g_adb_cmd_data[3]); - - if(g_rom_version >= 3) { - adb_printf(" and cmd12:%02x %02x cmd13:%02x %02x\n", - g_adb_cmd_data[4], g_adb_cmd_data[5], - g_adb_cmd_data[6], g_adb_cmd_data[7]); - } - break; - case 0x08: /* Write mem */ - addr = g_adb_cmd_data[0]; - val = g_adb_cmd_data[1]; - write_adb_ram(addr, val); - break; - case 0x09: /* Read mem */ - addr = (g_adb_cmd_data[1] << 8) + g_adb_cmd_data[0]; - adb_printf("Performing mem read to addr %04x\n", addr); - adb_send_1byte(read_adb_ram(addr)); - break; - case 0x11: /* Send ADB keycodes */ - val = g_adb_cmd_data[0]; - adb_printf("Performing send ADB keycodes: %02x\n", val); - adb_virtual_key_update(val & 0x7f, val >> 7); - break; - case 0x12: /* ADB cmd12 */ - adb_printf("Performing ADB cmd 12\n"); - adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], - g_adb_cmd_data[1]); - break; - case 0x13: /* ADB cmd13 */ - adb_printf("Performing ADB cmd 13\n"); - adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], - g_adb_cmd_data[1]); - break; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: - case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - /* Listen dev x reg 3 */ - if(dev == g_kbd_dev_addr) { - if(g_adb_cmd_data[1] == 0xfe) { - /* change keyboard addr? */ - new_kbd = g_adb_cmd_data[0] & 0xf; - if(new_kbd != dev) { - printf("Moving kbd to dev %x!\n", - new_kbd); - adb_error(); - } - g_kbd_dev_addr = new_kbd; - } else if(g_adb_cmd_data[1] != 1) { - /* see what new device handler id is */ - printf("KBD listen to dev %x reg 3: 1:%02x\n", - dev, g_adb_cmd_data[1]); - adb_error(); - } - if(g_adb_cmd_data[0] != (word32)g_kbd_dev_addr) { - /* see if app is trying to change addr */ - printf("KBD listen to dev %x reg 3: 0:%02x!\n", - dev, g_adb_cmd_data[0]); - adb_error(); - } - g_kbd_reg3_16bit = ((g_adb_cmd_data[0] & 0xf) << 12) + - (g_kbd_reg3_16bit & 0x0fff); - } else if(dev == g_mouse_dev_addr) { - if(g_adb_cmd_data[0] != (word32)dev) { - /* see if app is trying to change mouse addr */ - printf("MOUS listen to dev %x reg3: 0:%02x!\n", - dev, g_adb_cmd_data[0]); - adb_error(); - } - if(g_adb_cmd_data[1] != 1 && g_adb_cmd_data[1] != 2) { - /* see what new device handler id is */ - printf("MOUS listen to dev %x reg 3: 1:%02x\n", - dev, g_adb_cmd_data[1]); - adb_error(); - } - } else { - printf("Listen cmd to dev %x reg3????\n", dev); - printf("data0: %02x, data1: %02x ????\n", - g_adb_cmd_data[0], g_adb_cmd_data[1]); - adb_error(); - } - break; - default: - printf("Doing adb_cmd %02x: UNKNOWN!\n", g_adb_cmd); - break; - } -} - - -int -adb_read_c027() -{ - word32 ret; - - if(halt_on_all_c027) { - halt_printf("halting on all c027 reads!\n"); - } - - if(g_c027_val & (~ADB_C027_NEG_MASK)) { - halt_printf("read_c027: g_c027_val: %02x\n", g_c027_val); - } - - ret = (g_c027_val & ADB_C027_NEG_MASK); - - if(g_adb_mouse_valid_data) { - ret |= ADB_C027_MOUSE_DATA; - } - - if(g_adb_interrupt_byte != 0) { - ret |= ADB_C027_DATA_VALID; - } else if(g_adb_data_pending > 0) { - if((g_adb_state != ADB_IN_CMD)) { - ret |= ADB_C027_DATA_VALID; - } - } - - if(g_adb_mouse_coord) { - ret |= ADB_C027_MOUSE_COORD; - } - -#if 0 - adb_printf("Read c027: %02x, int_byte: %02x, d_pend: %d\n", - ret, g_adb_interrupt_byte, g_adb_data_pending); -#endif - -#if 0 - adb_log(0xc027, ret); -#endif - return ret; -} - -void -adb_write_c027(int val) -{ - word32 old_val; - word32 new_int; - word32 old_int; - - adb_printf("Writing c027 with %02x\n", val); - adb_log(0x1c027, val); - - - old_val = g_c027_val; - - g_c027_val = (val & ADB_C027_NEG_MASK); - new_int = g_c027_val & ADB_C027_MOUSE_INT; - old_int = old_val & ADB_C027_MOUSE_INT; - if(!new_int && old_int) { - adb_clear_mouse_int(); - } - - new_int = g_c027_val & ADB_C027_DATA_INT; - old_int = old_val & ADB_C027_DATA_INT; - if(!new_int && old_int) { - /* ints were on, now off */ - adb_clear_data_int(); - } - - if(g_c027_val & ADB_C027_KBD_INT) { - halt_printf("Can't support kbd interrupts!\n"); - } - - return; -} - -int -read_adb_ram(word32 addr) -{ - int val; - - adb_printf("Reading adb ram addr: %02x\n", addr); - - if(addr >= 0x100) { - if(addr >= 0x1000 && addr < 0x2000) { - /* ROM self-test checksum */ - if(addr == 0x1400) { - val = 0x72; - } else if(addr == 0x1401) { - val = 0xf7; - } else { - val = 0; - } - } else { - printf("adb ram addr out of range: %04x!\n", addr); - val = 0; - } - } else { - val = adb_memory[addr]; - if((addr == 0xb) && (g_rom_version == 1)) { - // read special key state byte for Out of This World - val = (g_c025_val >> 1) & 0x43; - val |= (g_c025_val << 2) & 0x4; - val |= (g_c025_val >> 2) & 0x10; - } - if((addr == 0xc) && (g_rom_version >= 3)) { - // read special key state byte for Out of This World - val = g_c025_val & 0xc7; - printf("val is %02x\n", val); - } - } - - adb_printf("adb_ram returning %02x\n", val); - return val; -} - -void -write_adb_ram(word32 addr, int val) -{ - - adb_printf("Writing adb_ram addr: %02x: %02x\n", addr, val); - - if(addr >= 0x100) { - printf("write adb_ram addr: %02x: %02x!\n", addr, val); - adb_error(); - } else { - adb_memory[addr] = val; - } -} - -int -adb_get_keypad_xy(int get_y) -{ - int x, y; - int key; - int num_keys; - int i, j; - - key = 1; - num_keys = 0; - x = 0; - y = 0; - for(i = 0; i < 3; i++) { - for(j = 0; j < 3; j++) { - if(g_keypad_key_is_down[key]) { - num_keys++; - x = x + (j - 1)*32768; - y = y + (1 - i)*32768; - } - key++; - } - } - if(num_keys == 0) { - num_keys = 1; - } - - adb_printf("get_xy=%d, num_keys: %d, x:%d, y:%d\n", get_y, - num_keys, x, y); - - if(get_y) { - return y / num_keys; - } else { - return x / num_keys; - } -} - -int -update_mouse(int x, int y, int button_states, int buttons_valid) -{ - double dcycs; - int button1_changed; - int mouse_moved; - int unhide; - int pos; - int i; - - dcycs = g_cur_dcycs; - - g_mouse_raw_x = x; - g_mouse_raw_y = y; - - unhide = 0; - if(x < 0) { - x = 0; - unhide = 1; - } - if(x >= 640) { - x = 639; - unhide = 1; - } - if(y < 0) { - y = 0; - unhide = 1; - } - if(y >= 400) { - y = 399; - unhide = 1; - } - - - g_unhide_pointer = unhide && !g_warp_pointer; - - if(!g_warp_pointer) { - if(g_hide_pointer && g_unhide_pointer) { - /* cursor has left a2 window, show it */ - g_hide_pointer = 0; - x_hide_pointer(0); - } - if((g_num_lines_prev_superhires == 200) && - (g_num_lines_prev_superhires640 == 0) && - ((g_slow_memory_ptr[0x19d00] & 0x80) == 0)) { - // In 320-mode superhires, cut mouse range in half - x = x >> 1; - } - y = y >> 1; - } - - mouse_compress_fifo(dcycs); - -#if 0 - printf("Update Mouse called with buttons:%d x,y:%d,%d, fifo:%d,%d, " - " a2: %d,%d\n", buttons_valid, x, y, - g_mouse_fifo[0].x, g_mouse_fifo[0].y, - g_mouse_a2_x, g_mouse_a2_y); -#endif - - if((buttons_valid < 0) && g_warp_pointer) { - /* Warping the pointer causes it to jump here...this is not */ - /* real motion, just update info and get out */ - g_mouse_a2_x += (x - g_mouse_fifo[0].x); - g_mouse_a2_y += (y - g_mouse_fifo[0].y); - g_mouse_fifo[0].x = x; - g_mouse_fifo[0].y = y; - return 0; - } - -#if 0 - printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n", - g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo[0].x, - g_mouse_fifo[0].y, g_mouse_a2_x, g_mouse_a2_y); -#endif - - mouse_moved = (g_mouse_fifo[0].x != x) || (g_mouse_fifo[0].y != y); - - g_mouse_a2_x += g_mouse_warp_x; - g_mouse_a2_y += g_mouse_warp_y; - g_mouse_fifo[0].x = x; - g_mouse_fifo[0].y = y; - g_mouse_fifo[0].dcycs = dcycs; - g_mouse_warp_x = 0; - g_mouse_warp_y = 0; - - button1_changed = (buttons_valid & 1) && - ((button_states & 1) != (g_mouse_fifo[0].buttons & 1)); - - if((button_states & 4) && !(g_mouse_fifo[0].buttons & 4) && - (buttons_valid & 4)) { - /* right button pressed */ - adb_increment_speed(); - } - if((button_states & 2) && !(g_mouse_fifo[0].buttons & 2) && - (buttons_valid & 2)) { - /* middle button pressed */ - adb_increment_speed(); - //halt2_printf("Middle button pressed\n"); - } - - pos = g_mouse_fifo_pos; - if((pos < (ADB_MOUSE_FIFO - 2)) && button1_changed) { - /* copy delta to overflow, set overflow */ - /* overflow ensures the mouse button state is precise at */ - /* button up/down times. Using a mouse event list where */ - /* deltas accumulate until a button change would work, too */ - for(i = pos; i >= 0; i--) { - g_mouse_fifo[i + 1] = g_mouse_fifo[i]; /* copy struct*/ - } - g_mouse_fifo_pos = pos + 1; - } - - g_mouse_fifo[0].buttons = (button_states & buttons_valid) | - (g_mouse_fifo[0].buttons & ~buttons_valid); - - if(mouse_moved || button1_changed) { - if( (g_mouse_ctl_addr == g_mouse_dev_addr) && - ((g_adb_mode & 0x2) == 0)) { - g_adb_mouse_valid_data = 1; - adb_add_mouse_int(); - } - } - - return mouse_moved; -} - -int -mouse_read_c024(double dcycs) -{ - word32 ret; - word32 tool_start; - int em_active; - int target_x, target_y; - int delta_x, delta_y; - int a2_x, a2_y; - int mouse_button; - int clamped; - int pos; - - if(((g_adb_mode & 0x2) != 0) || (g_mouse_dev_addr != g_mouse_ctl_addr)){ - /* mouse is off, return 0, or mouse is not autopoll */ - g_adb_mouse_valid_data = 0; - adb_clear_mouse_int(); - return 0; - } - - mouse_compress_fifo(dcycs); - - pos = g_mouse_fifo_pos; - target_x = g_mouse_fifo[pos].x; - target_y = g_mouse_fifo[pos].y; - mouse_button = (g_mouse_fifo[pos].buttons & 1); - delta_x = target_x - g_mouse_a2_x; - delta_y = target_y - g_mouse_a2_y; - - clamped = 0; - if(delta_x > 0x3f) { - delta_x = 0x3f; - clamped = 1; - } else if(delta_x < -0x3f) { - delta_x = -0x3f; - clamped = 1; - } - if(delta_y > 0x3f) { - delta_y = 0x3f; - clamped = 1; - } else if(delta_y < -0x3f) { - delta_y = -0x3f; - clamped = 1; - } - - if(pos > 0) { - /* peek into next entry's button info if we are not clamped */ - /* and we're returning the y-coord */ - if(!clamped && g_adb_mouse_coord) { - mouse_button = g_mouse_fifo[pos - 1].buttons & 1; - } - } - - if(g_adb_mouse_coord) { - /* y coord */ - delta_x = 0; /* clear unneeded x delta */ - } else { - delta_y = 0; /* clear unneeded y delta */ - } - - - adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", - g_slow_memory_ptr[0x100e9], g_slow_memory_ptr[0x100ea], - g_slow_memory_ptr[0x100eb], g_slow_memory_ptr[0x100ec]); - adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", - g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], - g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); - - /* Update event manager internal state */ - tool_start = (g_slow_memory_ptr[0x103ca] << 16) + - (g_slow_memory_ptr[0x103c9] << 8) + - g_slow_memory_ptr[0x103c8]; - - em_active = 0; - if((tool_start >= 0x20000) && (tool_start < (g_mem_size_total - 28)) ) { - /* seems to be valid ptr to addr of mem space for tools */ - /* see if event manager appears to be active */ - em_active = g_memory_ptr[tool_start + 6*4] + - (g_memory_ptr[tool_start + 6*4 + 1] << 8); - if(g_warp_pointer) { - em_active = 0; - } - } - - a2_x = g_mouse_a2_x; - a2_y = g_mouse_a2_y; - - if(em_active) { - if((!g_hide_pointer) && (g_num_lines_prev_superhires == 200) && - !g_unhide_pointer) { - /* if super-hires and forcing tracking, then hide */ - g_hide_pointer = 1; - x_hide_pointer(1); - } - if(g_adb_mouse_coord == 0) { - /* update x coord values */ - g_slow_memory_ptr[0x47c] = a2_x & 0xff; - g_slow_memory_ptr[0x57c] = a2_x >> 8; - g_memory_ptr[0x47c] = a2_x & 0xff; - g_memory_ptr[0x57c] = a2_x >> 8; - - g_slow_memory_ptr[0x10190] = a2_x & 0xff; - g_slow_memory_ptr[0x10192] = a2_x >> 8; - } else { - g_slow_memory_ptr[0x4fc] = a2_y & 0xff; - g_slow_memory_ptr[0x5fc] = a2_y >> 8; - g_memory_ptr[0x4fc] = a2_y & 0xff; - g_memory_ptr[0x5fc] = a2_y >> 8; - - g_slow_memory_ptr[0x10191] = a2_y & 0xff; - g_slow_memory_ptr[0x10193] = a2_y >> 8; - } - } else { - if(g_hide_pointer && !g_warp_pointer) { - g_hide_pointer = 0; - x_hide_pointer(0); - } - } - - ret = ((!mouse_button) << 7) + ((delta_x | delta_y) & 0x7f); - if(g_adb_mouse_coord) { - g_mouse_a2_button = mouse_button; /* y coord has button*/ - } else { - ret |= 0x80; /* mouse button not down on x coord rd */ - } - - a2_x += delta_x; - a2_y += delta_y; - g_mouse_a2_x = a2_x; - g_mouse_a2_y = a2_y; - if(g_mouse_fifo_pos) { - if((target_x == a2_x) && (target_y == a2_y) && - (g_mouse_a2_button == mouse_button)) { - g_mouse_fifo_pos--; - } - } - - - adb_printf("Read c024, mouse is_y:%d, %02x, vbl:%08x, dcyc:%f, em:%d\n", - g_adb_mouse_coord, ret, g_vbl_count, dcycs, em_active); - adb_printf("...mouse targ_x:%d,%d delta_x,y:%d,%d fifo:%d, a2:%d,%d\n", - target_x, target_y, delta_x, delta_y, g_mouse_fifo_pos, - a2_x, a2_y); - adb_printf(" post a2_x:%02x,%02x,%02x,%02x\n", - g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], - g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); - - if((g_mouse_fifo_pos == 0) && (g_mouse_fifo[0].x == a2_x) && - (g_mouse_fifo[0].y == a2_y) && - ((g_mouse_fifo[0].buttons & 1) == g_mouse_a2_button)) { - g_adb_mouse_valid_data = 0; - adb_clear_mouse_int(); - } - - g_adb_mouse_coord = !g_adb_mouse_coord; - return ret; -} - -void -mouse_compress_fifo(double dcycs) -{ - int pos; - - /* The mouse fifo exists so that fast button changes don't get lost */ - /* if the emulator lags behind the mouse events */ - /* But the FIFO means really old mouse events are saved if */ - /* the emulated code isn't looking at the mouse registers */ - /* This routine compresses all mouse events > 0.5 seconds old */ - - for(pos = g_mouse_fifo_pos; pos >= 1; pos--) { - if(g_mouse_fifo[pos].dcycs < (dcycs - 500*1000.0)) { - /* Remove this entry */ - adb_printf("Old mouse FIFO pos %d removed\n", pos); - g_mouse_fifo_pos = pos - 1; - continue; - } - /* Else, stop searching the FIFO */ - break; - } -} - -void -adb_key_event(int a2code, int is_up) -{ - word32 special; - word32 vbl_count; - int key; - int hard_key; - int pos; - int tmp_ascii; - int ascii; - - if(is_up) { - adb_printf("adb_key_event, key:%02x, is up, g_key_down: %02x\n", - a2code, g_key_down); - } - - if(a2code < 0 || a2code > 0x7f) { - halt_printf("add_key_event: a2code: %04x!\n", a2code); - return; - } - - if(!is_up && a2code == 0x35) { - /* ESC pressed, see if ctrl & cmd key down */ - if(CTRL_DOWN && CMD_DOWN) { - /* Desk mgr int */ - printf("Desk mgr int!\n"); - - g_adb_interrupt_byte |= 0x20; - adb_add_data_int(); - } - } - - /* convert key to ascii, if possible */ - hard_key = 0; - if(a2_key_to_ascii[a2code][1] & 0xef00) { - /* special key */ - } else { - /* we have ascii */ - hard_key = 1; - } - - pos = 1; - ascii = a2_key_to_ascii[a2code][1]; - if(CAPS_LOCK_DOWN && (ascii >= 'a' && ascii <= 'z')) { - pos = 2; - if(SHIFT_DOWN && (g_adb_mode & 0x40)) { - /* xor shift mode--capslock and shift == lowercase */ - pos = 1; - } - } else if(SHIFT_DOWN) { - pos = 2; - } - - ascii = a2_key_to_ascii[a2code][pos]; - if(CTRL_DOWN) { - tmp_ascii = a2_key_to_ascii[a2code][3]; - if(tmp_ascii >= 0) { - ascii = tmp_ascii; - } - } - key = (ascii & 0x7f) + 0x80; - - special = (ascii >> 8) & 0xff; - if(ascii < 0) { - printf("ascii1: %d, a2code: %02x, pos: %d\n", ascii,a2code,pos); - ascii = 0; - special = 0; - } - - - if(!is_up) { - if(hard_key) { - g_kbd_buf[g_kbd_chars_buffered] = key; - g_kbd_chars_buffered++; - if(g_kbd_chars_buffered >= MAX_KBD_BUF) { - g_kbd_chars_buffered = MAX_KBD_BUF - 1; - } - g_key_down = 1; - g_a2code_down = a2code; - - /* first key down, set up autorepeat */ - vbl_count = g_vbl_count; - if(g_config_control_panel) { - vbl_count = g_cfg_vbl_count; - } - g_adb_repeat_vbl = vbl_count + g_adb_repeat_delay; - if(g_adb_repeat_delay == 0) { - g_key_down = 0; - } - g_hard_key_down = 1; - } - - g_c025_val = g_c025_val | special; - adb_printf("new c025_or: %02x\n", g_c025_val); - } else { - if(hard_key && (a2code == g_a2code_down)) { - g_hard_key_down = 0; - /* Turn off repeat */ - g_key_down = 0; - } - - g_c025_val = g_c025_val & (~ special); - adb_printf("new c025_and: %02x\n", g_c025_val); - } - - if(g_key_down) { - g_c025_val = g_c025_val & (~0x20); - } else { - /* If no hard key down, set update mod latch */ - g_c025_val = g_c025_val | 0x20; - } - -} - -word32 -adb_read_c000() -{ - word32 vbl_count; - - if( ((g_kbd_buf[0] & 0x80) == 0) && (g_key_down == 0)) { - /* nothing happening, check clipboard */ - int c = clipboard_get_char(); - if(c) { - /* inject clipboard char into keyboard buffer */ - g_kbd_buf[0] = c; - } - /* just get out */ - return g_kbd_buf[0]; - } - if(g_kbd_buf[0] & 0x80) { - /* got one */ - if((g_kbd_read_no_update++ > 5) && (g_kbd_chars_buffered > 1)) { - /* read 5 times, keys pending, let's move it along */ - printf("Read %02x %d times, tossing\n", g_kbd_buf[0], - g_kbd_read_no_update); - adb_access_c010(); - } - } else { - vbl_count = g_vbl_count; - if(g_config_control_panel) { - vbl_count = g_cfg_vbl_count; - } - if(g_key_down && vbl_count >= g_adb_repeat_vbl) { - /* repeat the g_key_down */ - g_c025_val |= 0x8; - adb_key_event(g_a2code_down, 0); - g_adb_repeat_vbl = vbl_count + g_adb_repeat_rate; - } - } - - return g_kbd_buf[0]; -} - -word32 -adb_access_c010() -{ - int tmp; - int i; - - g_kbd_read_no_update = 0; - - tmp = g_kbd_buf[0] & 0x7f; - g_kbd_buf[0] = tmp; - - tmp = tmp | (g_hard_key_down << 7); - if(g_kbd_chars_buffered) { - for(i = 1; i < g_kbd_chars_buffered; i++) { - g_kbd_buf[i - 1] = g_kbd_buf[i]; - } - g_kbd_chars_buffered--; - } - - g_c025_val = g_c025_val & (~ (0x08)); - - return tmp; -} - -word32 -adb_read_c025() -{ - return g_c025_val; -} - -int -adb_is_cmd_key_down() -{ - return CMD_DOWN; -} - -int -adb_is_option_key_down() -{ - return OPTION_DOWN; -} - -void -adb_increment_speed() -{ - const char *str; - - g_limit_speed++; - if(g_limit_speed > 3) { - g_limit_speed = 0; - } - - str = ""; - switch(g_limit_speed) { - case 0: - str = "...as fast as possible!"; - break; - case 1: - str = "...1.024MHz!"; - break; - case 2: - str = "...2.8MHz!"; - break; - case 3: - str = "...8.0MHz!"; - break; - } - printf("Toggling g_limit_speed to %d%s\n", g_limit_speed, str); -} - -void -adb_physical_key_update(int a2code, int is_up) -{ - int autopoll; - int special; - int ascii_and_type; - int ascii; - - /* this routine called by xdriver to pass raw codes--handle */ - /* ucontroller and ADB bus protocol issues here */ - /* if autopoll on, pass it on through to c025,c000 regs */ - /* else only put it in kbd reg 3, and pull SRQ if needed */ - - adb_printf("adb_phys_key_update: %02x, %d\n", a2code, is_up); - - adb_printf("Handle a2code: %02x, is_up: %d\n", a2code, is_up); - - if(a2code < 0 || a2code > 0x7f) { - halt_printf("a2code: %04x!\n", a2code); - return; - } - - /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards) */ - if(a2code >= 0x7b && a2code <= 0x7e) { - a2code = a2code - 0x40; - } - - /* Now check for special keys (function keys, etc) */ - ascii_and_type = a2_key_to_ascii[a2code][1]; - special = 0; - if((ascii_and_type & 0xf000) == 0x8000) { - /* special function key */ - special = ascii_and_type & 0xff; - switch(special) { - case 0x01: /* F1 - remap to cmd */ - a2code = 0x37; - special = 0; - break; - case 0x02: /* F2 - remap to option */ - a2code = 0x3a; - special = 0; - break; - case 0x03: /* F3 - remap to escape for OS/2 */ - a2code = 0x35; - special = 0; - break; - case 0x0c: /* F12 - remap to reset */ - a2code = 0x7f; - special = 0; - break; - default: - break; - } - } - - /* CUA clipboard paste - for those that remember ctrl-insert/shift-insert */ - if(is_up == 0 && a2code == 0x72 && SHIFT_DOWN) { - clipboard_paste(); - } - - /* Only process reset requests here */ - if(is_up == 0 && a2code == 0x7f && CTRL_DOWN) { - /* Reset pressed! */ - printf("Reset pressed since CTRL_DOWN: %d\n", CTRL_DOWN); - do_reset(); - return; - } - - if(special && !is_up) { - switch(special) { -// OG Disabled special keys (but warp) -#ifndef ACTIVEGS - case 0x04: /* F4 - emulator config panel */ - if (CMD_DOWN) - { - printf("Quit!\n"); - iwm_shut(); - my_exit(1); - } - else - { - cfg_toggle_config_panel(); - } - break; - case 0x05: /* F5 - emulator clipboard paste */ - clipboard_paste(); - break; - case 0x06: /* F6 - emulator speed */ - if(SHIFT_DOWN) { - halt2_printf("Shift-F6 pressed\n"); - } else { - adb_increment_speed(); - } - break; - case 0x07: /* F7 - fast disk emul */ - g_fast_disk_emul = !g_fast_disk_emul; - printf("g_fast_disk_emul is now %d\n", - g_fast_disk_emul); - break; -#endif - case 0x08: /* F8 - warp pointer */ - g_warp_pointer = !g_warp_pointer; - if(g_hide_pointer != g_warp_pointer) { - g_hide_pointer = g_warp_pointer; - x_hide_pointer(g_hide_pointer); - } - break; -#ifndef ACTIVEGS - case 0x09: /* F9 - swap paddles */ - if(SHIFT_DOWN) { - g_swap_paddles = !g_swap_paddles; - printf("Swap paddles is now: %d\n", - g_swap_paddles); - } else { - g_invert_paddles = !g_invert_paddles; - printf("Invert paddles is now: %d\n", - g_invert_paddles); - } - break; - case 0x0a: /* F10 - change a2vid paletter */ - if (SHIFT_DOWN) { -#ifdef TOGGLE_STATUS - extern void x_toggle_status_lines(); - x_toggle_status_lines(); -#endif - } else if (CMD_DOWN) { - do_reset(); - return; - } else { - change_a2vid_palette((g_a2vid_palette + 1) & 0xf); - } - break; - case 0x0b: /* F11 - full screen */ - g_fullscreen = !g_fullscreen; - x_full_screen(g_fullscreen); - break; -#endif - } - - return; - } - /* Handle Keypad Joystick here partly...if keypad key pressed */ - /* while in Keypad Joystick mode, do not pass it on as a key press */ - if((ascii_and_type & 0xff00) == 0x1000) { - /* Keep track of keypad number keys being up or down even */ - /* if joystick mode isn't keypad. This avoid funny cases */ - /* if joystick mode is changed while a key is pressed */ - ascii = ascii_and_type & 0xff; - if(ascii > 0x30 && ascii <= 0x39) { - g_keypad_key_is_down[ascii - 0x30] = !is_up; - } - if(g_joystick_type == JOYSTICK_TYPE_KEYPAD) { - /* If Joystick type is keypad, then do not let these */ - /* keypress pass on further, except for cmd/opt */ - if(ascii == 0x30) { - /* remap '0' to cmd */ - a2code = 0x37; - } else if(ascii == 0x2e || ascii == 0x2c) { - /* remap '.' and ',' to option */ - a2code = 0x3a; - } else { - /* Just ignore it in this mode */ - return; - } - } - } - - autopoll = 1; - if(g_adb_mode & 1) { - /* autopoll is explicitly off */ - autopoll = 0; - } - if(g_kbd_dev_addr != g_kbd_ctl_addr) { - /* autopoll is off because ucontroller doesn't know kbd moved */ - autopoll = 0; - } - if(g_config_control_panel) { - /* always do autopoll */ - autopoll = 1; - } - - - if(is_up) { - if(!autopoll) { - /* no auto keys, generate SRQ! */ - adb_kbd_reg0_data(a2code, is_up); - } else { - adb_virtual_key_update(a2code, is_up); - } - } else { - if(!autopoll) { - /* no auto keys, generate SRQ! */ - adb_kbd_reg0_data(a2code, is_up); - } else { - /* was up, now down */ - adb_virtual_key_update(a2code, is_up); - } - } -} - -void -adb_virtual_key_update(int a2code, int is_up) -{ - int i; - int bitpos; - word32 mask; - - adb_printf("Virtual handle a2code: %02x, is_up: %d\n", a2code, is_up); - - if(a2code < 0 || a2code > 0x7f) { - halt_printf("a2code: %04x!\n", a2code); - return; - } - - i = (a2code >> 5) & 3; - bitpos = a2code & 0x1f; - mask = (1 << bitpos); - - if(is_up) { - if(g_virtual_key_up[i] & mask) { - /* already up, do nothing */ - } else { - g_virtual_key_up[i] |= mask; - adb_key_event(a2code, is_up); - } - } else { - if(g_virtual_key_up[i] & mask) { - g_virtual_key_up[i] &= (~mask); - adb_key_event(a2code, is_up); - } - } -} - -void -adb_all_keys_up() -{ - word32 mask; - int i, j; - - for(i = 0; i < 4; i++) { - for(j = 0; j < 32; j++) { - mask = 1 << j; - if((g_virtual_key_up[i] & mask) == 0) { - /* create key-up event */ - adb_physical_key_update(i*32 + j, 1); - } - } - } -} - -void -adb_kbd_repeat_off() -{ - g_key_down = 0; -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 - 2013 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* adb_mode bit 3 and bit 2 (faster repeats for arrows and space/del) not done*/ + +#include "adb.h" + +int g_fullscreen = 0; + +extern int Verbose; +extern word32 g_vbl_count; +extern int g_num_lines_prev_superhires640; +extern int g_num_lines_prev_superhires; +extern int g_rom_version; +extern int g_fast_disk_emul; +extern int g_limit_speed; +extern int g_irq_pending; +extern int g_swap_paddles; +extern int g_invert_paddles; +extern int g_joystick_type; +extern int g_a2vid_palette; +extern int g_config_control_panel; +extern word32 g_cfg_vbl_count; +extern double g_cur_dcycs; + +extern byte *g_slow_memory_ptr; +extern byte *g_memory_ptr; +extern word32 g_mem_size_total; + +enum { + ADB_IDLE = 0, + ADB_IN_CMD, + ADB_SENDING_DATA, +}; + +#define ADB_C027_MOUSE_DATA 0x80 +#define ADB_C027_MOUSE_INT 0x40 +#define ADB_C027_DATA_VALID 0x20 +#define ADB_C027_DATA_INT 0x10 +#define ADB_C027_KBD_VALID 0x08 +#define ADB_C027_KBD_INT 0x04 +#define ADB_C027_MOUSE_COORD 0x02 +#define ADB_C027_CMD_FULL 0x01 + +#define ADB_C027_NEG_MASK ( ~ ( \ + ADB_C027_MOUSE_DATA | ADB_C027_DATA_VALID | \ + ADB_C027_KBD_VALID | ADB_C027_MOUSE_COORD | \ + ADB_C027_CMD_FULL)) + + +int halt_on_all_c027 = 0; + +word32 g_adb_repeat_delay = 45; +word32 g_adb_repeat_rate = 3; +word32 g_adb_repeat_info = 0x23; +word32 g_adb_char_set = 0x0; +word32 g_adb_layout_lang = 0x0; + +word32 g_adb_interrupt_byte = 0; +int g_adb_state = ADB_IDLE; + +word32 g_adb_cmd = (word32)-1; +int g_adb_cmd_len = 0; +int g_adb_cmd_so_far = 0; +word32 g_adb_cmd_data[16]; + +#define MAX_ADB_DATA_PEND 16 + +word32 g_adb_data[MAX_ADB_DATA_PEND]; +int g_adb_data_pending = 0; + +word32 g_c027_val = 0; +word32 g_c025_val = 0; + +byte adb_memory[256]; + +word32 g_adb_mode = 0; /* mode set via set_modes, clear_modes */ + +int g_warp_pointer = 0; +int g_hide_pointer = 0; +int g_unhide_pointer = 0; + +int g_mouse_a2_x = 0; +int g_mouse_a2_y = 0; +int g_mouse_a2_button = 0; +int g_mouse_fifo_pos = 0; +int g_mouse_raw_x = 0; +int g_mouse_raw_y = 0; + +#define ADB_MOUSE_FIFO 8 + +STRUCT(Mouse_fifo) { + double dcycs; + int x; + int y; + int buttons; +}; + +Mouse_fifo g_mouse_fifo[ADB_MOUSE_FIFO] = { { 0, 0, 0, 0 } }; + +int g_mouse_warp_x = 0; +int g_mouse_warp_y = 0; + +int g_adb_mouse_valid_data = 0; +int g_adb_mouse_coord = 0; + +#define MAX_KBD_BUF 8 + +int g_key_down = 0; +int g_hard_key_down = 0; +int g_a2code_down = 0; +int g_kbd_read_no_update = 0; +int g_kbd_chars_buffered = 0; +int g_kbd_buf[MAX_KBD_BUF]; +word32 g_adb_repeat_vbl = 0; + +int g_kbd_dev_addr = 2; /* ADB physical kbd addr */ +int g_mouse_dev_addr = 3; /* ADB physical mouse addr */ + +int g_kbd_ctl_addr = 2; /* ADB microcontroller's kbd addr */ +int g_mouse_ctl_addr = 3; /* ADB ucontroller's mouse addr*/ + /* above are ucontroller's VIEW of where mouse/kbd */ + /* are...if they are moved, mouse/keyboard funcs */ + /* should stop (c025, c000, c024, etc). */ + +word32 g_virtual_key_up[4]; /* bitmask of all possible 128 a2codes */ + /* indicates which keys are up=1 by bit */ + +int g_keypad_key_is_down[10] = { 0 };/* List from 0-9 of which keypad */ + /* keys are currently pressed */ + + +#define SHIFT_DOWN ( (g_c025_val & 0x01) ) +#define CTRL_DOWN ( (g_c025_val & 0x02) ) +#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) +#define OPTION_DOWN ( (g_c025_val & 0x40) ) +#define CMD_DOWN ( (g_c025_val & 0x80) ) + + +#define MAX_ADB_KBD_REG3 16 + +int g_kbd_reg0_pos = 0; +int g_kbd_reg0_data[MAX_ADB_KBD_REG3]; +int g_kbd_reg3_16bit = 0x602; /* also set in adb_reset()! */ + + +int g_adb_init = 0; + +void +adb_init() +{ + int keycode; + int i; + + if(g_adb_init) { + halt_printf("g_adb_init = %d!\n", g_adb_init); + } + g_adb_init = 1; + + for(i = 0; i < 128; i++) { + keycode = a2_key_to_ascii[i][0]; + if(keycode != i) { + printf("ADB keycode lost/skipped: i=%x: keycode=%x\n", + i, keycode); + my_exit(1); + } + } + + g_c025_val = 0; + + for(i = 0; i < 4; i++) { + g_virtual_key_up[i] = -1; + } + + for(i = 0; i < 10; i++) { + g_keypad_key_is_down[i] = 0; + } + + adb_reset(); +} + +// OG Added adb_shut() +void adb_shut() +{ + g_adb_init = 0; +} + +void +adb_reset() +{ + + g_c027_val = 0; + + g_key_down = 0; + + g_kbd_dev_addr = 2; + g_mouse_dev_addr = 3; + + g_kbd_ctl_addr = 2; + g_mouse_ctl_addr = 3; + + adb_clear_data_int(); + adb_clear_mouse_int(); + adb_clear_kbd_srq(); + + g_adb_data_pending = 0; + g_adb_interrupt_byte = 0; + g_adb_state = ADB_IDLE; + g_adb_mouse_coord = 0; + g_adb_mouse_valid_data = 0; + + g_kbd_reg0_pos = 0; + g_kbd_reg3_16bit = 0x602; + +} + + +#define LEN_ADB_LOG 16 +STRUCT(Adb_log) { + word32 addr; + int val; + int state; +}; + +Adb_log g_adb_log[LEN_ADB_LOG]; +int g_adb_log_pos = 0; + +void +adb_log(word32 addr, int val) +{ + int pos; + + pos = g_adb_log_pos; + g_adb_log[pos].addr = addr; + g_adb_log[pos].val = val; + g_adb_log[pos].state = g_adb_state; + pos++; + if(pos >= LEN_ADB_LOG) { + pos = 0; + } + g_adb_log_pos = pos; +} + +void +show_adb_log(void) +{ + int pos; + int i; + + pos = g_adb_log_pos; + printf("ADB log pos: %d\n", pos); + for(i = 0; i < LEN_ADB_LOG; i++) { + pos--; + if(pos < 0) { + pos = LEN_ADB_LOG - 1; + } + printf("%d:%d: addr:%04x = %02x, st:%d\n", i, pos, + g_adb_log[pos].addr, g_adb_log[pos].val, + g_adb_log[pos].state); + } + printf("kbd: dev: %x, ctl: %x; mouse: dev: %x, ctl: %x\n", + g_kbd_dev_addr, g_kbd_ctl_addr, + g_mouse_dev_addr, g_mouse_ctl_addr); + printf("g_adb_state: %d, g_adb_interrupt_byte: %02x\n", + g_adb_state, g_adb_interrupt_byte); +} + +void +adb_error(void) +{ + halt_printf("Adb Error\n"); + + show_adb_log(); +} + + + +void +adb_add_kbd_srq() +{ + if(g_kbd_reg3_16bit & 0x200) { + /* generate SRQ */ + g_adb_interrupt_byte |= 0x08; + add_irq(IRQ_PENDING_ADB_KBD_SRQ); + } else { + printf("Got keycode but no kbd SRQ!\n"); + } +} + +void +adb_clear_kbd_srq() +{ + remove_irq(IRQ_PENDING_ADB_KBD_SRQ); + + /* kbd SRQ's are the only ones to handle now, so just clean it out */ + g_adb_interrupt_byte &= (~(0x08)); +} + +void +adb_add_data_int() +{ + if(g_c027_val & ADB_C027_DATA_INT) { + add_irq(IRQ_PENDING_ADB_DATA); + } +} + +void +adb_add_mouse_int() +{ + if(g_c027_val & ADB_C027_MOUSE_INT) { + add_irq(IRQ_PENDING_ADB_MOUSE); + } +} + +void +adb_clear_data_int() +{ + remove_irq(IRQ_PENDING_ADB_DATA); +} + +void +adb_clear_mouse_int() +{ + remove_irq(IRQ_PENDING_ADB_MOUSE); +} + + +void +adb_send_bytes(int num_bytes, word32 val0, word32 val1, word32 val2) +{ + word32 val; + int shift_amount; + int i; + + if((num_bytes >= 12) || (num_bytes >= MAX_ADB_DATA_PEND)) { + halt_printf("adb_send_bytes: %d is too many!\n", num_bytes); + } + + g_adb_state = ADB_SENDING_DATA; + g_adb_data_pending = num_bytes; + adb_add_data_int(); + + for(i = 0; i < num_bytes; i++) { + if(i < 4) { + val = val0; + } else if(i < 8) { + val = val1; + } else { + val = val2; + } + + shift_amount = 8*(3 - i); + g_adb_data[i] = (val >> shift_amount) & 0xff; + adb_printf("adb_send_bytes[%d] = %02x\n", i, g_adb_data[i]); + } +} + + +void +adb_send_1byte(word32 val) +{ + + if(g_adb_data_pending != 0) { + halt_printf("g_adb_data_pending: %d\n", g_adb_data_pending); + } + + adb_send_bytes(1, val << 24, 0, 0); +} + + + +void +adb_response_packet(int num_bytes, word32 val) +{ + + if(g_adb_data_pending != 0) { + halt_printf("adb_response_packet, but pending: %d\n", + g_adb_data_pending); + } + + g_adb_state = ADB_IDLE; + g_adb_data_pending = num_bytes; + g_adb_data[0] = val & 0xff; + g_adb_data[1] = (val >> 8) & 0xff; + g_adb_data[2] = (val >> 16) & 0xff; + g_adb_data[3] = (val >> 24) & 0xff; + if(num_bytes) { + g_adb_interrupt_byte |= 0x80 + num_bytes - 1; + } else { + g_adb_interrupt_byte |= 0x80; + } + + adb_printf("adb_response packet: %d: %08x\n", + num_bytes, val); + + adb_add_data_int(); +} + + +void +adb_kbd_reg0_data(int a2code, int is_up) +{ + if(g_kbd_reg0_pos >= MAX_ADB_KBD_REG3) { + /* too many keys, toss */ + halt_printf("Had to toss key: %02x, %d\n", a2code, is_up); + return; + } + + g_kbd_reg0_data[g_kbd_reg0_pos] = a2code + (is_up << 7); + + adb_printf("g_kbd_reg0_data[%d] = %02x\n", g_kbd_reg0_pos, + g_kbd_reg0_data[g_kbd_reg0_pos]); + + g_kbd_reg0_pos++; + + adb_add_kbd_srq(); +} + +void +adb_kbd_talk_reg0() +{ + word32 val0, val1; + word32 reg; + int num_bytes; + int num; + int i; + + num = 0; + val0 = g_kbd_reg0_data[0]; + val1 = g_kbd_reg0_data[1]; + + num_bytes = 0; + if(g_kbd_reg0_pos > 0) { + num_bytes = 2; + num = 1; + if((val0 & 0x7f) == 0x7f) { + /* reset */ + val1 = val0; + } else if(g_kbd_reg0_pos > 1) { + num = 2; + if((val1 & 0x7f) == 0x7f) { + /* If first byte some other key, don't */ + /* put RESET next! */ + num = 1; + val1 = 0xff; + } + } else { + val1 = 0xff; + } + } + + if(num) { + for(i = num; i < g_kbd_reg0_pos; i++) { + g_kbd_reg0_data[i-1] = g_kbd_reg0_data[i]; + } + g_kbd_reg0_pos -= num; + } + + reg = (val0 << 8) + val1; + + adb_printf("adb_kbd_talk0: %04x\n", reg); + + adb_response_packet(num_bytes, reg); + if(g_kbd_reg0_pos == 0) { + adb_clear_kbd_srq(); + } +} + +void +adb_set_config(word32 val0, word32 val1, word32 val2) +{ + int new_mouse; + int new_kbd; + int tmp1; + + new_mouse = val0 >> 4; + new_kbd = val0 & 0xf; + if(new_mouse != g_mouse_ctl_addr) { + printf("ADB config: mouse from %x to %x!\n", + g_mouse_ctl_addr, new_mouse); + adb_error(); + g_mouse_ctl_addr = new_mouse; + } + if(new_kbd != g_kbd_ctl_addr) { + printf("ADB config: kbd from %x to %x!\n", + g_kbd_ctl_addr, new_kbd); + adb_error(); + g_kbd_ctl_addr = new_kbd; + } + + + tmp1 = val2 >> 4; + if(tmp1 == 4) { + g_adb_repeat_delay = 0; + } else if(tmp1 < 4) { + g_adb_repeat_delay = (tmp1 + 1) * 15; + } else { + halt_printf("Bad ADB repeat delay: %02x\n", tmp1); + } + + tmp1 = val2 & 0xf; + if(g_rom_version >= 3) { + tmp1 = 9 - tmp1; + } + + switch(tmp1) { + case 0: + g_adb_repeat_rate = 1; + break; + case 1: + g_adb_repeat_rate = 2; + break; + case 2: + g_adb_repeat_rate = 3; + break; + case 3: + g_adb_repeat_rate = 3; + break; + case 4: + g_adb_repeat_rate = 4; + break; + case 5: + g_adb_repeat_rate = 5; + break; + case 6: + g_adb_repeat_rate = 7; + break; + case 7: + g_adb_repeat_rate = 15; + break; + case 8: + /* I don't know what this should be, ROM 03 uses it */ + g_adb_repeat_rate = 30; + break; + case 9: + /* I don't know what this should be, ROM 03 uses it */ + g_adb_repeat_rate = 60; + break; + default: + halt_printf("Bad repeat rate: %02x\n", tmp1); + } + +} + +void +adb_set_new_mode(word32 val) +{ + if(val & 0x03) { + printf("Disabling keyboard/mouse:%02x!\n", val); + } + + if(val & 0xa2) { + halt_printf("ADB set mode: %02x!\n", val); + adb_error(); + } + + g_adb_mode = val; +} + + +int +adb_read_c026() +{ + word32 ret; + int i; + + ret = 0; + switch(g_adb_state) { + case ADB_IDLE: + ret = g_adb_interrupt_byte; + g_adb_interrupt_byte = 0; + if(g_irq_pending & IRQ_PENDING_ADB_KBD_SRQ) { + g_adb_interrupt_byte |= 0x08; + } + if(g_adb_data_pending == 0) { + if(ret & 0x80) { + halt_printf("read_c026: ret:%02x, pend:%d\n", + ret, g_adb_data_pending); + } + adb_clear_data_int(); + } + if(g_adb_data_pending) { + if(g_adb_state != ADB_IN_CMD) { + g_adb_state = ADB_SENDING_DATA; + } + } + break; + case ADB_IN_CMD: + ret = 0; + break; + case ADB_SENDING_DATA: + ret = g_adb_data[0]; + for(i = 1; i < g_adb_data_pending; i++) { + g_adb_data[i-1] = g_adb_data[i]; + } + g_adb_data_pending--; + if(g_adb_data_pending <= 0) { + g_adb_data_pending = 0; + g_adb_state = ADB_IDLE; + adb_clear_data_int(); + } + break; + default: + halt_printf("Bad ADB state: %d!\n", g_adb_state); + adb_clear_data_int(); + break; + } + + adb_printf("Reading c026. Returning %02x, st: %02x, pend: %d\n", + ret, g_adb_state, g_adb_data_pending); + + adb_log(0xc026, ret); + return (ret & 0xff); +} + + +void +adb_write_c026(int val) +{ + word32 tmp; + int dev; + + adb_printf("Writing c026 with %02x\n", val); + adb_log(0x1c026, val); + + + switch(g_adb_state) { + case ADB_IDLE: + g_adb_cmd = val; + g_adb_cmd_so_far = 0; + g_adb_cmd_len = 0; + + dev = val & 0xf; + switch(val) { + case 0x01: /* Abort */ + adb_printf("Performing adb abort\n"); + /* adb_abort() */ + break; + case 0x03: /* Flush keyboard buffer */ + adb_printf("Flushing adb keyboard buffer\n"); + /* Do nothing */ + break; + case 0x04: /* Set modes */ + adb_printf("ADB set modes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x05: /* Clear modes */ + adb_printf("ADB clear modes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x06: /* Set config */ + adb_printf("ADB set config\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 3; + break; + case 0x07: /* Sync */ + adb_printf("Performing sync cmd!\n"); + g_adb_state = ADB_IN_CMD; + if(g_rom_version == 1) { + g_adb_cmd_len = 4; + } else { + g_adb_cmd_len = 8; + } + break; + case 0x08: /* Write mem */ + adb_printf("Starting write_mem cmd\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0x09: /* Read mem */ + adb_printf("Performing read_mem cmd!\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0x0a: /* Read modes byte */ + printf("Performing read_modes cmd!\n"); + /* set_halt(1); */ + adb_send_1byte(g_adb_mode); + break; + case 0x0b: /* Read config bytes */ + printf("Performing read_configs cmd!\n"); + tmp = (g_mouse_ctl_addr << 20) + + (g_kbd_ctl_addr << 16) + + (g_adb_char_set << 12) + + (g_adb_layout_lang << 8) + + (g_adb_repeat_info << 0); + tmp = (0x82U << 24) + tmp; + adb_send_bytes(4, tmp, 0, 0); + break; + case 0x0d: /* Get Version */ + adb_printf("Performing get_version cmd!\n"); + val = 0; + if(g_rom_version == 1) { + /* ROM 01 = revision 5 */ + val = 5; + } else { + /* ROM 03 checks for rev >= 6 */ + val = 6; + } + adb_send_1byte(val); + break; + case 0x0e: /* Read avail char sets */ + adb_printf("Performing read avail char sets cmd!\n"); + adb_send_bytes(2, /* just 2 bytes */ + 0x08000000, /* number of ch sets=0x8 */ + 0, 0); + /* set_halt(1); */ + break; + case 0x0f: /* Read avail kbd layouts */ + adb_printf("Performing read avail kbd layouts cmd!\n"); + adb_send_bytes(0x2, /* number of kbd layouts=0xa */ + 0x0a000000, 0, 0); + /* set_halt(1); */ + break; + case 0x10: /* Reset */ + printf("ADB reset, cmd 0x10\n"); + do_reset(); + break; + case 0x11: /* Send ADB keycodes */ + adb_printf("Sending ADB keycodes\n"); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 1; + break; + case 0x12: /* ADB cmd 12: ROM 03 only! */ + if(g_rom_version >= 3) { + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + } else { + printf("ADB cmd 12, but not ROM 3!\n"); + adb_error(); + } + break; + case 0x13: /* ADB cmd 13: ROM 03 only! */ + if(g_rom_version >= 3) { + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + } else { + printf("ADB cmd 13, but not ROM 3!\n"); + adb_error(); + } + break; + case 0x73: /* Disable SRQ device 3: mouse */ + adb_printf("Disabling Mouse SRQ's (device 3)\n"); + /* HACK HACK...should deal with SRQs on mouse */ + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* Listen dev x reg 3 */ + adb_printf("Sending data to dev %x reg 3\n", dev); + g_adb_state = ADB_IN_CMD; + g_adb_cmd_len = 2; + break; + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + /* Talk dev x reg 0 */ + adb_printf("Performing talk dev %x reg 0\n", dev); + if(dev == g_kbd_dev_addr) { + adb_kbd_talk_reg0(); + } else { + printf("Unknown talk dev %x reg 0!\n", dev); + /* send no data, on SRQ, system polls devs */ + /* so we don't want to send anything */ + adb_error(); + } + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + /* Talk dev x reg 3 */ + adb_printf("Performing talk dev %x reg 3\n", dev); + if(dev == g_kbd_dev_addr) { + adb_response_packet(2, g_kbd_reg3_16bit); + } else { + printf("Performing talk dev %x reg 3!!\n", dev); + adb_error(); + } + break; + default: + /* The Gog's says ACS Demo 2 has a bug and writes to */ + /* c026 */ + // OG + if (val==0x84) + printf("ACS Demo2 (3: Colum& Music scroll) : discarding unknown controller command\n"); + else + halt_printf("ADB ucontroller cmd %02x unknown!\n", val); + + break; + } + break; + case ADB_IN_CMD: + adb_printf("Setting byte %d of cmd %02x to %02x\n", + g_adb_cmd_so_far, g_adb_cmd, val); + + g_adb_cmd_data[g_adb_cmd_so_far] = val; + g_adb_cmd_so_far++; + if(g_adb_cmd_so_far >= g_adb_cmd_len) { + adb_printf("Finished cmd %02x\n", g_adb_cmd); + do_adb_cmd(); + } + + break; + default: + printf("adb_state: %02x is unknown! Setting it to ADB_IDLE\n", + g_adb_state); + g_adb_state = ADB_IDLE; + adb_error(); + halt_on_all_c027 = 1; + break; + } + return; +} + +void +do_adb_cmd() +{ + int dev; + int new_kbd; + int addr; + int val; + + dev = g_adb_cmd & 0xf; + + g_adb_state = ADB_IDLE; + + switch(g_adb_cmd) { + case 0x04: /* Set modes */ + adb_printf("Performing ADB set mode: OR'ing in %02x\n", + g_adb_cmd_data[0]); + + val = g_adb_cmd_data[0] | g_adb_mode; + adb_set_new_mode(val); + + break; + case 0x05: /* clear modes */ + adb_printf("Performing ADB clear mode: AND'ing in ~%02x\n", + g_adb_cmd_data[0]); + + val = g_adb_cmd_data[0]; + val = g_adb_mode & (~val); + adb_set_new_mode(val); + break; + case 0x06: /* Set config */ + adb_printf("Set ADB config to %02x %02x %02x\n", + g_adb_cmd_data[0], g_adb_cmd_data[1],g_adb_cmd_data[2]); + + adb_set_config(g_adb_cmd_data[0], g_adb_cmd_data[1], + g_adb_cmd_data[2]); + + break; + case 0x07: /* SYNC */ + adb_printf("Performing ADB SYNC\n"); + adb_printf("data: %02x %02x %02x %02x\n", + g_adb_cmd_data[0], g_adb_cmd_data[1], g_adb_cmd_data[2], + g_adb_cmd_data[3]); + + adb_set_new_mode(g_adb_cmd_data[0]); + adb_set_config(g_adb_cmd_data[1], g_adb_cmd_data[2], + g_adb_cmd_data[3]); + + if(g_rom_version >= 3) { + adb_printf(" and cmd12:%02x %02x cmd13:%02x %02x\n", + g_adb_cmd_data[4], g_adb_cmd_data[5], + g_adb_cmd_data[6], g_adb_cmd_data[7]); + } + break; + case 0x08: /* Write mem */ + addr = g_adb_cmd_data[0]; + val = g_adb_cmd_data[1]; + write_adb_ram(addr, val); + break; + case 0x09: /* Read mem */ + addr = (g_adb_cmd_data[1] << 8) + g_adb_cmd_data[0]; + adb_printf("Performing mem read to addr %04x\n", addr); + adb_send_1byte(read_adb_ram(addr)); + break; + case 0x11: /* Send ADB keycodes */ + val = g_adb_cmd_data[0]; + adb_printf("Performing send ADB keycodes: %02x\n", val); + adb_virtual_key_update(val & 0x7f, val >> 7); + break; + case 0x12: /* ADB cmd12 */ + adb_printf("Performing ADB cmd 12\n"); + adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], + g_adb_cmd_data[1]); + break; + case 0x13: /* ADB cmd13 */ + adb_printf("Performing ADB cmd 13\n"); + adb_printf("data: %02x %02x\n", g_adb_cmd_data[0], + g_adb_cmd_data[1]); + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* Listen dev x reg 3 */ + if(dev == g_kbd_dev_addr) { + if(g_adb_cmd_data[1] == 0xfe) { + /* change keyboard addr? */ + new_kbd = g_adb_cmd_data[0] & 0xf; + if(new_kbd != dev) { + printf("Moving kbd to dev %x!\n", + new_kbd); + adb_error(); + } + g_kbd_dev_addr = new_kbd; + } else if(g_adb_cmd_data[1] != 1) { + /* see what new device handler id is */ + printf("KBD listen to dev %x reg 3: 1:%02x\n", + dev, g_adb_cmd_data[1]); + adb_error(); + } + if(g_adb_cmd_data[0] != (word32)g_kbd_dev_addr) { + /* see if app is trying to change addr */ + printf("KBD listen to dev %x reg 3: 0:%02x!\n", + dev, g_adb_cmd_data[0]); + adb_error(); + } + g_kbd_reg3_16bit = ((g_adb_cmd_data[0] & 0xf) << 12) + + (g_kbd_reg3_16bit & 0x0fff); + } else if(dev == g_mouse_dev_addr) { + if(g_adb_cmd_data[0] != (word32)dev) { + /* see if app is trying to change mouse addr */ + printf("MOUS listen to dev %x reg3: 0:%02x!\n", + dev, g_adb_cmd_data[0]); + adb_error(); + } + if(g_adb_cmd_data[1] != 1 && g_adb_cmd_data[1] != 2) { + /* see what new device handler id is */ + printf("MOUS listen to dev %x reg 3: 1:%02x\n", + dev, g_adb_cmd_data[1]); + adb_error(); + } + } else { + printf("Listen cmd to dev %x reg3????\n", dev); + printf("data0: %02x, data1: %02x ????\n", + g_adb_cmd_data[0], g_adb_cmd_data[1]); + adb_error(); + } + break; + default: + printf("Doing adb_cmd %02x: UNKNOWN!\n", g_adb_cmd); + break; + } +} + + +int +adb_read_c027() +{ + word32 ret; + + if(halt_on_all_c027) { + halt_printf("halting on all c027 reads!\n"); + } + + if(g_c027_val & (~ADB_C027_NEG_MASK)) { + halt_printf("read_c027: g_c027_val: %02x\n", g_c027_val); + } + + ret = (g_c027_val & ADB_C027_NEG_MASK); + + if(g_adb_mouse_valid_data) { + ret |= ADB_C027_MOUSE_DATA; + } + + if(g_adb_interrupt_byte != 0) { + ret |= ADB_C027_DATA_VALID; + } else if(g_adb_data_pending > 0) { + if((g_adb_state != ADB_IN_CMD)) { + ret |= ADB_C027_DATA_VALID; + } + } + + if(g_adb_mouse_coord) { + ret |= ADB_C027_MOUSE_COORD; + } + +#if 0 + adb_printf("Read c027: %02x, int_byte: %02x, d_pend: %d\n", + ret, g_adb_interrupt_byte, g_adb_data_pending); +#endif + +#if 0 + adb_log(0xc027, ret); +#endif + return ret; +} + +void +adb_write_c027(int val) +{ + word32 old_val; + word32 new_int; + word32 old_int; + + adb_printf("Writing c027 with %02x\n", val); + adb_log(0x1c027, val); + + + old_val = g_c027_val; + + g_c027_val = (val & ADB_C027_NEG_MASK); + new_int = g_c027_val & ADB_C027_MOUSE_INT; + old_int = old_val & ADB_C027_MOUSE_INT; + if(!new_int && old_int) { + adb_clear_mouse_int(); + } + + new_int = g_c027_val & ADB_C027_DATA_INT; + old_int = old_val & ADB_C027_DATA_INT; + if(!new_int && old_int) { + /* ints were on, now off */ + adb_clear_data_int(); + } + + if(g_c027_val & ADB_C027_KBD_INT) { + halt_printf("Can't support kbd interrupts!\n"); + } + + return; +} + +int +read_adb_ram(word32 addr) +{ + int val; + + adb_printf("Reading adb ram addr: %02x\n", addr); + + if(addr >= 0x100) { + if(addr >= 0x1000 && addr < 0x2000) { + /* ROM self-test checksum */ + if(addr == 0x1400) { + val = 0x72; + } else if(addr == 0x1401) { + val = 0xf7; + } else { + val = 0; + } + } else { + printf("adb ram addr out of range: %04x!\n", addr); + val = 0; + } + } else { + val = adb_memory[addr]; + if((addr == 0xb) && (g_rom_version == 1)) { + // read special key state byte for Out of This World + val = (g_c025_val >> 1) & 0x43; + val |= (g_c025_val << 2) & 0x4; + val |= (g_c025_val >> 2) & 0x10; + } + if((addr == 0xc) && (g_rom_version >= 3)) { + // read special key state byte for Out of This World + val = g_c025_val & 0xc7; + printf("val is %02x\n", val); + } + } + + adb_printf("adb_ram returning %02x\n", val); + return val; +} + +void +write_adb_ram(word32 addr, int val) +{ + + adb_printf("Writing adb_ram addr: %02x: %02x\n", addr, val); + + if(addr >= 0x100) { + printf("write adb_ram addr: %02x: %02x!\n", addr, val); + adb_error(); + } else { + adb_memory[addr] = val; + } +} + +int +adb_get_keypad_xy(int get_y) +{ + int x, y; + int key; + int num_keys; + int i, j; + + key = 1; + num_keys = 0; + x = 0; + y = 0; + for(i = 0; i < 3; i++) { + for(j = 0; j < 3; j++) { + if(g_keypad_key_is_down[key]) { + num_keys++; + x = x + (j - 1)*32768; + y = y + (1 - i)*32768; + } + key++; + } + } + if(num_keys == 0) { + num_keys = 1; + } + + adb_printf("get_xy=%d, num_keys: %d, x:%d, y:%d\n", get_y, + num_keys, x, y); + + if(get_y) { + return y / num_keys; + } else { + return x / num_keys; + } +} + +int +update_mouse(int x, int y, int button_states, int buttons_valid) +{ + double dcycs; + int button1_changed; + int mouse_moved; + int unhide; + int pos; + int i; + + dcycs = g_cur_dcycs; + + g_mouse_raw_x = x; + g_mouse_raw_y = y; + + unhide = 0; + if(x < 0) { + x = 0; + unhide = 1; + } + if(x >= 640) { + x = 639; + unhide = 1; + } + if(y < 0) { + y = 0; + unhide = 1; + } + if(y >= 400) { + y = 399; + unhide = 1; + } + + + g_unhide_pointer = unhide && !g_warp_pointer; + + if(!g_warp_pointer) { + if(g_hide_pointer && g_unhide_pointer) { + /* cursor has left a2 window, show it */ + g_hide_pointer = 0; + x_hide_pointer(0); + } + if((g_num_lines_prev_superhires == 200) && + (g_num_lines_prev_superhires640 == 0) && + ((g_slow_memory_ptr[0x19d00] & 0x80) == 0)) { + // In 320-mode superhires, cut mouse range in half + x = x >> 1; + } + y = y >> 1; + } + + mouse_compress_fifo(dcycs); + +#if 0 + printf("Update Mouse called with buttons:%d x,y:%d,%d, fifo:%d,%d, " + " a2: %d,%d\n", buttons_valid, x, y, + g_mouse_fifo[0].x, g_mouse_fifo[0].y, + g_mouse_a2_x, g_mouse_a2_y); +#endif + + if((buttons_valid < 0) && g_warp_pointer) { + /* Warping the pointer causes it to jump here...this is not */ + /* real motion, just update info and get out */ + g_mouse_a2_x += (x - g_mouse_fifo[0].x); + g_mouse_a2_y += (y - g_mouse_fifo[0].y); + g_mouse_fifo[0].x = x; + g_mouse_fifo[0].y = y; + return 0; + } + +#if 0 + printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n", + g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo[0].x, + g_mouse_fifo[0].y, g_mouse_a2_x, g_mouse_a2_y); +#endif + + mouse_moved = (g_mouse_fifo[0].x != x) || (g_mouse_fifo[0].y != y); + + g_mouse_a2_x += g_mouse_warp_x; + g_mouse_a2_y += g_mouse_warp_y; + g_mouse_fifo[0].x = x; + g_mouse_fifo[0].y = y; + g_mouse_fifo[0].dcycs = dcycs; + g_mouse_warp_x = 0; + g_mouse_warp_y = 0; + + button1_changed = (buttons_valid & 1) && + ((button_states & 1) != (g_mouse_fifo[0].buttons & 1)); + + if((button_states & 4) && !(g_mouse_fifo[0].buttons & 4) && + (buttons_valid & 4)) { + /* right button pressed */ + adb_increment_speed(); + } + if((button_states & 2) && !(g_mouse_fifo[0].buttons & 2) && + (buttons_valid & 2)) { + /* middle button pressed */ + adb_increment_speed(); + //halt2_printf("Middle button pressed\n"); + } + + pos = g_mouse_fifo_pos; + if((pos < (ADB_MOUSE_FIFO - 2)) && button1_changed) { + /* copy delta to overflow, set overflow */ + /* overflow ensures the mouse button state is precise at */ + /* button up/down times. Using a mouse event list where */ + /* deltas accumulate until a button change would work, too */ + for(i = pos; i >= 0; i--) { + g_mouse_fifo[i + 1] = g_mouse_fifo[i]; /* copy struct*/ + } + g_mouse_fifo_pos = pos + 1; + } + + g_mouse_fifo[0].buttons = (button_states & buttons_valid) | + (g_mouse_fifo[0].buttons & ~buttons_valid); + + if(mouse_moved || button1_changed) { + if( (g_mouse_ctl_addr == g_mouse_dev_addr) && + ((g_adb_mode & 0x2) == 0)) { + g_adb_mouse_valid_data = 1; + adb_add_mouse_int(); + } + } + + return mouse_moved; +} + +int +mouse_read_c024(double dcycs) +{ + word32 ret; + word32 tool_start; + int em_active; + int target_x, target_y; + int delta_x, delta_y; + int a2_x, a2_y; + int mouse_button; + int clamped; + int pos; + + if(((g_adb_mode & 0x2) != 0) || (g_mouse_dev_addr != g_mouse_ctl_addr)){ + /* mouse is off, return 0, or mouse is not autopoll */ + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + return 0; + } + + mouse_compress_fifo(dcycs); + + pos = g_mouse_fifo_pos; + target_x = g_mouse_fifo[pos].x; + target_y = g_mouse_fifo[pos].y; + mouse_button = (g_mouse_fifo[pos].buttons & 1); + delta_x = target_x - g_mouse_a2_x; + delta_y = target_y - g_mouse_a2_y; + + clamped = 0; + if(delta_x > 0x3f) { + delta_x = 0x3f; + clamped = 1; + } else if(delta_x < -0x3f) { + delta_x = -0x3f; + clamped = 1; + } + if(delta_y > 0x3f) { + delta_y = 0x3f; + clamped = 1; + } else if(delta_y < -0x3f) { + delta_y = -0x3f; + clamped = 1; + } + + if(pos > 0) { + /* peek into next entry's button info if we are not clamped */ + /* and we're returning the y-coord */ + if(!clamped && g_adb_mouse_coord) { + mouse_button = g_mouse_fifo[pos - 1].buttons & 1; + } + } + + if(g_adb_mouse_coord) { + /* y coord */ + delta_x = 0; /* clear unneeded x delta */ + } else { + delta_y = 0; /* clear unneeded y delta */ + } + + + adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x100e9], g_slow_memory_ptr[0x100ea], + g_slow_memory_ptr[0x100eb], g_slow_memory_ptr[0x100ec]); + adb_printf(" pre a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], + g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); + + /* Update event manager internal state */ + tool_start = (g_slow_memory_ptr[0x103ca] << 16) + + (g_slow_memory_ptr[0x103c9] << 8) + + g_slow_memory_ptr[0x103c8]; + + em_active = 0; + if((tool_start >= 0x20000) && (tool_start < (g_mem_size_total - 28)) ) { + /* seems to be valid ptr to addr of mem space for tools */ + /* see if event manager appears to be active */ + em_active = g_memory_ptr[tool_start + 6*4] + + (g_memory_ptr[tool_start + 6*4 + 1] << 8); + if(g_warp_pointer) { + em_active = 0; + } + } + + a2_x = g_mouse_a2_x; + a2_y = g_mouse_a2_y; + + if(em_active) { + if((!g_hide_pointer) && (g_num_lines_prev_superhires == 200) && + !g_unhide_pointer) { + /* if super-hires and forcing tracking, then hide */ + g_hide_pointer = 1; + x_hide_pointer(1); + } + if(g_adb_mouse_coord == 0) { + /* update x coord values */ + g_slow_memory_ptr[0x47c] = a2_x & 0xff; + g_slow_memory_ptr[0x57c] = a2_x >> 8; + g_memory_ptr[0x47c] = a2_x & 0xff; + g_memory_ptr[0x57c] = a2_x >> 8; + + g_slow_memory_ptr[0x10190] = a2_x & 0xff; + g_slow_memory_ptr[0x10192] = a2_x >> 8; + } else { + g_slow_memory_ptr[0x4fc] = a2_y & 0xff; + g_slow_memory_ptr[0x5fc] = a2_y >> 8; + g_memory_ptr[0x4fc] = a2_y & 0xff; + g_memory_ptr[0x5fc] = a2_y >> 8; + + g_slow_memory_ptr[0x10191] = a2_y & 0xff; + g_slow_memory_ptr[0x10193] = a2_y >> 8; + } + } else { + if(g_hide_pointer && !g_warp_pointer) { + g_hide_pointer = 0; + x_hide_pointer(0); + } + } + + ret = ((!mouse_button) << 7) + ((delta_x | delta_y) & 0x7f); + if(g_adb_mouse_coord) { + g_mouse_a2_button = mouse_button; /* y coord has button*/ + } else { + ret |= 0x80; /* mouse button not down on x coord rd */ + } + + a2_x += delta_x; + a2_y += delta_y; + g_mouse_a2_x = a2_x; + g_mouse_a2_y = a2_y; + if(g_mouse_fifo_pos) { + if((target_x == a2_x) && (target_y == a2_y) && + (g_mouse_a2_button == mouse_button)) { + g_mouse_fifo_pos--; + } + } + + + adb_printf("Read c024, mouse is_y:%d, %02x, vbl:%08x, dcyc:%f, em:%d\n", + g_adb_mouse_coord, ret, g_vbl_count, dcycs, em_active); + adb_printf("...mouse targ_x:%d,%d delta_x,y:%d,%d fifo:%d, a2:%d,%d\n", + target_x, target_y, delta_x, delta_y, g_mouse_fifo_pos, + a2_x, a2_y); + adb_printf(" post a2_x:%02x,%02x,%02x,%02x\n", + g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], + g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); + + if((g_mouse_fifo_pos == 0) && (g_mouse_fifo[0].x == a2_x) && + (g_mouse_fifo[0].y == a2_y) && + ((g_mouse_fifo[0].buttons & 1) == g_mouse_a2_button)) { + g_adb_mouse_valid_data = 0; + adb_clear_mouse_int(); + } + + g_adb_mouse_coord = !g_adb_mouse_coord; + return ret; +} + +void +mouse_compress_fifo(double dcycs) +{ + int pos; + + /* The mouse fifo exists so that fast button changes don't get lost */ + /* if the emulator lags behind the mouse events */ + /* But the FIFO means really old mouse events are saved if */ + /* the emulated code isn't looking at the mouse registers */ + /* This routine compresses all mouse events > 0.5 seconds old */ + + for(pos = g_mouse_fifo_pos; pos >= 1; pos--) { + if(g_mouse_fifo[pos].dcycs < (dcycs - 500*1000.0)) { + /* Remove this entry */ + adb_printf("Old mouse FIFO pos %d removed\n", pos); + g_mouse_fifo_pos = pos - 1; + continue; + } + /* Else, stop searching the FIFO */ + break; + } +} + +void +adb_key_event(int a2code, int is_up) +{ + word32 special; + word32 vbl_count; + int key; + int hard_key; + int pos; + int tmp_ascii; + int ascii; + + if(is_up) { + adb_printf("adb_key_event, key:%02x, is up, g_key_down: %02x\n", + a2code, g_key_down); + } + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("add_key_event: a2code: %04x!\n", a2code); + return; + } + + if(!is_up && a2code == 0x35) { + /* ESC pressed, see if ctrl & cmd key down */ + if(CTRL_DOWN && CMD_DOWN) { + /* Desk mgr int */ + printf("Desk mgr int!\n"); + + g_adb_interrupt_byte |= 0x20; + adb_add_data_int(); + } + } + + /* convert key to ascii, if possible */ + hard_key = 0; + if(a2_key_to_ascii[a2code][1] & 0xef00) { + /* special key */ + } else { + /* we have ascii */ + hard_key = 1; + } + + pos = 1; + ascii = a2_key_to_ascii[a2code][1]; + if(CAPS_LOCK_DOWN && (ascii >= 'a' && ascii <= 'z')) { + pos = 2; + if(SHIFT_DOWN && (g_adb_mode & 0x40)) { + /* xor shift mode--capslock and shift == lowercase */ + pos = 1; + } + } else if(SHIFT_DOWN) { + pos = 2; + } + + ascii = a2_key_to_ascii[a2code][pos]; + if(CTRL_DOWN) { + tmp_ascii = a2_key_to_ascii[a2code][3]; + if(tmp_ascii >= 0) { + ascii = tmp_ascii; + } + } + key = (ascii & 0x7f) + 0x80; + + special = (ascii >> 8) & 0xff; + if(ascii < 0) { + printf("ascii1: %d, a2code: %02x, pos: %d\n", ascii,a2code,pos); + ascii = 0; + special = 0; + } + + + if(!is_up) { + if(hard_key) { + g_kbd_buf[g_kbd_chars_buffered] = key; + g_kbd_chars_buffered++; + if(g_kbd_chars_buffered >= MAX_KBD_BUF) { + g_kbd_chars_buffered = MAX_KBD_BUF - 1; + } + g_key_down = 1; + g_a2code_down = a2code; + + /* first key down, set up autorepeat */ + vbl_count = g_vbl_count; + if(g_config_control_panel) { + vbl_count = g_cfg_vbl_count; + } + g_adb_repeat_vbl = vbl_count + g_adb_repeat_delay; + if(g_adb_repeat_delay == 0) { + g_key_down = 0; + } + g_hard_key_down = 1; + } + + g_c025_val = g_c025_val | special; + adb_printf("new c025_or: %02x\n", g_c025_val); + } else { + if(hard_key && (a2code == g_a2code_down)) { + g_hard_key_down = 0; + /* Turn off repeat */ + g_key_down = 0; + } + + g_c025_val = g_c025_val & (~ special); + adb_printf("new c025_and: %02x\n", g_c025_val); + } + + if(g_key_down) { + g_c025_val = g_c025_val & (~0x20); + } else { + /* If no hard key down, set update mod latch */ + g_c025_val = g_c025_val | 0x20; + } + +} + +word32 +adb_read_c000() +{ + word32 vbl_count; + + if( ((g_kbd_buf[0] & 0x80) == 0) && (g_key_down == 0)) { + /* nothing happening, check clipboard */ + int c = clipboard_get_char(); + if(c) { + /* inject clipboard char into keyboard buffer */ + g_kbd_buf[0] = c; + } + /* just get out */ + return g_kbd_buf[0]; + } + if(g_kbd_buf[0] & 0x80) { + /* got one */ + if((g_kbd_read_no_update++ > 5) && (g_kbd_chars_buffered > 1)) { + /* read 5 times, keys pending, let's move it along */ + printf("Read %02x %d times, tossing\n", g_kbd_buf[0], + g_kbd_read_no_update); + adb_access_c010(); + } + } else { + vbl_count = g_vbl_count; + if(g_config_control_panel) { + vbl_count = g_cfg_vbl_count; + } + if(g_key_down && vbl_count >= g_adb_repeat_vbl) { + /* repeat the g_key_down */ + g_c025_val |= 0x8; + adb_key_event(g_a2code_down, 0); + g_adb_repeat_vbl = vbl_count + g_adb_repeat_rate; + } + } + + return g_kbd_buf[0]; +} + +word32 +adb_access_c010() +{ + int tmp; + int i; + + g_kbd_read_no_update = 0; + + tmp = g_kbd_buf[0] & 0x7f; + g_kbd_buf[0] = tmp; + + tmp = tmp | (g_hard_key_down << 7); + if(g_kbd_chars_buffered) { + for(i = 1; i < g_kbd_chars_buffered; i++) { + g_kbd_buf[i - 1] = g_kbd_buf[i]; + } + g_kbd_chars_buffered--; + } + + g_c025_val = g_c025_val & (~ (0x08)); + + return tmp; +} + +word32 +adb_read_c025() +{ + return g_c025_val; +} + +int +adb_is_cmd_key_down() +{ + return CMD_DOWN; +} + +int +adb_is_option_key_down() +{ + return OPTION_DOWN; +} + +void +adb_increment_speed() +{ + const char *str; + + g_limit_speed++; + if(g_limit_speed > 3) { + g_limit_speed = 0; + } + + str = ""; + switch(g_limit_speed) { + case 0: + str = "...as fast as possible!"; + break; + case 1: + str = "...1.024MHz!"; + break; + case 2: + str = "...2.8MHz!"; + break; + case 3: + str = "...8.0MHz!"; + break; + } + printf("Toggling g_limit_speed to %d%s\n", g_limit_speed, str); +} + +void +adb_physical_key_update(int a2code, int is_up) +{ + int autopoll; + int special; + int ascii_and_type; + int ascii; + + /* this routine called by xdriver to pass raw codes--handle */ + /* ucontroller and ADB bus protocol issues here */ + /* if autopoll on, pass it on through to c025,c000 regs */ + /* else only put it in kbd reg 3, and pull SRQ if needed */ + + adb_printf("adb_phys_key_update: %02x, %d\n", a2code, is_up); + + adb_printf("Handle a2code: %02x, is_up: %d\n", a2code, is_up); + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("a2code: %04x!\n", a2code); + return; + } + + /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards) */ + if(a2code >= 0x7b && a2code <= 0x7e) { + a2code = a2code - 0x40; + } + + /* Now check for special keys (function keys, etc) */ + ascii_and_type = a2_key_to_ascii[a2code][1]; + special = 0; + if((ascii_and_type & 0xf000) == 0x8000) { + /* special function key */ + special = ascii_and_type & 0xff; + switch(special) { + case 0x01: /* F1 - remap to cmd */ + a2code = 0x37; + special = 0; + break; + case 0x02: /* F2 - remap to option */ + a2code = 0x3a; + special = 0; + break; + case 0x03: /* F3 - remap to escape for OS/2 */ + a2code = 0x35; + special = 0; + break; + case 0x0c: /* F12 - remap to reset */ + a2code = 0x7f; + special = 0; + break; + default: + break; + } + } + + /* CUA clipboard paste - for those that remember ctrl-insert/shift-insert */ + if(is_up == 0 && a2code == 0x72 && SHIFT_DOWN) { + clipboard_paste(); + } + + /* Only process reset requests here */ + if(is_up == 0 && a2code == 0x7f && CTRL_DOWN) { + /* Reset pressed! */ + printf("Reset pressed since CTRL_DOWN: %d\n", CTRL_DOWN); + do_reset(); + return; + } + + if(special && !is_up) { + switch(special) { +// OG Disabled special keys (but warp) +#ifndef ACTIVEGS + case 0x04: /* F4 - emulator config panel */ + if (CMD_DOWN) + { + printf("Quit!\n"); + iwm_shut(); + my_exit(1); + } + else + { + cfg_toggle_config_panel(); + } + break; + case 0x05: /* F5 - emulator clipboard paste */ + clipboard_paste(); + break; + case 0x06: /* F6 - emulator speed */ + if(SHIFT_DOWN) { + halt2_printf("Shift-F6 pressed\n"); + } else { + adb_increment_speed(); + } + break; + case 0x07: /* F7 - fast disk emul */ + g_fast_disk_emul = !g_fast_disk_emul; + printf("g_fast_disk_emul is now %d\n", + g_fast_disk_emul); + break; +#endif + case 0x08: /* F8 - warp pointer */ + g_warp_pointer = !g_warp_pointer; + if(g_hide_pointer != g_warp_pointer) { + g_hide_pointer = g_warp_pointer; + x_hide_pointer(g_hide_pointer); + } + break; +#ifndef ACTIVEGS + case 0x09: /* F9 - swap paddles */ + if(SHIFT_DOWN) { + g_swap_paddles = !g_swap_paddles; + printf("Swap paddles is now: %d\n", + g_swap_paddles); + } else { + g_invert_paddles = !g_invert_paddles; + printf("Invert paddles is now: %d\n", + g_invert_paddles); + } + break; + case 0x0a: /* F10 - change a2vid paletter */ + if (SHIFT_DOWN) { +#ifdef TOGGLE_STATUS + extern void x_toggle_status_lines(); + x_toggle_status_lines(); +#endif + } else if (CMD_DOWN) { + do_reset(); + return; + } else { + change_a2vid_palette((g_a2vid_palette + 1) & 0xf); + } + break; + case 0x0b: /* F11 - full screen */ + g_fullscreen = !g_fullscreen; + x_full_screen(g_fullscreen); + break; +#endif + } + + return; + } + /* Handle Keypad Joystick here partly...if keypad key pressed */ + /* while in Keypad Joystick mode, do not pass it on as a key press */ + if((ascii_and_type & 0xff00) == 0x1000) { + /* Keep track of keypad number keys being up or down even */ + /* if joystick mode isn't keypad. This avoid funny cases */ + /* if joystick mode is changed while a key is pressed */ + ascii = ascii_and_type & 0xff; + if(ascii > 0x30 && ascii <= 0x39) { + g_keypad_key_is_down[ascii - 0x30] = !is_up; + } + if(g_joystick_type == JOYSTICK_TYPE_KEYPAD) { + /* If Joystick type is keypad, then do not let these */ + /* keypress pass on further, except for cmd/opt */ + if(ascii == 0x30) { + /* remap '0' to cmd */ + a2code = 0x37; + } else if(ascii == 0x2e || ascii == 0x2c) { + /* remap '.' and ',' to option */ + a2code = 0x3a; + } else { + /* Just ignore it in this mode */ + return; + } + } + } + + autopoll = 1; + if(g_adb_mode & 1) { + /* autopoll is explicitly off */ + autopoll = 0; + } + if(g_kbd_dev_addr != g_kbd_ctl_addr) { + /* autopoll is off because ucontroller doesn't know kbd moved */ + autopoll = 0; + } + if(g_config_control_panel) { + /* always do autopoll */ + autopoll = 1; + } + + + if(is_up) { + if(!autopoll) { + /* no auto keys, generate SRQ! */ + adb_kbd_reg0_data(a2code, is_up); + } else { + adb_virtual_key_update(a2code, is_up); + } + } else { + if(!autopoll) { + /* no auto keys, generate SRQ! */ + adb_kbd_reg0_data(a2code, is_up); + } else { + /* was up, now down */ + adb_virtual_key_update(a2code, is_up); + } + } +} + +void +adb_virtual_key_update(int a2code, int is_up) +{ + int i; + int bitpos; + word32 mask; + + adb_printf("Virtual handle a2code: %02x, is_up: %d\n", a2code, is_up); + + if(a2code < 0 || a2code > 0x7f) { + halt_printf("a2code: %04x!\n", a2code); + return; + } + + i = (a2code >> 5) & 3; + bitpos = a2code & 0x1f; + mask = (1 << bitpos); + + if(is_up) { + if(g_virtual_key_up[i] & mask) { + /* already up, do nothing */ + } else { + g_virtual_key_up[i] |= mask; + adb_key_event(a2code, is_up); + } + } else { + if(g_virtual_key_up[i] & mask) { + g_virtual_key_up[i] &= (~mask); + adb_key_event(a2code, is_up); + } + } +} + +void +adb_all_keys_up() +{ + word32 mask; + int i, j; + + for(i = 0; i < 4; i++) { + for(j = 0; j < 32; j++) { + mask = 1 << j; + if((g_virtual_key_up[i] & mask) == 0) { + /* create key-up event */ + adb_physical_key_update(i*32 + j, 1); + } + } + } +} + +void +adb_kbd_repeat_off() +{ + g_key_down = 0; +} diff --git a/src/adb.h b/src/adb.h index 8a5e94f..9f6fa56 100644 --- a/src/adb.h +++ b/src/adb.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/arch/os2/Makefile b/src/arch/os2/Makefile index de27c42..e661841 100644 --- a/src/arch/os2/Makefile +++ b/src/arch/os2/Makefile @@ -1,76 +1,76 @@ -# GSport OS/2 makefile - -TARGET = gsport.exe - -OBJECTS1 = dirport.obj adb.obj clock.obj dis.obj engine_c.obj scc.obj \ - iwm.obj joystick_driver.obj moremem.obj paddles.obj \ - sim65816.obj smartport.obj sound.obj \ - video.obj config.obj scc_socket_os2.obj os2driver.obj os2snd_driver.obj - -{..\..}.c.obj: - @echo " Compile::C++ Compiler " - icc.exe /DTCPV40HDRS /DBSD_SELECT /Dinline= /I..\.. /Ss /Q /Ti /Gm /G4 /Ft- /C %s - -{src\}.c.obj: - @echo " Compile::C++ Compiler " - icc.exe /DTCPV40HDRS /DBSD_SELECT /Dinline= /I..\.. /Ss /Q /Ti /Gm /G4 /Ft- /C %s - -.c.obj: - @echo " Compile::C++ Compiler " - icc.exe /DTCPV40HDRS /DBSD_SELECT /Dinline= /I..\.. /Ss /Q /Ti /Gm /G4 /Ft- /C %s - -$(TARGET): $(OBJECTS1) - @echo " Link::Linker " - icc.exe @<< - /B" /de /pmtype:pm /st:196608 " - /Fe$(TARGET) - so32dll.lib - tcp32dll.lib - $(OBJECTS1) -<< - rc gsportos2.rc $(TARGET) - echo done - -clean: - - rm $(OBJECTS1) - - rm $(TARGET) - - rm gsportos2.res - - rm ../../size_s.h - - rm ../../size_c.h - - rm ../../8size_s.h - - rm ../../16size_s.h - - rm ../../8inst_s.h - - rm ../../8inst_c.h - - rm ../../16inst_s.h - - rm ../../16inst_c.h - -../../size_c.h: - call make_size.cmd - -../../8inst_c.h: - call make_inst.cmd - -# dependency stuff -dirport.obj: src/dirport.c src/dirport.h -adb.obj: ../../adb.c ../../adb.h ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -engine_c.obj: ../../engine_c.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../protos_engine_c.h ../../size_c.h ../../op_routs.h ../../defs_instr.h ../../8inst_c.h ../../16inst_c.h -clock.obj: ..\..\clock.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -compile_time.obj: ../../compile_time.c -config.obj: ../../config.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../config.h -dis.obj: ../../dis.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../disas.h -scc.obj: ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../scc.h -scc_socket_driver.obj: ../../scc_socket_driver.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../scc.h -scc_socket_os2.obj: scc_socket_os2.c -iwm.obj: ../../iwm.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../iwm_35_525.h -joystick_driver.obj: ../../joystick_driver.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -moremem.obj: ../../moremem.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -paddles.obj: ../../paddles.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -parallel.obj: ../../parallel.c ../../defc.h -printer.obj: ../../printer.cpp -sim65816.obj: ../../sim65816.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -smartport.obj: ../../smartport.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -sound.obj: ../../sound.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -sound_driver.obj: ../../sound_driver.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../sound.h -video.obj: ../../video.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../superhires.h ../../gsportfont.h -os2driver.obj: os2driver.c gsportos2.h ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h -os2snd_driver.obj: os2snd_driver.c +# GSport OS/2 makefile + +TARGET = gsport.exe + +OBJECTS1 = dirport.obj adb.obj clock.obj dis.obj engine_c.obj scc.obj \ + iwm.obj joystick_driver.obj moremem.obj paddles.obj \ + sim65816.obj smartport.obj sound.obj \ + video.obj config.obj scc_socket_os2.obj os2driver.obj os2snd_driver.obj + +{..\..}.c.obj: + @echo " Compile::C++ Compiler " + icc.exe /DTCPV40HDRS /DBSD_SELECT /Dinline= /I..\.. /Ss /Q /Ti /Gm /G4 /Ft- /C %s + +{src\}.c.obj: + @echo " Compile::C++ Compiler " + icc.exe /DTCPV40HDRS /DBSD_SELECT /Dinline= /I..\.. /Ss /Q /Ti /Gm /G4 /Ft- /C %s + +.c.obj: + @echo " Compile::C++ Compiler " + icc.exe /DTCPV40HDRS /DBSD_SELECT /Dinline= /I..\.. /Ss /Q /Ti /Gm /G4 /Ft- /C %s + +$(TARGET): $(OBJECTS1) + @echo " Link::Linker " + icc.exe @<< + /B" /de /pmtype:pm /st:196608 " + /Fe$(TARGET) + so32dll.lib + tcp32dll.lib + $(OBJECTS1) +<< + rc gsportos2.rc $(TARGET) + echo done + +clean: + - rm $(OBJECTS1) + - rm $(TARGET) + - rm gsportos2.res + - rm ../../size_s.h + - rm ../../size_c.h + - rm ../../8size_s.h + - rm ../../16size_s.h + - rm ../../8inst_s.h + - rm ../../8inst_c.h + - rm ../../16inst_s.h + - rm ../../16inst_c.h + +../../size_c.h: + call make_size.cmd + +../../8inst_c.h: + call make_inst.cmd + +# dependency stuff +dirport.obj: src/dirport.c src/dirport.h +adb.obj: ../../adb.c ../../adb.h ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +engine_c.obj: ../../engine_c.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../protos_engine_c.h ../../size_c.h ../../op_routs.h ../../defs_instr.h ../../8inst_c.h ../../16inst_c.h +clock.obj: ..\..\clock.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +compile_time.obj: ../../compile_time.c +config.obj: ../../config.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../config.h +dis.obj: ../../dis.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../disas.h +scc.obj: ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../scc.h +scc_socket_driver.obj: ../../scc_socket_driver.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../scc.h +scc_socket_os2.obj: scc_socket_os2.c +iwm.obj: ../../iwm.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../iwm_35_525.h +joystick_driver.obj: ../../joystick_driver.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +moremem.obj: ../../moremem.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +paddles.obj: ../../paddles.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +parallel.obj: ../../parallel.c ../../defc.h +printer.obj: ../../printer.cpp +sim65816.obj: ../../sim65816.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +smartport.obj: ../../smartport.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +sound.obj: ../../sound.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +sound_driver.obj: ../../sound_driver.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../sound.h +video.obj: ../../video.c ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h ../../superhires.h ../../gsportfont.h +os2driver.obj: os2driver.c gsportos2.h ../../scc.c ../../defc.h ../../defcomm.h ../../iwm.h ../../protos.h +os2snd_driver.obj: os2snd_driver.c diff --git a/src/arch/os2/gsportos2.h b/src/arch/os2/gsportos2.h index 227ac0b..459abee 100644 --- a/src/arch/os2/gsportos2.h +++ b/src/arch/os2/gsportos2.h @@ -1,44 +1,46 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * Function prototypes - */ -MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ); -VOID os2_abort(HWND hwndFrame, HWND hwndClient); - -#define MSGBOXID 1001 - -#define ID_WINDOW 256 - -#define ID_OPTIONS 257 -#define ID_OPTION1 258 -#define ID_OPTION2 259 -#define ID_OPTION3 260 - -#define ID_EXITPROG 261 - -#define IDS_HELLO 262 -#define IDS_1 263 -#define IDS_2 264 -#define IDS_3 265 - -#define ID_BITMAP 266 /* For testing backgrounds - can be removed once video works */ +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Function prototypes + */ +MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ); +VOID os2_abort(HWND hwndFrame, HWND hwndClient); + +#define MSGBOXID 1001 + +#define ID_WINDOW 256 + +#define ID_OPTIONS 257 +#define ID_OPTION1 258 +#define ID_OPTION2 259 +#define ID_OPTION3 260 + +#define ID_EXITPROG 261 + +#define IDS_HELLO 262 +#define IDS_1 263 +#define IDS_2 264 +#define IDS_3 265 + +#define ID_BITMAP 266 /* For testing backgrounds - can be removed once video works */ diff --git a/src/arch/os2/gsportos2.rc b/src/arch/os2/gsportos2.rc index 2e097b0..d9819b0 100644 --- a/src/arch/os2/gsportos2.rc +++ b/src/arch/os2/gsportos2.rc @@ -1,48 +1,49 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include "gsportos2.h" - -ICON ID_WINDOW gsportos2.ico - -BITMAP ID_BITMAP gsportos2.bmp - -MENU ID_WINDOW PRELOAD -BEGIN - SUBMENU "~Options", ID_OPTIONS - BEGIN - MENUITEM "Option ~1\tCtrl+A", ID_OPTION1, MIS_TEXT - MENUITEM "Option ~2\tCtrl+B", ID_OPTION2, MIS_TEXT - MENUITEM "Option ~3\tCtrl+C", ID_OPTION3, MIS_TEXT - END -END - -ACCELTABLE ID_WINDOW PRELOAD -BEGIN - VK_F3, ID_EXITPROG, VIRTUALKEY -END - -STRINGTABLE PRELOAD -BEGIN - IDS_HELLO, "Hello" -END - \ No newline at end of file +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "gsportos2.h" + +ICON ID_WINDOW gsportos2.ico + +BITMAP ID_BITMAP gsportos2.bmp + +MENU ID_WINDOW PRELOAD +BEGIN + SUBMENU "~Options", ID_OPTIONS + BEGIN + MENUITEM "Option ~1\tCtrl+A", ID_OPTION1, MIS_TEXT + MENUITEM "Option ~2\tCtrl+B", ID_OPTION2, MIS_TEXT + MENUITEM "Option ~3\tCtrl+C", ID_OPTION3, MIS_TEXT + END +END + +ACCELTABLE ID_WINDOW PRELOAD +BEGIN + VK_F3, ID_EXITPROG, VIRTUALKEY +END + +STRINGTABLE PRELOAD +BEGIN + IDS_HELLO, "Hello" +END diff --git a/src/arch/os2/make_inst.cmd b/src/arch/os2/make_inst.cmd index 0b10e54..6c592c8 100644 --- a/src/arch/os2/make_inst.cmd +++ b/src/arch/os2/make_inst.cmd @@ -1,76 +1,76 @@ -/* - -make_inst.cmd: - -Translation of the make_inst perl script and makefile to rexx for OS/2 - -8inst_s.h: instable.h - $(PERL) make_inst s 8 instable.h > 8inst_s.h - -16inst_s.h: instable.h - $(PERL) make_inst s 16 instable.h > 16inst_s.h - -8inst_c.h: instable.h - $(PERL) make_inst c 8 instable.h > 8inst_c.h - -16inst_c.h: instable.h - $(PERL) make_inst c 16 instable.h > 16inst_c.h - -*/ - -count = 0; - -FileNameIn = "..\..\instable.h" -FileNameOut8s = "..\..\8inst_s.h" -FileNameOut8c = "..\..\8inst_c.h" -FileNameOut16s = "..\..\16inst_s.h" -FileNameOut16c = "..\..\16inst_c.h" - -DEL FileNameOut8s -DEL FileNameOut8c -DEL FileNameOut16s -DEL FileNameOut16c -crud = STREAM(FileNameIn,"C","open read") -crud = STREAM(FileNameOut8s,"C","open write") -crud = STREAM(FileNameOut8c,"C","open write") -crud = STREAM(FileNameOut16s,"C","open write") -crud = STREAM(FileNameOut16c,"C","open write") - -Do while (STREAM(FileNameIn,"S") = "READY") - line = LINEIN(FileNameIn); - - SymPos = POS("_SYM",line) - if (SymPos > 0) Then - Do - if POS("inst",line) > 0 Then - Do - if (count > 0) Then - Do - crud = LINEOUT(FileNameOut8c," break;"); - crud = LINEOUT(FileNameOut16c," break;"); - End - newline = "case 0x"SUBSTR(line,SymPos-2,2)": "SUBSTR(line,SymPos+4) - crud = LINEOUT(FileNameOut8c, newline); - crud = LINEOUT(FileNameOut16c, newline); - count = count + 1; - End - Else - Do - crud = LINEOUT(FileNameOut8s,SUBSTR(line,1,SymPos)" . "8" . "SUBSTR(line,SymPos+4)); - crud = LINEOUT(FileNameOut16s,SUBSTR(line,1,SymPos)" . "16" . "SUBSTR(line,SymPos+4)); - End - End - Else - Do - crud = LINEOUT(FileNameOut8c,line); - crud = LINEOUT(FileNameOut8s,line); - crud = LINEOUT(FileNameOut16c,line); - crud = LINEOUT(FileNameOut16s,line); - End -End -say "Lines read: "Count -crud = STREAM(FileNameIn,"C","close") -crud = STREAM(FileNameOut8s,"C","close") -crud = STREAM(FileNameOut8c,"C","close") -crud = STREAM(FileNameOut16s,"C","close") -crud = STREAM(FileNameOut16c,"C","close") +/* + +make_inst.cmd: + +Translation of the make_inst perl script and makefile to rexx for OS/2 + +8inst_s.h: instable.h + $(PERL) make_inst s 8 instable.h > 8inst_s.h + +16inst_s.h: instable.h + $(PERL) make_inst s 16 instable.h > 16inst_s.h + +8inst_c.h: instable.h + $(PERL) make_inst c 8 instable.h > 8inst_c.h + +16inst_c.h: instable.h + $(PERL) make_inst c 16 instable.h > 16inst_c.h + +*/ + +count = 0; + +FileNameIn = "..\..\instable.h" +FileNameOut8s = "..\..\8inst_s.h" +FileNameOut8c = "..\..\8inst_c.h" +FileNameOut16s = "..\..\16inst_s.h" +FileNameOut16c = "..\..\16inst_c.h" + +DEL FileNameOut8s +DEL FileNameOut8c +DEL FileNameOut16s +DEL FileNameOut16c +crud = STREAM(FileNameIn,"C","open read") +crud = STREAM(FileNameOut8s,"C","open write") +crud = STREAM(FileNameOut8c,"C","open write") +crud = STREAM(FileNameOut16s,"C","open write") +crud = STREAM(FileNameOut16c,"C","open write") + +Do while (STREAM(FileNameIn,"S") = "READY") + line = LINEIN(FileNameIn); + + SymPos = POS("_SYM",line) + if (SymPos > 0) Then + Do + if POS("inst",line) > 0 Then + Do + if (count > 0) Then + Do + crud = LINEOUT(FileNameOut8c," break;"); + crud = LINEOUT(FileNameOut16c," break;"); + End + newline = "case 0x"SUBSTR(line,SymPos-2,2)": "SUBSTR(line,SymPos+4) + crud = LINEOUT(FileNameOut8c, newline); + crud = LINEOUT(FileNameOut16c, newline); + count = count + 1; + End + Else + Do + crud = LINEOUT(FileNameOut8s,SUBSTR(line,1,SymPos)" . "8" . "SUBSTR(line,SymPos+4)); + crud = LINEOUT(FileNameOut16s,SUBSTR(line,1,SymPos)" . "16" . "SUBSTR(line,SymPos+4)); + End + End + Else + Do + crud = LINEOUT(FileNameOut8c,line); + crud = LINEOUT(FileNameOut8s,line); + crud = LINEOUT(FileNameOut16c,line); + crud = LINEOUT(FileNameOut16s,line); + End +End +say "Lines read: "Count +crud = STREAM(FileNameIn,"C","close") +crud = STREAM(FileNameOut8s,"C","close") +crud = STREAM(FileNameOut8c,"C","close") +crud = STREAM(FileNameOut16s,"C","close") +crud = STREAM(FileNameOut16c,"C","close") diff --git a/src/arch/os2/make_size.cmd b/src/arch/os2/make_size.cmd index 532739c..aa6176a 100644 --- a/src/arch/os2/make_size.cmd +++ b/src/arch/os2/make_size.cmd @@ -1,71 +1,71 @@ -/* - -make_inst.cmd: - -Translation of the make_size perl script and makefile to rexx for OS/2 - -size_c.h: size_tab.h - $(PERL) make_size c size_tab.h > size_c.h - -size_s.h: size_tab.h - $(PERL) make_size s size_tab.h > size_s.h - -8size_s.h: size_tab.h - $(PERL) make_size 8 size_tab.h > 8size_s.h - -16size_s.h: size_tab.h - $(PERL) make_size 16 size_tab.h > 16size_s.h - -*/ - -FileNameIn = "..\..\size_tab.h" -FileNameOuts = "..\..\size_s.h" -FileNameOutc = "..\..\size_c.h" -FileNameOut8 = "..\..\8size_s.h" -FileNameOut16 = "..\..\16size_s.h" - -DEL FileNameOuts -DEL FileNameOutc -DEL FileNameOut8 -DEL FileNameOut16 -crud = STREAM(FileNameIn,"C","open read") -crud = STREAM(FileNameOuts,"C","open write") -crud = STREAM(FileNameOutc,"C","open write") -crud = STREAM(FileNameOut8,"C","open write") -crud = STREAM(FileNameOut16,"C","open write") - -Do while (STREAM(FileNameIn,"S") = "READY") - line = LINEIN(FileNameIn); - - SymPos = POS("_SYM",line) - if (SymPos > 0) Then - Do - newline = " .byte 0x"SUBSTR(line,SymPos+5,1)", /* "SUBSTR(line,SymPos-2,2)" */ "SUBSTR(line,SymPos+6) - crud = LINEOUT(FileNameOuts, newline); - newline = " 0x"SUBSTR(line,SymPos+5,1)", /* "SUBSTR(line,SymPos-2,2)" */ "SUBSTR(line,SymPos+6) - crud = LINEOUT(FileNameOutc, newline); - newline = " .word inst"SUBSTR(line,SymPos-2,2)" . 8 . /*"SUBSTR(line,SymPos+5,1)"*/ "SUBSTR(line,SymPos+6) - crud = LINEOUT(FileNameOut8, newline); - newline = " .word inst"SUBSTR(line,SymPos-2,2)" . 16 . /*"SUBSTR(line,SymPos+5,1)"*/ "SUBSTR(line,SymPos+6) - crud = LINEOUT(FileNameOut16, newline); - End - Else if (POS(".block",line) > 0) Then - Do - crud = LINEOUT(FileNameOuts, ""); - crud = LINEOUT(FileNameOutc, ""); - crud = LINEOUT(FileNameOut8, line); - crud = LINEOUT(FileNameOut16, line); - End - Else - Do - crud = LINEOUT(FileNameOuts, line); - crud = LINEOUT(FileNameOutc, line); - crud = LINEOUT(FileNameOut8, line); - crud = LINEOUT(FileNameOut16, line); - End -End -crud = STREAM(FileNameIn,"C","close") -crud = STREAM(FileNameOuts,"C","close") -crud = STREAM(FileNameOutc,"C","close") -crud = STREAM(FileNameOut8,"C","close") -crud = STREAM(FileNameOut16,"C","close") +/* + +make_inst.cmd: + +Translation of the make_size perl script and makefile to rexx for OS/2 + +size_c.h: size_tab.h + $(PERL) make_size c size_tab.h > size_c.h + +size_s.h: size_tab.h + $(PERL) make_size s size_tab.h > size_s.h + +8size_s.h: size_tab.h + $(PERL) make_size 8 size_tab.h > 8size_s.h + +16size_s.h: size_tab.h + $(PERL) make_size 16 size_tab.h > 16size_s.h + +*/ + +FileNameIn = "..\..\size_tab.h" +FileNameOuts = "..\..\size_s.h" +FileNameOutc = "..\..\size_c.h" +FileNameOut8 = "..\..\8size_s.h" +FileNameOut16 = "..\..\16size_s.h" + +DEL FileNameOuts +DEL FileNameOutc +DEL FileNameOut8 +DEL FileNameOut16 +crud = STREAM(FileNameIn,"C","open read") +crud = STREAM(FileNameOuts,"C","open write") +crud = STREAM(FileNameOutc,"C","open write") +crud = STREAM(FileNameOut8,"C","open write") +crud = STREAM(FileNameOut16,"C","open write") + +Do while (STREAM(FileNameIn,"S") = "READY") + line = LINEIN(FileNameIn); + + SymPos = POS("_SYM",line) + if (SymPos > 0) Then + Do + newline = " .byte 0x"SUBSTR(line,SymPos+5,1)", /* "SUBSTR(line,SymPos-2,2)" */ "SUBSTR(line,SymPos+6) + crud = LINEOUT(FileNameOuts, newline); + newline = " 0x"SUBSTR(line,SymPos+5,1)", /* "SUBSTR(line,SymPos-2,2)" */ "SUBSTR(line,SymPos+6) + crud = LINEOUT(FileNameOutc, newline); + newline = " .word inst"SUBSTR(line,SymPos-2,2)" . 8 . /*"SUBSTR(line,SymPos+5,1)"*/ "SUBSTR(line,SymPos+6) + crud = LINEOUT(FileNameOut8, newline); + newline = " .word inst"SUBSTR(line,SymPos-2,2)" . 16 . /*"SUBSTR(line,SymPos+5,1)"*/ "SUBSTR(line,SymPos+6) + crud = LINEOUT(FileNameOut16, newline); + End + Else if (POS(".block",line) > 0) Then + Do + crud = LINEOUT(FileNameOuts, ""); + crud = LINEOUT(FileNameOutc, ""); + crud = LINEOUT(FileNameOut8, line); + crud = LINEOUT(FileNameOut16, line); + End + Else + Do + crud = LINEOUT(FileNameOuts, line); + crud = LINEOUT(FileNameOutc, line); + crud = LINEOUT(FileNameOut8, line); + crud = LINEOUT(FileNameOut16, line); + End +End +crud = STREAM(FileNameIn,"C","close") +crud = STREAM(FileNameOuts,"C","close") +crud = STREAM(FileNameOutc,"C","close") +crud = STREAM(FileNameOut8,"C","close") +crud = STREAM(FileNameOut16,"C","close") diff --git a/src/arch/os2/os2driver.c b/src/arch/os2/os2driver.c index 419fda8..1fcedd7 100644 --- a/src/arch/os2/os2driver.c +++ b/src/arch/os2/os2driver.c @@ -1,542 +1,543 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "../../defc.h" -#include "../../protos.h" - -#define INCL_WIN -#define INCL_GPI - -#include /* PM header file */ -#include -#include "gsportos2.h" /* Resource symbolic identifiers*/ - -HAB g_hab; /* PM anchor block handle */ -PSZ pszErrMsg; -QMSG qmsg; /* Message from message queue */ -HWND g_hwnd_frame = NULLHANDLE; /* Frame window handle */ -HWND g_hwnd_client = NULLHANDLE; /* Client area window handle */ - -HMQ g_hmq; /* Message queue handle */ - -extern int Verbose; - -extern int g_warp_pointer; -extern int g_screen_depth; -extern int g_force_depth; -int g_screen_mdepth = 0; - -extern int g_quit_sim_now; - -int g_use_shmem = 1; -int g_has_focus = 0; -int g_auto_repeat_on = -1; - -extern Kimage g_mainwin_kimage; - -int g_main_height = 0; - -int g_win_capslock_down = 0; - -extern int g_border_sides_refresh_needed; -extern int g_border_special_refresh_needed; -extern int g_status_refresh_needed; -extern int g_needfullrefreshfornextframe; -extern int g_lores_colors[]; -extern int g_cur_a2_stat; - -extern int g_a2vid_palette; - -extern int g_installed_full_superhires_colormap; - -extern int g_screen_redraw_skip_amt; - -extern word32 g_a2_screen_buffer_changed; - -BITMAPINFO2 *g_bmapinfo_ptr = 0; -volatile BITMAPINFOHEADER2 *g_bmaphdr_ptr = 0; -HDC g_hdc_screen, g_hdc_memory; -HPS g_hps_screen, g_hps_memory; - -extern word32 g_palette_8to1624[256]; -extern word32 g_a2palette_8to1624[256]; -extern char *g_status_ptrs[MAX_STATUS_LINES]; - -VOID DispErrorMessage(); - -int -win_nonblock_read_stdin(int fd, char *bufptr, int len) -{ - return 0; -} - -void -x_dialog_create_gsport_conf(const char *str) -{ -} - -int -x_show_alert(int is_fatal, const char *str) -{ - return 0; -} - - - -int -main(int argc, char **argv) -{ -DEVOPENSTRUC pszData; -ULONG flCreate; /* Window creation control flags*/ -int height; -SIZEL sizel; - - if ((g_hab = WinInitialize(0)) == 0L) /* Initialize PM */ - os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ - - if ((g_hmq = WinCreateMsgQueue( g_hab, 0 )) == 0L)/* Create a msg queue */ - os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ - - if (!WinRegisterClass( /* Register window class */ - g_hab, /* Anchor block handle */ - (PSZ)"MyWindow", /* Window class name */ - (PFNWP)MyWindowProc, /* Address of window procedure */ - CS_SIZEREDRAW, /* Class style */ - 0 /* No extra window words */ - )) - os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ - - height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES*16); - g_main_height = height; - - flCreate = FCF_STANDARD & /* Set frame control flags to */ - ~FCF_SHELLPOSITION; /* standard except for shell */ - /* positioning. */ - - if ((g_hwnd_frame = WinCreateStdWindow( - HWND_DESKTOP, /* Desktop window is parent */ - 0, /* STD. window styles */ - &flCreate, /* Frame control flag */ - "MyWindow", /* Client window class name */ - "", /* No window text */ - 0, /* No special class style */ - (HMODULE)0L, /* Resource is in .EXE file */ - ID_WINDOW, /* Frame window identifier */ - &g_hwnd_client /* Client window handle */ - )) == 0L) - os2_abort(HWND_DESKTOP, HWND_DESKTOP); /* Terminate the application */ - - WinSetWindowText(g_hwnd_frame, "GSport"); - - if (!WinSetWindowPos( g_hwnd_frame, /* Shows and activates frame */ - HWND_TOP, /* window at position 100, 100, */ - 100, 100, X_A2_WINDOW_WIDTH, height, /* and size 200, 200. */ - SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW - )) - os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ - - g_hdc_screen = WinOpenWindowDC(g_hwnd_client); - sizel.cx = X_A2_WINDOW_WIDTH; - sizel.cy = height; - g_hps_screen = GpiCreatePS(g_hab,g_hdc_screen, &sizel, PU_PELS | GPIF_LONG | GPIA_ASSOC); - - g_hdc_memory = DevOpenDC(g_hab, OD_MEMORY, "*", 4, (PDEVOPENDATA)&pszData, NULL); - g_hps_memory = GpiCreatePS(g_hab,g_hdc_memory, &sizel, PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC); - - // Call gsportmain - return gsportmain(argc, argv); - -} - - -/************************************************************************** - * - * Name : MyWindowProc - * - * Description: The window procedure associated with the client area in - * the standard frame window. It processes all messages - * either sent or posted to the client area, depending on - * the message command and parameters. - * - *************************************************************************/ -MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) -{ -HPS hps; -RECTL rcl; - - switch( msg ) - { - case WM_CREATE: - /* - * Window initialization is performed here in WM_CREATE processing - * WinLoadString loads strings from the resource file. - */ - break; - - case WM_COMMAND: - /* - * When the user chooses option 1, 2, or 3 from the Options pull- - * down, the text string is set to 1, 2, or 3, and - * WinInvalidateRegion sends a WM_PAINT message. - * When Exit is chosen, the application posts itself a WM_CLOSE - * message. - */ - { - USHORT command; /* WM_COMMAND command value */ - command = SHORT1FROMMP(mp1); /* Extract the command value */ - switch (command) - { - case ID_EXITPROG: - WinPostMsg( hwnd, WM_CLOSE, (MPARAM)0, (MPARAM)0 ); - break; - default: - return WinDefWindowProc( hwnd, msg, mp1, mp2 ); - } - - break; - } - case WM_ERASEBACKGROUND: - /* - * Return TRUE to request PM to paint the window background - * in SYSCLR_WINDOW. - */ - return (MRESULT)( TRUE ); - case WM_PAINT: - /* - * Window contents are drawn here in WM_PAINT processing. - */ - hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl); - WinEndPaint(hps); - g_needfullrefreshfornextframe = 1; - break; - case WM_CLOSE: - /* - * This is the place to put your termination routines - */ - WinPostMsg( hwnd, WM_QUIT, (MPARAM)0,(MPARAM)0 ); /* Cause termination*/ - exit(0); - break; - default: - /* - * Everything else comes here. This call MUST exist - * in your window procedure. - */ - - return WinDefWindowProc( hwnd, msg, mp1, mp2 ); - } - - return (MRESULT)FALSE; -} /* End of MyWindowProc */ - -void -check_input_events() -{ - -/* - * Get and dispatch messages from the application message queue - * until WinGetMsg returns FALSE, indicating a WM_QUIT message. - */ - - while(WinPeekMsg(g_hab, &qmsg, g_hwnd_frame, 0, 0, PM_NOREMOVE)) { - if(WinGetMsg(g_hab, &qmsg, 0L, 0, 0) > 0) { - //TranslateMessage(&qmsg); - WinDispatchMsg(g_hab, &qmsg); - } else { - printf("GetMessage returned <= 0\n"); - my_exit(2); - } - } -} - - -void -x_update_color(int col_num, int red, int green, int blue, word32 rgb) -{ -} - -void -x_update_physical_colormap() -{ -} - -void -show_xcolor_array() -{ -} - - -void -xdriver_end() -{ - printf("OS/2 driver_end\n"); -} - - -void -x_get_kimage(Kimage *kimage_ptr) -{ - byte *ptr; - int width; - int height; - int depth, mdepth; - int size; - - width = kimage_ptr->width_req; - height = kimage_ptr->height; - depth = kimage_ptr->depth; - mdepth = kimage_ptr->mdepth; - - size = 0; - - if(depth == g_screen_depth) { - /* Use g_bmapinfo_ptr, adjusting width, height */ - g_bmaphdr_ptr->cx = width; - g_bmaphdr_ptr->cy = height; - - kimage_ptr->dev_handle = GpiCreateBitmap( - - (HPS)g_hps_memory, (PBITMAPINFOHEADER2)g_bmaphdr_ptr, - 0L, (PBYTE)kimage_ptr->data_ptr, - (PBITMAPINFO2)g_bmapinfo_ptr); - - size = (width*height*mdepth) >> 3; - ptr = (byte *)malloc(size); - - if(ptr == 0) { - printf("malloc for data failed, mdepth: %d\n", mdepth); - exit(2); - } - - kimage_ptr->data_ptr = ptr; - - } else { - /* allocate buffers for video.c to draw into */ - - size = (width*height*mdepth) >> 3; - ptr = (byte *)malloc(size); - - if(ptr == 0) { - printf("malloc for data failed, mdepth: %d\n", mdepth); - exit(2); - } - - kimage_ptr->data_ptr = ptr; - - kimage_ptr->dev_handle = (void *)-1; - - } - - return; -} - - -void -dev_video_init() -{ - int lores_col; - int i; - - printf("Preparing graphics system\n"); - - g_screen_depth = 24; - g_screen_mdepth = 32; - - g_bmapinfo_ptr = (BITMAPINFO2 *)malloc(sizeof(BITMAPINFOHEADER2)); - g_bmaphdr_ptr = (BITMAPINFOHEADER2 *)g_bmapinfo_ptr; - g_bmaphdr_ptr->cbFix = sizeof(BITMAPINFOHEADER2); - g_bmaphdr_ptr->cx = A2_WINDOW_WIDTH; - g_bmaphdr_ptr->cy = A2_WINDOW_HEIGHT; - g_bmaphdr_ptr->cPlanes = 1; - g_bmaphdr_ptr->cBitCount = g_screen_mdepth; - g_bmaphdr_ptr->ulCompression = BCA_UNCOMP; - g_bmaphdr_ptr->cclrUsed = 0; - - video_get_kimages(); - - if(g_screen_depth != 8) { - // Allocate g_mainwin_kimage - video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, - g_screen_mdepth); - } - - for(i = 0; i < 256; i++) { - lores_col = g_lores_colors[i & 0xf]; - video_update_color_raw(i, lores_col); - g_a2palette_8to1624[i] = g_palette_8to1624[i]; - } - - g_installed_full_superhires_colormap = 1; - - printf("Done with dev_video_init\n"); - fflush(stdout); -} - -void -x_redraw_status_lines() -{ - - int line,len,height; - POINTL pt; - char *buf; - - printf("x_redraw_status_lines() called\n"); -/* - if (g_status_ptrs[0] != NULL) - { - height = 16; - pt.x = 5; pt.y = 0; - GpiSetColor( g_hps_screen, CLR_NEUTRAL ); - GpiSetBackColor( g_hps_screen, CLR_BACKGROUND ); - GpiSetBackMix( g_hps_screen, BM_OVERPAINT ); - - for (line = 0; line < MAX_STATUS_LINES; line++) - { - buf = g_status_ptrs[line]; - if (buf != 0) - { - pt.y = height * (line+1); - len = strlen(buf); - GpiCharStringAt( g_hps_screen, &pt, (LONG)strlen( buf ), buf ); - } - } - } -*/ -} - - -void -x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, - int width, int height) -{ - RECTL rc; - POINTL pt[4]; - HBITMAP hbmOld, hbmNew; - - char *szString = "Hello, world!\0"; - - printf("x_push_kimage() called: Src: (%d,%d) Dest: (%d,%d) Width: %d Height: %d\n",srcx,srcy,destx,desty,width,height); - pt[0].x = destx; /* Target X1 */ - pt[0].y = desty+(MAX_STATUS_LINES*16); /* Target Y1 */ - pt[1].x = destx+width; /* Target X2 */ - pt[1].y = desty+height+(MAX_STATUS_LINES*16); /* Target Y2: Translate up, make room for status border */ - pt[2].x = srcx; /* Source X */ - pt[2].y = srcy; /* Source Y */ - pt[3].x = srcx+width; - pt[3].y = srcy+height; - -if (width == 560) -{ - /* Paint a known-good bitmap until we can figure out why images aren't showing up */ - hbmNew = GpiLoadBitmap(g_hps_memory,NULLHANDLE,ID_BITMAP,560,400); - hbmOld = GpiSetBitmap(g_hps_memory, hbmNew); - GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE); - GpiSetBitmap(g_hps_memory, hbmOld); - GpiDeleteBitmap(hbmNew); -} -else -{ - hbmOld = GpiSetBitmap(g_hps_memory, (HBITMAP)kimage_ptr->dev_handle); - GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE); - GpiSetBitmap(g_hps_memory, hbmOld); -} - -} - -// OG Adding release -void x_release_kimage(Kimage* kimage_ptr) -{ - if (kimage_ptr->dev_handle == (void*)-1) - { - free(kimage_ptr->data_ptr); - kimage_ptr->data_ptr = NULL; - } - else - { - } -} - -void -x_push_done() -{ -} - -void -x_auto_repeat_on(int must) -{ -} - -void -x_auto_repeat_off(int must) -{ -} - -void -x_hide_pointer(int do_hide) -{ -} - -void -x_full_screen(int do_full) -{ - return; -} - -int x_calc_ratio(float ratiox,float ratioy) -{ - return 0; // not stretched -} - -/**************************************************************************/ -/* DispErrorMsg -- report an error returned from an API service. */ -/* */ -/* The error message is displayed using a message box */ -/* */ -/**************************************************************************/ -VOID DispErrorMessage() -{ - PERRINFO pErrInfoBlk; - PSZ pszOffSet, pszErrMsg; - ERRORID ErrorId; - PCH ErrorStr; - - ErrorId = WinGetLastError(g_hab); - - if ((pErrInfoBlk = WinGetErrorInfo(g_hab)) != (PERRINFO)NULL) - { - pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg; - pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet); - - WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */ - g_hwnd_frame, /* Owner window is our frame */ - pszErrMsg, /* PMWIN Error message */ - "Error", /* Title bar message */ - 0, /* Message identifier */ - MB_MOVEABLE | MB_CANCEL ); /* Flags */ - - WinFreeErrorInfo(pErrInfoBlk); - } -} - -void -os2_abort(HWND g_hwnd_frame, HWND g_hwnd_client) -{ - exit(-1); -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2010 by GSport contributors + Copyright (C) 2016 - Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "../../defc.h" +#include "../../protos.h" + +#define INCL_WIN +#define INCL_GPI + +#include /* PM header file */ +#include +#include "gsportos2.h" /* Resource symbolic identifiers*/ + +HAB g_hab; /* PM anchor block handle */ +PSZ pszErrMsg; +QMSG qmsg; /* Message from message queue */ +HWND g_hwnd_frame = NULLHANDLE; /* Frame window handle */ +HWND g_hwnd_client = NULLHANDLE; /* Client area window handle */ + +HMQ g_hmq; /* Message queue handle */ + +extern int Verbose; + +extern int g_warp_pointer; +extern int g_screen_depth; +extern int g_force_depth; +int g_screen_mdepth = 0; + +extern int g_quit_sim_now; + +int g_use_shmem = 1; +int g_has_focus = 0; +int g_auto_repeat_on = -1; + +extern Kimage g_mainwin_kimage; + +int g_main_height = 0; + +int g_win_capslock_down = 0; + +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; +extern int g_needfullrefreshfornextframe; +extern int g_lores_colors[]; +extern int g_cur_a2_stat; + +extern int g_a2vid_palette; + +extern int g_installed_full_superhires_colormap; + +extern int g_screen_redraw_skip_amt; + +extern word32 g_a2_screen_buffer_changed; + +BITMAPINFO2 *g_bmapinfo_ptr = 0; +volatile BITMAPINFOHEADER2 *g_bmaphdr_ptr = 0; +HDC g_hdc_screen, g_hdc_memory; +HPS g_hps_screen, g_hps_memory; + +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; +extern char *g_status_ptrs[MAX_STATUS_LINES]; + +VOID DispErrorMessage(); + +int +win_nonblock_read_stdin(int fd, char *bufptr, int len) +{ + return 0; +} + +void +x_dialog_create_gsport_conf(const char *str) +{ +} + +int +x_show_alert(int is_fatal, const char *str) +{ + return 0; +} + + + +int +main(int argc, char **argv) +{ +DEVOPENSTRUC pszData; +ULONG flCreate; /* Window creation control flags*/ +int height; +SIZEL sizel; + + if ((g_hab = WinInitialize(0)) == 0L) /* Initialize PM */ + os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ + + if ((g_hmq = WinCreateMsgQueue( g_hab, 0 )) == 0L)/* Create a msg queue */ + os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ + + if (!WinRegisterClass( /* Register window class */ + g_hab, /* Anchor block handle */ + (PSZ)"MyWindow", /* Window class name */ + (PFNWP)MyWindowProc, /* Address of window procedure */ + CS_SIZEREDRAW, /* Class style */ + 0 /* No extra window words */ + )) + os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ + + height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES*16); + g_main_height = height; + + flCreate = FCF_STANDARD & /* Set frame control flags to */ + ~FCF_SHELLPOSITION; /* standard except for shell */ + /* positioning. */ + + if ((g_hwnd_frame = WinCreateStdWindow( + HWND_DESKTOP, /* Desktop window is parent */ + 0, /* STD. window styles */ + &flCreate, /* Frame control flag */ + "MyWindow", /* Client window class name */ + "", /* No window text */ + 0, /* No special class style */ + (HMODULE)0L, /* Resource is in .EXE file */ + ID_WINDOW, /* Frame window identifier */ + &g_hwnd_client /* Client window handle */ + )) == 0L) + os2_abort(HWND_DESKTOP, HWND_DESKTOP); /* Terminate the application */ + + WinSetWindowText(g_hwnd_frame, "GSport"); + + if (!WinSetWindowPos( g_hwnd_frame, /* Shows and activates frame */ + HWND_TOP, /* window at position 100, 100, */ + 100, 100, X_A2_WINDOW_WIDTH, height, /* and size 200, 200. */ + SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW + )) + os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */ + + g_hdc_screen = WinOpenWindowDC(g_hwnd_client); + sizel.cx = X_A2_WINDOW_WIDTH; + sizel.cy = height; + g_hps_screen = GpiCreatePS(g_hab,g_hdc_screen, &sizel, PU_PELS | GPIF_LONG | GPIA_ASSOC); + + g_hdc_memory = DevOpenDC(g_hab, OD_MEMORY, "*", 4, (PDEVOPENDATA)&pszData, NULL); + g_hps_memory = GpiCreatePS(g_hab,g_hdc_memory, &sizel, PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC); + + // Call gsportmain + return gsportmain(argc, argv); + +} + + +/************************************************************************** + * + * Name : MyWindowProc + * + * Description: The window procedure associated with the client area in + * the standard frame window. It processes all messages + * either sent or posted to the client area, depending on + * the message command and parameters. + * + *************************************************************************/ +MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) +{ +HPS hps; +RECTL rcl; + + switch( msg ) + { + case WM_CREATE: + /* + * Window initialization is performed here in WM_CREATE processing + * WinLoadString loads strings from the resource file. + */ + break; + + case WM_COMMAND: + /* + * When the user chooses option 1, 2, or 3 from the Options pull- + * down, the text string is set to 1, 2, or 3, and + * WinInvalidateRegion sends a WM_PAINT message. + * When Exit is chosen, the application posts itself a WM_CLOSE + * message. + */ + { + USHORT command; /* WM_COMMAND command value */ + command = SHORT1FROMMP(mp1); /* Extract the command value */ + switch (command) + { + case ID_EXITPROG: + WinPostMsg( hwnd, WM_CLOSE, (MPARAM)0, (MPARAM)0 ); + break; + default: + return WinDefWindowProc( hwnd, msg, mp1, mp2 ); + } + + break; + } + case WM_ERASEBACKGROUND: + /* + * Return TRUE to request PM to paint the window background + * in SYSCLR_WINDOW. + */ + return (MRESULT)( TRUE ); + case WM_PAINT: + /* + * Window contents are drawn here in WM_PAINT processing. + */ + hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl); + WinEndPaint(hps); + g_needfullrefreshfornextframe = 1; + break; + case WM_CLOSE: + /* + * This is the place to put your termination routines + */ + WinPostMsg( hwnd, WM_QUIT, (MPARAM)0,(MPARAM)0 ); /* Cause termination*/ + exit(0); + break; + default: + /* + * Everything else comes here. This call MUST exist + * in your window procedure. + */ + + return WinDefWindowProc( hwnd, msg, mp1, mp2 ); + } + + return (MRESULT)FALSE; +} /* End of MyWindowProc */ + +void +check_input_events() +{ + +/* + * Get and dispatch messages from the application message queue + * until WinGetMsg returns FALSE, indicating a WM_QUIT message. + */ + + while(WinPeekMsg(g_hab, &qmsg, g_hwnd_frame, 0, 0, PM_NOREMOVE)) { + if(WinGetMsg(g_hab, &qmsg, 0L, 0, 0) > 0) { + //TranslateMessage(&qmsg); + WinDispatchMsg(g_hab, &qmsg); + } else { + printf("GetMessage returned <= 0\n"); + my_exit(2); + } + } +} + + +void +x_update_color(int col_num, int red, int green, int blue, word32 rgb) +{ +} + +void +x_update_physical_colormap() +{ +} + +void +show_xcolor_array() +{ +} + + +void +xdriver_end() +{ + printf("OS/2 driver_end\n"); +} + + +void +x_get_kimage(Kimage *kimage_ptr) +{ + byte *ptr; + int width; + int height; + int depth, mdepth; + int size; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + mdepth = kimage_ptr->mdepth; + + size = 0; + + if(depth == g_screen_depth) { + /* Use g_bmapinfo_ptr, adjusting width, height */ + g_bmaphdr_ptr->cx = width; + g_bmaphdr_ptr->cy = height; + + kimage_ptr->dev_handle = GpiCreateBitmap( + + (HPS)g_hps_memory, (PBITMAPINFOHEADER2)g_bmaphdr_ptr, + 0L, (PBYTE)kimage_ptr->data_ptr, + (PBITMAPINFO2)g_bmapinfo_ptr); + + size = (width*height*mdepth) >> 3; + ptr = (byte *)malloc(size); + + if(ptr == 0) { + printf("malloc for data failed, mdepth: %d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + } else { + /* allocate buffers for video.c to draw into */ + + size = (width*height*mdepth) >> 3; + ptr = (byte *)malloc(size); + + if(ptr == 0) { + printf("malloc for data failed, mdepth: %d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + kimage_ptr->dev_handle = (void *)-1; + + } + + return; +} + + +void +dev_video_init() +{ + int lores_col; + int i; + + printf("Preparing graphics system\n"); + + g_screen_depth = 24; + g_screen_mdepth = 32; + + g_bmapinfo_ptr = (BITMAPINFO2 *)malloc(sizeof(BITMAPINFOHEADER2)); + g_bmaphdr_ptr = (BITMAPINFOHEADER2 *)g_bmapinfo_ptr; + g_bmaphdr_ptr->cbFix = sizeof(BITMAPINFOHEADER2); + g_bmaphdr_ptr->cx = A2_WINDOW_WIDTH; + g_bmaphdr_ptr->cy = A2_WINDOW_HEIGHT; + g_bmaphdr_ptr->cPlanes = 1; + g_bmaphdr_ptr->cBitCount = g_screen_mdepth; + g_bmaphdr_ptr->ulCompression = BCA_UNCOMP; + g_bmaphdr_ptr->cclrUsed = 0; + + video_get_kimages(); + + if(g_screen_depth != 8) { + // Allocate g_mainwin_kimage + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, + g_screen_mdepth); + } + + for(i = 0; i < 256; i++) { + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + + g_installed_full_superhires_colormap = 1; + + printf("Done with dev_video_init\n"); + fflush(stdout); +} + +void +x_redraw_status_lines() +{ + + int line,len,height; + POINTL pt; + char *buf; + + printf("x_redraw_status_lines() called\n"); +/* + if (g_status_ptrs[0] != NULL) + { + height = 16; + pt.x = 5; pt.y = 0; + GpiSetColor( g_hps_screen, CLR_NEUTRAL ); + GpiSetBackColor( g_hps_screen, CLR_BACKGROUND ); + GpiSetBackMix( g_hps_screen, BM_OVERPAINT ); + + for (line = 0; line < MAX_STATUS_LINES; line++) + { + buf = g_status_ptrs[line]; + if (buf != 0) + { + pt.y = height * (line+1); + len = strlen(buf); + GpiCharStringAt( g_hps_screen, &pt, (LONG)strlen( buf ), buf ); + } + } + } +*/ +} + + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, + int width, int height) +{ + RECTL rc; + POINTL pt[4]; + HBITMAP hbmOld, hbmNew; + + char *szString = "Hello, world!\0"; + + printf("x_push_kimage() called: Src: (%d,%d) Dest: (%d,%d) Width: %d Height: %d\n",srcx,srcy,destx,desty,width,height); + pt[0].x = destx; /* Target X1 */ + pt[0].y = desty+(MAX_STATUS_LINES*16); /* Target Y1 */ + pt[1].x = destx+width; /* Target X2 */ + pt[1].y = desty+height+(MAX_STATUS_LINES*16); /* Target Y2: Translate up, make room for status border */ + pt[2].x = srcx; /* Source X */ + pt[2].y = srcy; /* Source Y */ + pt[3].x = srcx+width; + pt[3].y = srcy+height; + +if (width == 560) +{ + /* Paint a known-good bitmap until we can figure out why images aren't showing up */ + hbmNew = GpiLoadBitmap(g_hps_memory,NULLHANDLE,ID_BITMAP,560,400); + hbmOld = GpiSetBitmap(g_hps_memory, hbmNew); + GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE); + GpiSetBitmap(g_hps_memory, hbmOld); + GpiDeleteBitmap(hbmNew); +} +else +{ + hbmOld = GpiSetBitmap(g_hps_memory, (HBITMAP)kimage_ptr->dev_handle); + GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE); + GpiSetBitmap(g_hps_memory, hbmOld); +} + +} + +// OG Adding release +void x_release_kimage(Kimage* kimage_ptr) +{ + if (kimage_ptr->dev_handle == (void*)-1) + { + free(kimage_ptr->data_ptr); + kimage_ptr->data_ptr = NULL; + } + else + { + } +} + +void +x_push_done() +{ +} + +void +x_auto_repeat_on(int must) +{ +} + +void +x_auto_repeat_off(int must) +{ +} + +void +x_hide_pointer(int do_hide) +{ +} + +void +x_full_screen(int do_full) +{ + return; +} + +int x_calc_ratio(float ratiox,float ratioy) +{ + return 0; // not stretched +} + +/**************************************************************************/ +/* DispErrorMsg -- report an error returned from an API service. */ +/* */ +/* The error message is displayed using a message box */ +/* */ +/**************************************************************************/ +VOID DispErrorMessage() +{ + PERRINFO pErrInfoBlk; + PSZ pszOffSet, pszErrMsg; + ERRORID ErrorId; + PCH ErrorStr; + + ErrorId = WinGetLastError(g_hab); + + if ((pErrInfoBlk = WinGetErrorInfo(g_hab)) != (PERRINFO)NULL) + { + pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg; + pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet); + + WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */ + g_hwnd_frame, /* Owner window is our frame */ + pszErrMsg, /* PMWIN Error message */ + "Error", /* Title bar message */ + 0, /* Message identifier */ + MB_MOVEABLE | MB_CANCEL ); /* Flags */ + + WinFreeErrorInfo(pErrInfoBlk); + } +} + +void +os2_abort(HWND g_hwnd_frame, HWND g_hwnd_client) +{ + exit(-1); +} diff --git a/src/arch/os2/os2snd_driver.c b/src/arch/os2/os2snd_driver.c index cfad069..b8fe83b 100644 --- a/src/arch/os2/os2snd_driver.c +++ b/src/arch/os2/os2snd_driver.c @@ -1,22 +1,23 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -int g_preferred_rate = 48000; \ No newline at end of file +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2010 by GSport contributors + Copyright (C) 2016 - Dagen Brock + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +int g_preferred_rate = 48000; diff --git a/src/arch/os2/scc_socket_os2.c b/src/arch/os2/scc_socket_os2.c index 753a794..491f0b6 100644 --- a/src/arch/os2/scc_socket_os2.c +++ b/src/arch/os2/scc_socket_os2.c @@ -1,12 +1,12 @@ -/* scc_socket_driver.c */ -void scc_socket_init(int port) -{} - -void scc_socket_change_params(int port) -{} - -void scc_socket_empty_writebuf(int port, double dcycs) -{} - -void scc_socket_fill_readbuf(int port, int space_left, double dcycs) -{} \ No newline at end of file +/* scc_socket_driver.c */ +void scc_socket_init(int port) +{} + +void scc_socket_change_params(int port) +{} + +void scc_socket_empty_writebuf(int port, double dcycs) +{} + +void scc_socket_fill_readbuf(int port, int space_left, double dcycs) +{} diff --git a/src/arch/os2/src/dirport.c b/src/arch/os2/src/dirport.c index 0271962..2873391 100644 --- a/src/arch/os2/src/dirport.c +++ b/src/arch/os2/src/dirport.c @@ -1,835 +1,835 @@ -/* - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - -#include -#include -#include "dirport.h" - -DIR *opendir (char *path) -{ - APIRET ulrc; - ULONG cnt = 1; - DIR *dir; - char *name; - - if (!(dir = (DIR*)calloc(1, sizeof(DIR)))) { - return NULL; - } - if (name = (char*)calloc(1, strlen(path) + 3)) { - strcat(strcpy(name, path),path[strlen(path) - 1] == '\\' ? "*" : "\\*"); - dir->handle = HDIR_CREATE; - ulrc = DosFindFirst(name, &(dir->handle), _A_ANY, &(dir->buffer), sizeof(struct _FILEFINDBUF3), &cnt, FIL_STANDARD); - free(name); - } - if (!name || ulrc) { - DosFindClose (dir->handle); - free(dir); - dir = NULL; - } - return dir; -} - -struct dirent *readdir (DIR *dir) -{ - ULONG cnt = 1; - - return DosFindNext (dir->handle, &(dir->buffer), sizeof(struct _FILEFINDBUF), &cnt) ? NULL : &(dir->buffer); -} - -int closedir (DIR *dir) -{ - APIRET ulrc = DosFindClose (dir->handle); - - free(dir); - return (int)ulrc; -} - - -#ifndef HAVE_SNPRINTF -/* - * What follows is a portable snprintf routine, written by Mark Martinec. - * See: http://www.ijs.si/software/snprintf/ - - snprintf.c - - a portable implementation of snprintf, - including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf - - snprintf is a routine to convert numeric and string arguments to - formatted strings. It is similar to sprintf(3) provided in a system's - C library, yet it requires an additional argument - the buffer size - - and it guarantees never to store anything beyond the given buffer, - regardless of the format or arguments to be formatted. Some newer - operating systems do provide snprintf in their C library, but many do - not or do provide an inadequate (slow or idiosyncratic) version, which - calls for a portable implementation of this routine. - -Author - - Mark Martinec , April 1999, June 2000 - Copyright © 1999, Mark Martinec - - */ - -#define PORTABLE_SNPRINTF_VERSION_MAJOR 2 -#define PORTABLE_SNPRINTF_VERSION_MINOR 2 - -#if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) -# if defined(NEED_SNPRINTF_ONLY) -# undef NEED_SNPRINTF_ONLY -# endif -# if !defined(PREFER_PORTABLE_SNPRINTF) -# define PREFER_PORTABLE_SNPRINTF -# endif -#endif - -#if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE) -#define SOLARIS_COMPATIBLE -#endif - -#if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE) -#define HPUX_COMPATIBLE -#endif - -#if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE) -#define DIGITAL_UNIX_COMPATIBLE -#endif - -#if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE) -#define PERL_COMPATIBLE -#endif - -#if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE) -#define LINUX_COMPATIBLE -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef isdigit -#undef isdigit -#endif -#define isdigit(c) ((c) >= '0' && (c) <= '9') - -/* For copying strings longer or equal to 'breakeven_point' - * it is more efficient to call memcpy() than to do it inline. - * The value depends mostly on the processor architecture, - * but also on the compiler and its optimization capabilities. - * The value is not critical, some small value greater than zero - * will be just fine if you don't care to squeeze every drop - * of performance out of the code. - * - * Small values favor memcpy, large values favor inline code. - */ -#if defined(__alpha__) || defined(__alpha) -# define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */ -#endif -#if defined(__i386__) || defined(__i386) -# define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */ -#endif -#if defined(__hppa) -# define breakeven_point 10 /* HP-PA - gcc */ -#endif -#if defined(__sparc__) || defined(__sparc) -# define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */ -#endif - -/* some other values of possible interest: */ -/* #define breakeven_point 8 */ /* VAX 4000 - vaxc */ -/* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */ - -#ifndef breakeven_point -# define breakeven_point 6 /* some reasonable one-size-fits-all value */ -#endif - -#define fast_memcpy(d,s,n) \ - { register size_t nn = (size_t)(n); \ - if (nn >= breakeven_point) memcpy((d), (s), nn); \ - else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ - register char *dd; register const char *ss; \ - for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } - -#define fast_memset(d,c,n) \ - { register size_t nn = (size_t)(n); \ - if (nn >= breakeven_point) memset((d), (int)(c), nn); \ - else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ - register char *dd; register const int cc=(int)(c); \ - for (dd=(d); nn>0; nn--) *dd++ = cc; } } - -/* prototypes */ - -#if defined(NEED_ASPRINTF) -int asprintf (char **ptr, const char *fmt, /*args*/ ...); -#endif -#if defined(NEED_VASPRINTF) -int vasprintf (char **ptr, const char *fmt, va_list ap); -#endif -#if defined(NEED_ASNPRINTF) -int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); -#endif -#if defined(NEED_VASNPRINTF) -int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap); -#endif - -#if defined(HAVE_SNPRINTF) -/* declare our portable snprintf routine under name portable_snprintf */ -/* declare our portable vsnprintf routine under name portable_vsnprintf */ -#else -/* declare our portable routines under names snprintf and vsnprintf */ -#define portable_snprintf snprintf -#if !defined(NEED_SNPRINTF_ONLY) -#define portable_vsnprintf vsnprintf -#endif -#endif - -#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) -int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); -#if !defined(NEED_SNPRINTF_ONLY) -int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); -#endif -#endif - -/* declarations */ - -static char credits[] = "\n\ -@(#)snprintf.c, v2.2: Mark Martinec, \n\ -@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\ -@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n"; - -#if defined(NEED_ASPRINTF) -int asprintf(char **ptr, const char *fmt, /*args*/ ...) { - va_list ap; - size_t str_m; - int str_l; - - *ptr = NULL; - va_start(ap, fmt); /* measure the required size */ - str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); - va_end(ap); - assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ - *ptr = (char *) malloc(str_m = (size_t)str_l + 1); - if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } - else { - int str_l2; - va_start(ap, fmt); - str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); - va_end(ap); - assert(str_l2 == str_l); - } - return str_l; -} -#endif - -#if defined(NEED_VASPRINTF) -int vasprintf(char **ptr, const char *fmt, va_list ap) { - size_t str_m; - int str_l; - - *ptr = NULL; - { va_list ap2; - va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ - str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ - va_end(ap2); - } - assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ - *ptr = (char *) malloc(str_m = (size_t)str_l + 1); - if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } - else { - int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); - assert(str_l2 == str_l); - } - return str_l; -} -#endif - -#if defined(NEED_ASNPRINTF) -int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) { - va_list ap; - int str_l; - - *ptr = NULL; - va_start(ap, fmt); /* measure the required size */ - str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); - va_end(ap); - assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ - if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ - /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ - if (str_m == 0) { /* not interested in resulting string, just return size */ - } else { - *ptr = (char *) malloc(str_m); - if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } - else { - int str_l2; - va_start(ap, fmt); - str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); - va_end(ap); - assert(str_l2 == str_l); - } - } - return str_l; -} -#endif - -#if defined(NEED_VASNPRINTF) -int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) { - int str_l; - - *ptr = NULL; - { va_list ap2; - va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ - str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ - va_end(ap2); - } - assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ - if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ - /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ - if (str_m == 0) { /* not interested in resulting string, just return size */ - } else { - *ptr = (char *) malloc(str_m); - if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } - else { - int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); - assert(str_l2 == str_l); - } - } - return str_l; -} -#endif - -/* - * If the system does have snprintf and the portable routine is not - * specifically required, this module produces no code for snprintf/vsnprintf. - */ -#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) - -#if !defined(NEED_SNPRINTF_ONLY) -int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { - va_list ap; - int str_l; - - va_start(ap, fmt); - str_l = portable_vsnprintf(str, str_m, fmt, ap); - va_end(ap); - return str_l; -} -#endif - -#if defined(NEED_SNPRINTF_ONLY) -int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { -#else -int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { -#endif - -#if defined(NEED_SNPRINTF_ONLY) - va_list ap; -#endif - size_t str_l = 0; - const char *p = fmt; - -/* In contrast with POSIX, the ISO C99 now says - * that str can be NULL and str_m can be 0. - * This is more useful than the old: if (str_m < 1) return -1; */ - -#if defined(NEED_SNPRINTF_ONLY) - va_start(ap, fmt); -#endif - if (!p) p = ""; - while (*p) { - if (*p != '%') { - /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */ - /* but the following code achieves better performance for cases - * where format string is long and contains few conversions */ - const char *q = strchr(p+1,'%'); - size_t n = !q ? strlen(p) : (q-p); - if (str_l < str_m) { - size_t avail = str_m-str_l; - fast_memcpy(str+str_l, p, (n>avail?avail:n)); - } - p += n; str_l += n; - } else { - const char *starting_p; - size_t min_field_width = 0, precision = 0; - int zero_padding = 0, precision_specified = 0, justify_left = 0; - int alternate_form = 0, force_sign = 0; - int space_for_positive = 1; /* If both the ' ' and '+' flags appear, - the ' ' flag should be ignored. */ - char length_modifier = '\0'; /* allowed values: \0, h, l, L */ - char tmp[32];/* temporary buffer for simple numeric->string conversion */ - - const char *str_arg; /* string address in case of string argument */ - size_t str_arg_l; /* natural field width of arg without padding - and sign */ - unsigned char uchar_arg; - /* unsigned char argument value - only defined for c conversion. - N.B. standard explicitly states the char argument for - the c conversion is unsigned */ - - size_t number_of_zeros_to_pad = 0; - /* number of zeros to be inserted for numeric conversions - as required by the precision or minimal field width */ - - size_t zero_padding_insertion_ind = 0; - /* index into tmp where zero padding is to be inserted */ - - char fmt_spec = '\0'; - /* current conversion specifier character */ - - str_arg = credits;/* just to make compiler happy (defined but not used)*/ - str_arg = NULL; - starting_p = p; p++; /* skip '%' */ - /* parse flags */ - while (*p == '0' || *p == '-' || *p == '+' || - *p == ' ' || *p == '#' || *p == '\'') { - switch (*p) { - case '0': zero_padding = 1; break; - case '-': justify_left = 1; break; - case '+': force_sign = 1; space_for_positive = 0; break; - case ' ': force_sign = 1; - /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ -#ifdef PERL_COMPATIBLE - /* ... but in Perl the last of ' ' and '+' applies */ - space_for_positive = 1; -#endif - break; - case '#': alternate_form = 1; break; - case '\'': break; - } - p++; - } - /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */ - - /* parse field width */ - if (*p == '*') { - int j; - p++; j = va_arg(ap, int); - if (j >= 0) min_field_width = j; - else { min_field_width = -j; justify_left = 1; } - } else if (isdigit((int)(*p))) { - /* size_t could be wider than unsigned int; - make sure we treat argument like common implementations do */ - unsigned int uj = *p++ - '0'; - while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); - min_field_width = uj; - } - /* parse precision */ - if (*p == '.') { - p++; precision_specified = 1; - if (*p == '*') { - int j = va_arg(ap, int); - p++; - if (j >= 0) precision = j; - else { - precision_specified = 0; precision = 0; - /* NOTE: - * Solaris 2.6 man page claims that in this case the precision - * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page - * claim that this case should be treated as unspecified precision, - * which is what we do here. - */ - } - } else if (isdigit((int)(*p))) { - /* size_t could be wider than unsigned int; - make sure we treat argument like common implementations do */ - unsigned int uj = *p++ - '0'; - while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); - precision = uj; - } - } - /* parse 'h', 'l' and 'll' length modifiers */ - if (*p == 'h' || *p == 'l') { - length_modifier = *p; p++; - if (length_modifier == 'l' && *p == 'l') { /* double l = long long */ -#ifdef SNPRINTF_LONGLONG_SUPPORT - length_modifier = '2'; /* double l encoded as '2' */ -#else - length_modifier = 'l'; /* treat it as a single 'l' */ -#endif - p++; - } - } - fmt_spec = *p; - /* common synonyms: */ - switch (fmt_spec) { - case 'i': fmt_spec = 'd'; break; - case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; - case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; - case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; - default: break; - } - /* get parameter value, do initial processing */ - switch (fmt_spec) { - case '%': /* % behaves similar to 's' regarding flags and field widths */ - case 'c': /* c behaves similar to 's' regarding flags and field widths */ - case 's': - length_modifier = '\0'; /* wint_t and wchar_t not supported */ - /* the result of zero padding flag with non-numeric conversion specifier*/ - /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ - /* Digital Unix and Linux does not. */ -#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE) - zero_padding = 0; /* turn zero padding off for string conversions */ -#endif - str_arg_l = 1; - switch (fmt_spec) { - case '%': - str_arg = p; break; - case 'c': { - int j = va_arg(ap, int); - uchar_arg = (unsigned char) j; /* standard demands unsigned char */ - str_arg = (const char *) &uchar_arg; - break; - } - case 's': - str_arg = va_arg(ap, const char *); - if (!str_arg) str_arg_l = 0; - /* make sure not to address string beyond the specified precision !!! */ - else if (!precision_specified) str_arg_l = strlen(str_arg); - /* truncate string if necessary as requested by precision */ - else if (precision == 0) str_arg_l = 0; - else { - /* memchr on HP does not like n > 2^31 !!! */ - const char *q = memchr(str_arg, '\0', - precision <= 0x7fffffff ? precision : 0x7fffffff); - str_arg_l = !q ? precision : (q-str_arg); - } - break; - default: break; - } - break; - case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { - /* NOTE: the u, o, x, X and p conversion specifiers imply - the value is unsigned; d implies a signed value */ - - int arg_sign = 0; - /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), - +1 if greater than zero (or nonzero for unsigned arguments), - -1 if negative (unsigned argument is never negative) */ - - int int_arg = 0; unsigned int uint_arg = 0; - /* only defined for length modifier h, or for no length modifiers */ - - long int long_arg = 0; unsigned long int ulong_arg = 0; - /* only defined for length modifier l */ - - void *ptr_arg = NULL; - /* pointer argument value -only defined for p conversion */ - -#ifdef SNPRINTF_LONGLONG_SUPPORT - long long int long_long_arg = 0; - unsigned long long int ulong_long_arg = 0; - /* only defined for length modifier ll */ -#endif - if (fmt_spec == 'p') { - /* HPUX 10: An l, h, ll or L before any other conversion character - * (other than d, i, u, o, x, or X) is ignored. - * Digital Unix: - * not specified, but seems to behave as HPUX does. - * Solaris: If an h, l, or L appears before any other conversion - * specifier (other than d, i, u, o, x, or X), the behavior - * is undefined. (Actually %hp converts only 16-bits of address - * and %llp treats address as 64-bit data which is incompatible - * with (void *) argument on a 32-bit system). - */ -#ifdef SOLARIS_COMPATIBLE -# ifdef SOLARIS_BUG_COMPATIBLE - /* keep length modifiers even if it represents 'll' */ -# else - if (length_modifier == '2') length_modifier = '\0'; -# endif -#else - length_modifier = '\0'; -#endif - ptr_arg = va_arg(ap, void *); - if (ptr_arg != NULL) arg_sign = 1; - } else if (fmt_spec == 'd') { /* signed */ - switch (length_modifier) { - case '\0': - case 'h': - /* It is non-portable to specify a second argument of char or short - * to va_arg, because arguments seen by the called function - * are not char or short. C converts char and short arguments - * to int before passing them to a function. - */ - int_arg = va_arg(ap, int); - if (int_arg > 0) arg_sign = 1; - else if (int_arg < 0) arg_sign = -1; - break; - case 'l': - long_arg = va_arg(ap, long int); - if (long_arg > 0) arg_sign = 1; - else if (long_arg < 0) arg_sign = -1; - break; -#ifdef SNPRINTF_LONGLONG_SUPPORT - case '2': - long_long_arg = va_arg(ap, long long int); - if (long_long_arg > 0) arg_sign = 1; - else if (long_long_arg < 0) arg_sign = -1; - break; -#endif - } - } else { /* unsigned */ - switch (length_modifier) { - case '\0': - case 'h': - uint_arg = va_arg(ap, unsigned int); - if (uint_arg) arg_sign = 1; - break; - case 'l': - ulong_arg = va_arg(ap, unsigned long int); - if (ulong_arg) arg_sign = 1; - break; -#ifdef SNPRINTF_LONGLONG_SUPPORT - case '2': - ulong_long_arg = va_arg(ap, unsigned long long int); - if (ulong_long_arg) arg_sign = 1; - break; -#endif - } - } - str_arg = tmp; str_arg_l = 0; - /* NOTE: - * For d, i, u, o, x, and X conversions, if precision is specified, - * the '0' flag should be ignored. This is so with Solaris 2.6, - * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. - */ -#ifndef PERL_COMPATIBLE - if (precision_specified) zero_padding = 0; -#endif - if (fmt_spec == 'd') { - if (force_sign && arg_sign >= 0) - tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; - /* leave negative numbers for sprintf to handle, - to avoid handling tricky cases like (short int)(-32768) */ -#ifdef LINUX_COMPATIBLE - } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) { - tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; -#endif - } else if (alternate_form) { - if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) - { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } - /* alternate form should have no effect for p conversion, but ... */ -#ifdef HPUX_COMPATIBLE - else if (fmt_spec == 'p' - /* HPUX 10: for an alternate form of p conversion, - * a nonzero result is prefixed by 0x. */ -#ifndef HPUX_BUG_COMPATIBLE - /* Actually it uses 0x prefix even for a zero value. */ - && arg_sign != 0 -#endif - ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; } -#endif - } - zero_padding_insertion_ind = str_arg_l; - if (!precision_specified) precision = 1; /* default precision is 1 */ - if (precision == 0 && arg_sign == 0 -#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE) - && fmt_spec != 'p' - /* HPUX 10 man page claims: With conversion character p the result of - * converting a zero value with a precision of zero is a null string. - * Actually HP returns all zeroes, and Linux returns "(nil)". */ -#endif - ) { - /* converted to null string */ - /* When zero value is formatted with an explicit precision 0, - the resulting formatted string is empty (d, i, u, o, x, X, p). */ - } else { - char f[5]; int f_l = 0; - f[f_l++] = '%'; /* construct a simple format string for sprintf */ - if (!length_modifier) { } - else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } - else f[f_l++] = length_modifier; - f[f_l++] = fmt_spec; f[f_l++] = '\0'; - if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg); - else if (fmt_spec == 'd') { /* signed */ - switch (length_modifier) { - case '\0': - case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break; - case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break; -#ifdef SNPRINTF_LONGLONG_SUPPORT - case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break; -#endif - } - } else { /* unsigned */ - switch (length_modifier) { - case '\0': - case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break; - case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break; -#ifdef SNPRINTF_LONGLONG_SUPPORT - case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; -#endif - } - } - /* include the optional minus sign and possible "0x" - in the region before the zero padding insertion point */ - if (zero_padding_insertion_ind < str_arg_l && - tmp[zero_padding_insertion_ind] == '-') { - zero_padding_insertion_ind++; - } - if (zero_padding_insertion_ind+1 < str_arg_l && - tmp[zero_padding_insertion_ind] == '0' && - (tmp[zero_padding_insertion_ind+1] == 'x' || - tmp[zero_padding_insertion_ind+1] == 'X') ) { - zero_padding_insertion_ind += 2; - } - } - { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; - if (alternate_form && fmt_spec == 'o' -#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */ - && (str_arg_l > 0) -#endif -#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */ -#else - /* unless zero is already the first character */ - && !(zero_padding_insertion_ind < str_arg_l - && tmp[zero_padding_insertion_ind] == '0') -#endif - ) { /* assure leading zero for alternate-form octal numbers */ - if (!precision_specified || precision < num_of_digits+1) { - /* precision is increased to force the first character to be zero, - except if a zero value is formatted with an explicit precision - of zero */ - precision = num_of_digits+1; precision_specified = 1; - } - } - /* zero padding to specified precision? */ - if (num_of_digits < precision) - number_of_zeros_to_pad = precision - num_of_digits; - } - /* zero padding to specified minimal field width? */ - if (!justify_left && zero_padding) { - int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); - if (n > 0) number_of_zeros_to_pad += n; - } - break; - } - default: /* unrecognized conversion specifier, keep format string as-is*/ - zero_padding = 0; /* turn zero padding off for non-numeric convers. */ -#ifndef DIGITAL_UNIX_COMPATIBLE - justify_left = 1; min_field_width = 0; /* reset flags */ -#endif -#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE) - /* keep the entire format string unchanged */ - str_arg = starting_p; str_arg_l = p - starting_p; - /* well, not exactly so for Linux, which does something inbetween, - * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */ -#else - /* discard the unrecognized conversion, just keep * - * the unrecognized conversion character */ - str_arg = p; str_arg_l = 0; -#endif - if (*p) str_arg_l++; /* include invalid conversion specifier unchanged - if not at end-of-string */ - break; - } - if (*p) p++; /* step over the just processed conversion specifier */ - /* insert padding to the left as requested by min_field_width; - this does not include the zero padding in case of numerical conversions*/ - if (!justify_left) { /* left padding with blank or zero */ - int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); - if (n > 0) { - if (str_l < str_m) { - size_t avail = str_m-str_l; - fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n)); - } - str_l += n; - } - } - /* zero padding as requested by the precision or by the minimal field width - * for numeric conversions required? */ - if (number_of_zeros_to_pad <= 0) { - /* will not copy first part of numeric right now, * - * force it to be copied later in its entirety */ - zero_padding_insertion_ind = 0; - } else { - /* insert first part of numerics (sign or '0x') before zero padding */ - int n = zero_padding_insertion_ind; - if (n > 0) { - if (str_l < str_m) { - size_t avail = str_m-str_l; - fast_memcpy(str+str_l, str_arg, (n>avail?avail:n)); - } - str_l += n; - } - /* insert zero padding as requested by the precision or min field width */ - n = number_of_zeros_to_pad; - if (n > 0) { - if (str_l < str_m) { - size_t avail = str_m-str_l; - fast_memset(str+str_l, '0', (n>avail?avail:n)); - } - str_l += n; - } - } - /* insert formatted string - * (or as-is conversion specifier for unknown conversions) */ - { int n = str_arg_l - zero_padding_insertion_ind; - if (n > 0) { - if (str_l < str_m) { - size_t avail = str_m-str_l; - fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, - (n>avail?avail:n)); - } - str_l += n; - } - } - /* insert right padding */ - if (justify_left) { /* right blank padding to the field width */ - int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); - if (n > 0) { - if (str_l < str_m) { - size_t avail = str_m-str_l; - fast_memset(str+str_l, ' ', (n>avail?avail:n)); - } - str_l += n; - } - } - } - } -#if defined(NEED_SNPRINTF_ONLY) - va_end(ap); -#endif - if (str_m > 0) { /* make sure the string is null-terminated - even at the expense of overwriting the last character - (shouldn't happen, but just in case) */ - str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; - } - /* Return the number of characters formatted (excluding trailing null - * character), that is, the number of characters that would have been - * written to the buffer if it were large enough. - * - * The value of str_l should be returned, but str_l is of unsigned type - * size_t, and snprintf is int, possibly leading to an undetected - * integer overflow, resulting in a negative return value, which is illegal. - * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. - * Should errno be set to EOVERFLOW and EOF returned in this case??? - */ - return (int) str_l; -} -#endif -#endif /* ndef HAVE_SNPRINTF */ -/* - Local Variables: - tab-width: 3 - end: -*/ +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include +#include +#include "dirport.h" + +DIR *opendir (char *path) +{ + APIRET ulrc; + ULONG cnt = 1; + DIR *dir; + char *name; + + if (!(dir = (DIR*)calloc(1, sizeof(DIR)))) { + return NULL; + } + if (name = (char*)calloc(1, strlen(path) + 3)) { + strcat(strcpy(name, path),path[strlen(path) - 1] == '\\' ? "*" : "\\*"); + dir->handle = HDIR_CREATE; + ulrc = DosFindFirst(name, &(dir->handle), _A_ANY, &(dir->buffer), sizeof(struct _FILEFINDBUF3), &cnt, FIL_STANDARD); + free(name); + } + if (!name || ulrc) { + DosFindClose (dir->handle); + free(dir); + dir = NULL; + } + return dir; +} + +struct dirent *readdir (DIR *dir) +{ + ULONG cnt = 1; + + return DosFindNext (dir->handle, &(dir->buffer), sizeof(struct _FILEFINDBUF), &cnt) ? NULL : &(dir->buffer); +} + +int closedir (DIR *dir) +{ + APIRET ulrc = DosFindClose (dir->handle); + + free(dir); + return (int)ulrc; +} + + +#ifndef HAVE_SNPRINTF +/* + * What follows is a portable snprintf routine, written by Mark Martinec. + * See: http://www.ijs.si/software/snprintf/ + + snprintf.c + - a portable implementation of snprintf, + including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf + + snprintf is a routine to convert numeric and string arguments to + formatted strings. It is similar to sprintf(3) provided in a system's + C library, yet it requires an additional argument - the buffer size - + and it guarantees never to store anything beyond the given buffer, + regardless of the format or arguments to be formatted. Some newer + operating systems do provide snprintf in their C library, but many do + not or do provide an inadequate (slow or idiosyncratic) version, which + calls for a portable implementation of this routine. + +Author + + Mark Martinec , April 1999, June 2000 + Copyright © 1999, Mark Martinec + + */ + +#define PORTABLE_SNPRINTF_VERSION_MAJOR 2 +#define PORTABLE_SNPRINTF_VERSION_MINOR 2 + +#if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) +# if defined(NEED_SNPRINTF_ONLY) +# undef NEED_SNPRINTF_ONLY +# endif +# if !defined(PREFER_PORTABLE_SNPRINTF) +# define PREFER_PORTABLE_SNPRINTF +# endif +#endif + +#if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE) +#define SOLARIS_COMPATIBLE +#endif + +#if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE) +#define HPUX_COMPATIBLE +#endif + +#if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE) +#define DIGITAL_UNIX_COMPATIBLE +#endif + +#if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE) +#define PERL_COMPATIBLE +#endif + +#if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE) +#define LINUX_COMPATIBLE +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef isdigit +#undef isdigit +#endif +#define isdigit(c) ((c) >= '0' && (c) <= '9') + +/* For copying strings longer or equal to 'breakeven_point' + * it is more efficient to call memcpy() than to do it inline. + * The value depends mostly on the processor architecture, + * but also on the compiler and its optimization capabilities. + * The value is not critical, some small value greater than zero + * will be just fine if you don't care to squeeze every drop + * of performance out of the code. + * + * Small values favor memcpy, large values favor inline code. + */ +#if defined(__alpha__) || defined(__alpha) +# define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */ +#endif +#if defined(__i386__) || defined(__i386) +# define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */ +#endif +#if defined(__hppa) +# define breakeven_point 10 /* HP-PA - gcc */ +#endif +#if defined(__sparc__) || defined(__sparc) +# define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */ +#endif + +/* some other values of possible interest: */ +/* #define breakeven_point 8 */ /* VAX 4000 - vaxc */ +/* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */ + +#ifndef breakeven_point +# define breakeven_point 6 /* some reasonable one-size-fits-all value */ +#endif + +#define fast_memcpy(d,s,n) \ + { register size_t nn = (size_t)(n); \ + if (nn >= breakeven_point) memcpy((d), (s), nn); \ + else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ + register char *dd; register const char *ss; \ + for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } + +#define fast_memset(d,c,n) \ + { register size_t nn = (size_t)(n); \ + if (nn >= breakeven_point) memset((d), (int)(c), nn); \ + else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ + register char *dd; register const int cc=(int)(c); \ + for (dd=(d); nn>0; nn--) *dd++ = cc; } } + +/* prototypes */ + +#if defined(NEED_ASPRINTF) +int asprintf (char **ptr, const char *fmt, /*args*/ ...); +#endif +#if defined(NEED_VASPRINTF) +int vasprintf (char **ptr, const char *fmt, va_list ap); +#endif +#if defined(NEED_ASNPRINTF) +int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); +#endif +#if defined(NEED_VASNPRINTF) +int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap); +#endif + +#if defined(HAVE_SNPRINTF) +/* declare our portable snprintf routine under name portable_snprintf */ +/* declare our portable vsnprintf routine under name portable_vsnprintf */ +#else +/* declare our portable routines under names snprintf and vsnprintf */ +#define portable_snprintf snprintf +#if !defined(NEED_SNPRINTF_ONLY) +#define portable_vsnprintf vsnprintf +#endif +#endif + +#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); +#if !defined(NEED_SNPRINTF_ONLY) +int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); +#endif +#endif + +/* declarations */ + +static char credits[] = "\n\ +@(#)snprintf.c, v2.2: Mark Martinec, \n\ +@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\ +@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n"; + +#if defined(NEED_ASPRINTF) +int asprintf(char **ptr, const char *fmt, /*args*/ ...) { + va_list ap; + size_t str_m; + int str_l; + + *ptr = NULL; + va_start(ap, fmt); /* measure the required size */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); + va_end(ap); + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + *ptr = (char *) malloc(str_m = (size_t)str_l + 1); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2; + va_start(ap, fmt); + str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + va_end(ap); + assert(str_l2 == str_l); + } + return str_l; +} +#endif + +#if defined(NEED_VASPRINTF) +int vasprintf(char **ptr, const char *fmt, va_list ap) { + size_t str_m; + int str_l; + + *ptr = NULL; + { va_list ap2; + va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ + va_end(ap2); + } + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + *ptr = (char *) malloc(str_m = (size_t)str_l + 1); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + assert(str_l2 == str_l); + } + return str_l; +} +#endif + +#if defined(NEED_ASNPRINTF) +int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) { + va_list ap; + int str_l; + + *ptr = NULL; + va_start(ap, fmt); /* measure the required size */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); + va_end(ap); + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ + /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ + if (str_m == 0) { /* not interested in resulting string, just return size */ + } else { + *ptr = (char *) malloc(str_m); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2; + va_start(ap, fmt); + str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + va_end(ap); + assert(str_l2 == str_l); + } + } + return str_l; +} +#endif + +#if defined(NEED_VASNPRINTF) +int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) { + int str_l; + + *ptr = NULL; + { va_list ap2; + va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ + va_end(ap2); + } + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ + /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ + if (str_m == 0) { /* not interested in resulting string, just return size */ + } else { + *ptr = (char *) malloc(str_m); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + assert(str_l2 == str_l); + } + } + return str_l; +} +#endif + +/* + * If the system does have snprintf and the portable routine is not + * specifically required, this module produces no code for snprintf/vsnprintf. + */ +#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) + +#if !defined(NEED_SNPRINTF_ONLY) +int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { + va_list ap; + int str_l; + + va_start(ap, fmt); + str_l = portable_vsnprintf(str, str_m, fmt, ap); + va_end(ap); + return str_l; +} +#endif + +#if defined(NEED_SNPRINTF_ONLY) +int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { +#else +int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { +#endif + +#if defined(NEED_SNPRINTF_ONLY) + va_list ap; +#endif + size_t str_l = 0; + const char *p = fmt; + +/* In contrast with POSIX, the ISO C99 now says + * that str can be NULL and str_m can be 0. + * This is more useful than the old: if (str_m < 1) return -1; */ + +#if defined(NEED_SNPRINTF_ONLY) + va_start(ap, fmt); +#endif + if (!p) p = ""; + while (*p) { + if (*p != '%') { + /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */ + /* but the following code achieves better performance for cases + * where format string is long and contains few conversions */ + const char *q = strchr(p+1,'%'); + size_t n = !q ? strlen(p) : (q-p); + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, p, (n>avail?avail:n)); + } + p += n; str_l += n; + } else { + const char *starting_p; + size_t min_field_width = 0, precision = 0; + int zero_padding = 0, precision_specified = 0, justify_left = 0; + int alternate_form = 0, force_sign = 0; + int space_for_positive = 1; /* If both the ' ' and '+' flags appear, + the ' ' flag should be ignored. */ + char length_modifier = '\0'; /* allowed values: \0, h, l, L */ + char tmp[32];/* temporary buffer for simple numeric->string conversion */ + + const char *str_arg; /* string address in case of string argument */ + size_t str_arg_l; /* natural field width of arg without padding + and sign */ + unsigned char uchar_arg; + /* unsigned char argument value - only defined for c conversion. + N.B. standard explicitly states the char argument for + the c conversion is unsigned */ + + size_t number_of_zeros_to_pad = 0; + /* number of zeros to be inserted for numeric conversions + as required by the precision or minimal field width */ + + size_t zero_padding_insertion_ind = 0; + /* index into tmp where zero padding is to be inserted */ + + char fmt_spec = '\0'; + /* current conversion specifier character */ + + str_arg = credits;/* just to make compiler happy (defined but not used)*/ + str_arg = NULL; + starting_p = p; p++; /* skip '%' */ + /* parse flags */ + while (*p == '0' || *p == '-' || *p == '+' || + *p == ' ' || *p == '#' || *p == '\'') { + switch (*p) { + case '0': zero_padding = 1; break; + case '-': justify_left = 1; break; + case '+': force_sign = 1; space_for_positive = 0; break; + case ' ': force_sign = 1; + /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ +#ifdef PERL_COMPATIBLE + /* ... but in Perl the last of ' ' and '+' applies */ + space_for_positive = 1; +#endif + break; + case '#': alternate_form = 1; break; + case '\'': break; + } + p++; + } + /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */ + + /* parse field width */ + if (*p == '*') { + int j; + p++; j = va_arg(ap, int); + if (j >= 0) min_field_width = j; + else { min_field_width = -j; justify_left = 1; } + } else if (isdigit((int)(*p))) { + /* size_t could be wider than unsigned int; + make sure we treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); + min_field_width = uj; + } + /* parse precision */ + if (*p == '.') { + p++; precision_specified = 1; + if (*p == '*') { + int j = va_arg(ap, int); + p++; + if (j >= 0) precision = j; + else { + precision_specified = 0; precision = 0; + /* NOTE: + * Solaris 2.6 man page claims that in this case the precision + * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page + * claim that this case should be treated as unspecified precision, + * which is what we do here. + */ + } + } else if (isdigit((int)(*p))) { + /* size_t could be wider than unsigned int; + make sure we treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); + precision = uj; + } + } + /* parse 'h', 'l' and 'll' length modifiers */ + if (*p == 'h' || *p == 'l') { + length_modifier = *p; p++; + if (length_modifier == 'l' && *p == 'l') { /* double l = long long */ +#ifdef SNPRINTF_LONGLONG_SUPPORT + length_modifier = '2'; /* double l encoded as '2' */ +#else + length_modifier = 'l'; /* treat it as a single 'l' */ +#endif + p++; + } + } + fmt_spec = *p; + /* common synonyms: */ + switch (fmt_spec) { + case 'i': fmt_spec = 'd'; break; + case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; + case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; + case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; + default: break; + } + /* get parameter value, do initial processing */ + switch (fmt_spec) { + case '%': /* % behaves similar to 's' regarding flags and field widths */ + case 'c': /* c behaves similar to 's' regarding flags and field widths */ + case 's': + length_modifier = '\0'; /* wint_t and wchar_t not supported */ + /* the result of zero padding flag with non-numeric conversion specifier*/ + /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ + /* Digital Unix and Linux does not. */ +#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE) + zero_padding = 0; /* turn zero padding off for string conversions */ +#endif + str_arg_l = 1; + switch (fmt_spec) { + case '%': + str_arg = p; break; + case 'c': { + int j = va_arg(ap, int); + uchar_arg = (unsigned char) j; /* standard demands unsigned char */ + str_arg = (const char *) &uchar_arg; + break; + } + case 's': + str_arg = va_arg(ap, const char *); + if (!str_arg) str_arg_l = 0; + /* make sure not to address string beyond the specified precision !!! */ + else if (!precision_specified) str_arg_l = strlen(str_arg); + /* truncate string if necessary as requested by precision */ + else if (precision == 0) str_arg_l = 0; + else { + /* memchr on HP does not like n > 2^31 !!! */ + const char *q = memchr(str_arg, '\0', + precision <= 0x7fffffff ? precision : 0x7fffffff); + str_arg_l = !q ? precision : (q-str_arg); + } + break; + default: break; + } + break; + case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { + /* NOTE: the u, o, x, X and p conversion specifiers imply + the value is unsigned; d implies a signed value */ + + int arg_sign = 0; + /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), + +1 if greater than zero (or nonzero for unsigned arguments), + -1 if negative (unsigned argument is never negative) */ + + int int_arg = 0; unsigned int uint_arg = 0; + /* only defined for length modifier h, or for no length modifiers */ + + long int long_arg = 0; unsigned long int ulong_arg = 0; + /* only defined for length modifier l */ + + void *ptr_arg = NULL; + /* pointer argument value -only defined for p conversion */ + +#ifdef SNPRINTF_LONGLONG_SUPPORT + long long int long_long_arg = 0; + unsigned long long int ulong_long_arg = 0; + /* only defined for length modifier ll */ +#endif + if (fmt_spec == 'p') { + /* HPUX 10: An l, h, ll or L before any other conversion character + * (other than d, i, u, o, x, or X) is ignored. + * Digital Unix: + * not specified, but seems to behave as HPUX does. + * Solaris: If an h, l, or L appears before any other conversion + * specifier (other than d, i, u, o, x, or X), the behavior + * is undefined. (Actually %hp converts only 16-bits of address + * and %llp treats address as 64-bit data which is incompatible + * with (void *) argument on a 32-bit system). + */ +#ifdef SOLARIS_COMPATIBLE +# ifdef SOLARIS_BUG_COMPATIBLE + /* keep length modifiers even if it represents 'll' */ +# else + if (length_modifier == '2') length_modifier = '\0'; +# endif +#else + length_modifier = '\0'; +#endif + ptr_arg = va_arg(ap, void *); + if (ptr_arg != NULL) arg_sign = 1; + } else if (fmt_spec == 'd') { /* signed */ + switch (length_modifier) { + case '\0': + case 'h': + /* It is non-portable to specify a second argument of char or short + * to va_arg, because arguments seen by the called function + * are not char or short. C converts char and short arguments + * to int before passing them to a function. + */ + int_arg = va_arg(ap, int); + if (int_arg > 0) arg_sign = 1; + else if (int_arg < 0) arg_sign = -1; + break; + case 'l': + long_arg = va_arg(ap, long int); + if (long_arg > 0) arg_sign = 1; + else if (long_arg < 0) arg_sign = -1; + break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': + long_long_arg = va_arg(ap, long long int); + if (long_long_arg > 0) arg_sign = 1; + else if (long_long_arg < 0) arg_sign = -1; + break; +#endif + } + } else { /* unsigned */ + switch (length_modifier) { + case '\0': + case 'h': + uint_arg = va_arg(ap, unsigned int); + if (uint_arg) arg_sign = 1; + break; + case 'l': + ulong_arg = va_arg(ap, unsigned long int); + if (ulong_arg) arg_sign = 1; + break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': + ulong_long_arg = va_arg(ap, unsigned long long int); + if (ulong_long_arg) arg_sign = 1; + break; +#endif + } + } + str_arg = tmp; str_arg_l = 0; + /* NOTE: + * For d, i, u, o, x, and X conversions, if precision is specified, + * the '0' flag should be ignored. This is so with Solaris 2.6, + * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. + */ +#ifndef PERL_COMPATIBLE + if (precision_specified) zero_padding = 0; +#endif + if (fmt_spec == 'd') { + if (force_sign && arg_sign >= 0) + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; + /* leave negative numbers for sprintf to handle, + to avoid handling tricky cases like (short int)(-32768) */ +#ifdef LINUX_COMPATIBLE + } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) { + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; +#endif + } else if (alternate_form) { + if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) + { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } + /* alternate form should have no effect for p conversion, but ... */ +#ifdef HPUX_COMPATIBLE + else if (fmt_spec == 'p' + /* HPUX 10: for an alternate form of p conversion, + * a nonzero result is prefixed by 0x. */ +#ifndef HPUX_BUG_COMPATIBLE + /* Actually it uses 0x prefix even for a zero value. */ + && arg_sign != 0 +#endif + ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; } +#endif + } + zero_padding_insertion_ind = str_arg_l; + if (!precision_specified) precision = 1; /* default precision is 1 */ + if (precision == 0 && arg_sign == 0 +#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE) + && fmt_spec != 'p' + /* HPUX 10 man page claims: With conversion character p the result of + * converting a zero value with a precision of zero is a null string. + * Actually HP returns all zeroes, and Linux returns "(nil)". */ +#endif + ) { + /* converted to null string */ + /* When zero value is formatted with an explicit precision 0, + the resulting formatted string is empty (d, i, u, o, x, X, p). */ + } else { + char f[5]; int f_l = 0; + f[f_l++] = '%'; /* construct a simple format string for sprintf */ + if (!length_modifier) { } + else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } + else f[f_l++] = length_modifier; + f[f_l++] = fmt_spec; f[f_l++] = '\0'; + if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg); + else if (fmt_spec == 'd') { /* signed */ + switch (length_modifier) { + case '\0': + case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break; + case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break; +#endif + } + } else { /* unsigned */ + switch (length_modifier) { + case '\0': + case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break; + case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; +#endif + } + } + /* include the optional minus sign and possible "0x" + in the region before the zero padding insertion point */ + if (zero_padding_insertion_ind < str_arg_l && + tmp[zero_padding_insertion_ind] == '-') { + zero_padding_insertion_ind++; + } + if (zero_padding_insertion_ind+1 < str_arg_l && + tmp[zero_padding_insertion_ind] == '0' && + (tmp[zero_padding_insertion_ind+1] == 'x' || + tmp[zero_padding_insertion_ind+1] == 'X') ) { + zero_padding_insertion_ind += 2; + } + } + { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; + if (alternate_form && fmt_spec == 'o' +#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */ + && (str_arg_l > 0) +#endif +#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */ +#else + /* unless zero is already the first character */ + && !(zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '0') +#endif + ) { /* assure leading zero for alternate-form octal numbers */ + if (!precision_specified || precision < num_of_digits+1) { + /* precision is increased to force the first character to be zero, + except if a zero value is formatted with an explicit precision + of zero */ + precision = num_of_digits+1; precision_specified = 1; + } + } + /* zero padding to specified precision? */ + if (num_of_digits < precision) + number_of_zeros_to_pad = precision - num_of_digits; + } + /* zero padding to specified minimal field width? */ + if (!justify_left && zero_padding) { + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) number_of_zeros_to_pad += n; + } + break; + } + default: /* unrecognized conversion specifier, keep format string as-is*/ + zero_padding = 0; /* turn zero padding off for non-numeric convers. */ +#ifndef DIGITAL_UNIX_COMPATIBLE + justify_left = 1; min_field_width = 0; /* reset flags */ +#endif +#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE) + /* keep the entire format string unchanged */ + str_arg = starting_p; str_arg_l = p - starting_p; + /* well, not exactly so for Linux, which does something inbetween, + * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */ +#else + /* discard the unrecognized conversion, just keep * + * the unrecognized conversion character */ + str_arg = p; str_arg_l = 0; +#endif + if (*p) str_arg_l++; /* include invalid conversion specifier unchanged + if not at end-of-string */ + break; + } + if (*p) p++; /* step over the just processed conversion specifier */ + /* insert padding to the left as requested by min_field_width; + this does not include the zero padding in case of numerical conversions*/ + if (!justify_left) { /* left padding with blank or zero */ + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n)); + } + str_l += n; + } + } + /* zero padding as requested by the precision or by the minimal field width + * for numeric conversions required? */ + if (number_of_zeros_to_pad <= 0) { + /* will not copy first part of numeric right now, * + * force it to be copied later in its entirety */ + zero_padding_insertion_ind = 0; + } else { + /* insert first part of numerics (sign or '0x') before zero padding */ + int n = zero_padding_insertion_ind; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, str_arg, (n>avail?avail:n)); + } + str_l += n; + } + /* insert zero padding as requested by the precision or min field width */ + n = number_of_zeros_to_pad; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, '0', (n>avail?avail:n)); + } + str_l += n; + } + } + /* insert formatted string + * (or as-is conversion specifier for unknown conversions) */ + { int n = str_arg_l - zero_padding_insertion_ind; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, + (n>avail?avail:n)); + } + str_l += n; + } + } + /* insert right padding */ + if (justify_left) { /* right blank padding to the field width */ + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, ' ', (n>avail?avail:n)); + } + str_l += n; + } + } + } + } +#if defined(NEED_SNPRINTF_ONLY) + va_end(ap); +#endif + if (str_m > 0) { /* make sure the string is null-terminated + even at the expense of overwriting the last character + (shouldn't happen, but just in case) */ + str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; + } + /* Return the number of characters formatted (excluding trailing null + * character), that is, the number of characters that would have been + * written to the buffer if it were large enough. + * + * The value of str_l should be returned, but str_l is of unsigned type + * size_t, and snprintf is int, possibly leading to an undetected + * integer overflow, resulting in a negative return value, which is illegal. + * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. + * Should errno be set to EOVERFLOW and EOF returned in this case??? + */ + return (int) str_l; +} +#endif +#endif /* ndef HAVE_SNPRINTF */ +/* + Local Variables: + tab-width: 3 + end: +*/ diff --git a/src/arch/os2/src/dirport.h b/src/arch/os2/src/dirport.h index 617a41a..65a55eb 100644 --- a/src/arch/os2/src/dirport.h +++ b/src/arch/os2/src/dirport.h @@ -1,85 +1,84 @@ -/* - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - -#ifndef VICE_DIRPORT_H -#define VICE_DIRPORT_H - -#define INCL_DOS -#include -#include -#include - -#ifndef _A_VOLID -#define _A_VOLID 0 -#endif - -#ifndef _A_NORMAL -#define _A_NORMAL FILE_NORMAL -#endif - -#ifndef _A_RDONLY -#define _A_RDONLY FILE_READONLY -#endif - -#ifndef _A_HIDDEN -#define _A_HIDDEN FILE_HIDDEN -#endif - -#ifndef _A_SYSTEM -#define _A_SYSTEM FILE_SYSTEM -#endif - -#ifndef _A_SUBDIR -#define _A_SUBDIR FILE_DIRECTORY -#endif - -#ifndef _A_ARCH -#define _A_ARCH FILE_ARCHIVED -#endif - -#define _A_ANY FILE_NORMAL | FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED - -#ifndef EPERM -#define EPERM EDOM // Operation not permitted = Domain Error -#endif - -#define dirent _FILEFINDBUF3 -#define d_name achName /* For struct dirent portability */ -#define d_size cbFile - -#define mkdir(name, mode) mkdir(name) - -#ifndef WATCOM_COMPILE -#define S_ISDIR(mode) ((mode) & S_IFDIR) - -typedef struct _DIR { - struct dirent buffer; - HDIR handle; - APIRET ulrc; -} DIR; - -extern DIR *opendir(char *path); -extern struct dirent *readdir(DIR *dirp); -extern int closedir(DIR *dirp); -#endif - -#endif /* DIRPORT__H */ - \ No newline at end of file +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_DIRPORT_H +#define VICE_DIRPORT_H + +#define INCL_DOS +#include +#include +#include + +#ifndef _A_VOLID +#define _A_VOLID 0 +#endif + +#ifndef _A_NORMAL +#define _A_NORMAL FILE_NORMAL +#endif + +#ifndef _A_RDONLY +#define _A_RDONLY FILE_READONLY +#endif + +#ifndef _A_HIDDEN +#define _A_HIDDEN FILE_HIDDEN +#endif + +#ifndef _A_SYSTEM +#define _A_SYSTEM FILE_SYSTEM +#endif + +#ifndef _A_SUBDIR +#define _A_SUBDIR FILE_DIRECTORY +#endif + +#ifndef _A_ARCH +#define _A_ARCH FILE_ARCHIVED +#endif + +#define _A_ANY FILE_NORMAL | FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED + +#ifndef EPERM +#define EPERM EDOM // Operation not permitted = Domain Error +#endif + +#define dirent _FILEFINDBUF3 +#define d_name achName /* For struct dirent portability */ +#define d_size cbFile + +#define mkdir(name, mode) mkdir(name) + +#ifndef WATCOM_COMPILE +#define S_ISDIR(mode) ((mode) & S_IFDIR) + +typedef struct _DIR { + struct dirent buffer; + HDIR handle; + APIRET ulrc; +} DIR; + +extern DIR *opendir(char *path); +extern struct dirent *readdir(DIR *dirp); +extern int closedir(DIR *dirp); +#endif + +#endif /* DIRPORT__H */ diff --git a/src/atbridge/aarp.c b/src/atbridge/aarp.c index e2c682f..4fd5a96 100644 --- a/src/atbridge/aarp.c +++ b/src/atbridge/aarp.c @@ -1,302 +1,304 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements AARP, a necessary protocol for ELAP communication. **/ - -#include -#include -#include "../defc.h" -#include "atbridge.h" -#include "elap.h" -#include "port.h" -#include "elap_defs.h" -#include "aarp.h" - -#ifdef WIN32 -#include -#elif __linux__ -#include -#endif - -struct amt_entry_t -{ - struct at_addr_t protocol; - struct ether_addr_t hardware; - - struct amt_entry_t* next; -}; - -typedef struct amt_entry_t* amt_t; - -static amt_t amt = 0; - -static unsigned int retry_count; -static clock_t retry_timer; - - -void aarp_init() -{ - aarp_retry_reset(); -} - -void aarp_shutdown() -{ - struct amt_entry_t* entry = amt; - while (entry) - { - struct amt_entry_t* next = entry->next; - free(entry); - entry = next; - } -} - -//// - -static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr) -{ - if (source_at_addr && dest_at_addr && dest_hw_addr) - { - struct aarp_header_t response; - response.hardware_type = htons(AARP_HARDWARE_ETHER); - response.protocol_type = htons(AARP_PROTOCOL_TYPE); - response.hw_addr_len = AARP_HW_ADDR_LEN; - response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN; - response.function = htons(function); - - memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr)); - response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network); - response.source_proto_addr.zero = 0x00; - - memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr)); - response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network); - response.dest_proto_addr.zero = 0x00; - - memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac)); - - memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac)); - - if (dest_hw_addr == &HW_ZERO) - elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); - else - elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); - } -} - -void aarp_probe(const struct at_addr_t* addr) -{ - if (addr) - { - aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO); - } -} - -static void aarp_request(const struct at_addr_t* addr) -{ - if (addr) - { - aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO); - } -} - -//// - -static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware) -{ - if (hardware) - { - struct amt_entry_t* entry = amt; - while (entry) - { - if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0) - return entry; - entry = entry->next; - } - } - return 0; -} - -static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol) -{ - if (protocol) - { - struct amt_entry_t* entry = amt; - while (entry) - { - if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) - return entry; - entry = entry->next; - } - } - return 0; -} - -static void amt_delete_entry_protocol(const struct at_addr_t* protocol) -{ - if (protocol) - { - struct amt_entry_t* entry = amt; - struct amt_entry_t* previous = amt; - while (entry) - { - if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) - { - previous->next = entry->next; - free(entry); - break; - } - previous = entry; - entry = entry->next; - } - } -} - -static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) -{ - // Does an entry matching one of the protocol or hardware addresses exist? If so, update it. - struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); - if (entry) - { - memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); - return; - } - - entry = amt_lookup_entry_hardware(hardware); - if (entry) - { - memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); - return; - } - - // Otherwise, add a new entry. - entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t)); - memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); - memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); - entry->next = amt; - amt = entry; -} - -const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol) -{ - struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); - if (entry) - { - aarp_retry_reset(); - return (const struct ether_addr_t*)&entry->hardware; - } - else - { - // The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period. - if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) && - (retry_count > 0)) - { - aarp_request(protocol); - - retry_count--; - retry_timer = clock(); - - //atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer); - } - - return 0; - } -} - -const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware) -{ - struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware); - if (entry) - return (const struct at_addr_t*)&entry->protocol; - else - return 0; -} - -bool aarp_retry() -{ - return retry_count > 0; -} - -void aarp_retry_reset() -{ - retry_count = AARP_REQUEST_COUNT; - retry_timer = clock(); -} - -void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) -{ - amt_add(protocol, hardware); -} - -bool aarp_address_used(const struct at_addr_t* protocol) -{ - // reference 2-8 - if (protocol) - { - // Check for reserved node numbers, per reference 3-9. - if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff) - return true; - - // Look for the address in the AMT. If it's there, another node is using this address. - struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); - if (entry) - return true; - - // Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet. - // Return true to advise the caller that the address is not known to be in use. The caller should - // retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT), - // per the AARP protocol definition, before choosing this address. - aarp_probe(protocol); - return false; - } - return false; -} - -//// - -void aarp_handle_packet(const struct aarp_header_t* aarp) -{ - if (aarp && - aarp->hardware_type == AARP_HARDWARE_ETHER && - aarp->protocol_type == AARP_PROTOCOL_TYPE && - aarp->hw_addr_len == AARP_HW_ADDR_LEN && - aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN) - { - switch (aarp->function) - { - case AARP_FUNCTION_REQUEST: - if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) || - (aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) && - (aarp->dest_proto_addr.addr.node == atbridge_get_node())) - { - // Generate a response for the AARP request. - aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr); - } - break; - case AARP_FUNCTION_RESPONSE: - aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr); - aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr); - break; - case AARP_FUNCTION_PROBE: - // AMT entry aging, method 2, reference 2-11 - amt_delete_entry_protocol(&aarp->dest_proto_addr.addr); - break; - default: - break; - } - } -} +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements AARP, a necessary protocol for ELAP communication. **/ + +#include +#include +#include "../defc.h" +#include "atbridge.h" +#include "elap.h" +#include "port.h" +#include "elap_defs.h" +#include "aarp.h" + +#ifdef WIN32 +#include +#elif __linux__ +#include +#endif + +struct amt_entry_t +{ + struct at_addr_t protocol; + struct ether_addr_t hardware; + + struct amt_entry_t* next; +}; + +typedef struct amt_entry_t* amt_t; + +static amt_t amt = 0; + +static unsigned int retry_count; +static clock_t retry_timer; + + +void aarp_init() +{ + aarp_retry_reset(); +} + +void aarp_shutdown() +{ + struct amt_entry_t* entry = amt; + while (entry) + { + struct amt_entry_t* next = entry->next; + free(entry); + entry = next; + } +} + +//// + +static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr) +{ + if (source_at_addr && dest_at_addr && dest_hw_addr) + { + struct aarp_header_t response; + response.hardware_type = htons(AARP_HARDWARE_ETHER); + response.protocol_type = htons(AARP_PROTOCOL_TYPE); + response.hw_addr_len = AARP_HW_ADDR_LEN; + response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN; + response.function = htons(function); + + memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr)); + response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network); + response.source_proto_addr.zero = 0x00; + + memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr)); + response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network); + response.dest_proto_addr.zero = 0x00; + + memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac)); + + memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac)); + + if (dest_hw_addr == &HW_ZERO) + elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); + else + elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response); + } +} + +void aarp_probe(const struct at_addr_t* addr) +{ + if (addr) + { + aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO); + } +} + +static void aarp_request(const struct at_addr_t* addr) +{ + if (addr) + { + aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO); + } +} + +//// + +static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware) +{ + if (hardware) + { + struct amt_entry_t* entry = amt; + while (entry) + { + if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0) + return entry; + entry = entry->next; + } + } + return 0; +} + +static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol) +{ + if (protocol) + { + struct amt_entry_t* entry = amt; + while (entry) + { + if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) + return entry; + entry = entry->next; + } + } + return 0; +} + +static void amt_delete_entry_protocol(const struct at_addr_t* protocol) +{ + if (protocol) + { + struct amt_entry_t* entry = amt; + struct amt_entry_t* previous = amt; + while (entry) + { + if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0) + { + previous->next = entry->next; + free(entry); + break; + } + previous = entry; + entry = entry->next; + } + } +} + +static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) +{ + // Does an entry matching one of the protocol or hardware addresses exist? If so, update it. + struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); + if (entry) + { + memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); + return; + } + + entry = amt_lookup_entry_hardware(hardware); + if (entry) + { + memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); + return; + } + + // Otherwise, add a new entry. + entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t)); + memcpy(&entry->hardware, hardware, sizeof(entry->hardware)); + memcpy(&entry->protocol, protocol, sizeof(entry->protocol)); + entry->next = amt; + amt = entry; +} + +const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol) +{ + struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); + if (entry) + { + aarp_retry_reset(); + return (const struct ether_addr_t*)&entry->hardware; + } + else + { + // The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period. + if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) && + (retry_count > 0)) + { + aarp_request(protocol); + + retry_count--; + retry_timer = clock(); + + //atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer); + } + + return 0; + } +} + +const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware) +{ + struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware); + if (entry) + return (const struct at_addr_t*)&entry->protocol; + else + return 0; +} + +bool aarp_retry() +{ + return retry_count > 0; +} + +void aarp_retry_reset() +{ + retry_count = AARP_REQUEST_COUNT; + retry_timer = clock(); +} + +void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) +{ + amt_add(protocol, hardware); +} + +bool aarp_address_used(const struct at_addr_t* protocol) +{ + // reference 2-8 + if (protocol) + { + // Check for reserved node numbers, per reference 3-9. + if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff) + return true; + + // Look for the address in the AMT. If it's there, another node is using this address. + struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol); + if (entry) + return true; + + // Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet. + // Return true to advise the caller that the address is not known to be in use. The caller should + // retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT), + // per the AARP protocol definition, before choosing this address. + aarp_probe(protocol); + return false; + } + return false; +} + +//// + +void aarp_handle_packet(const struct aarp_header_t* aarp) +{ + if (aarp && + aarp->hardware_type == AARP_HARDWARE_ETHER && + aarp->protocol_type == AARP_PROTOCOL_TYPE && + aarp->hw_addr_len == AARP_HW_ADDR_LEN && + aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN) + { + switch (aarp->function) + { + case AARP_FUNCTION_REQUEST: + if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) || + (aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) && + (aarp->dest_proto_addr.addr.node == atbridge_get_node())) + { + // Generate a response for the AARP request. + aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr); + } + break; + case AARP_FUNCTION_RESPONSE: + aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr); + aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr); + break; + case AARP_FUNCTION_PROBE: + // AMT entry aging, method 2, reference 2-11 + amt_delete_entry_protocol(&aarp->dest_proto_addr.addr); + break; + default: + break; + } + } +} diff --git a/src/atbridge/aarp.h b/src/atbridge/aarp.h index 2cfed75..6b0e7d3 100644 --- a/src/atbridge/aarp.h +++ b/src/atbridge/aarp.h @@ -1,37 +1,39 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct at_addr_t; -struct aarp_header_t; -struct ether_addr_t; - -void aarp_init(); -void aarp_shutdown(); - -const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol); -const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware); - -bool aarp_retry(); -void aarp_retry_reset(); - -void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware); - -bool aarp_address_used(const struct at_addr_t* protocol); - -void aarp_handle_packet(const struct aarp_header_t* aarp); \ No newline at end of file +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct at_addr_t; +struct aarp_header_t; +struct ether_addr_t; + +void aarp_init(); +void aarp_shutdown(); + +const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol); +const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware); + +bool aarp_retry(); +void aarp_retry_reset(); + +void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware); + +bool aarp_address_used(const struct at_addr_t* protocol); + +void aarp_handle_packet(const struct aarp_header_t* aarp); diff --git a/src/atbridge/atalk.h b/src/atbridge/atalk.h index 6ecd70c..f4c14ac 100644 --- a/src/atbridge/atalk.h +++ b/src/atbridge/atalk.h @@ -1,137 +1,139 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -typedef byte at_node_t; -static const at_node_t at_broadcast_node = 0xFF; - -typedef word16 at_network_t; - -#pragma pack(push, 1) -struct at_addr_t -{ - at_network_t network; - at_node_t node; -}; -#pragma pack(pop) - -enum LAP_TYPES { /* reference C-6 */ - LAP_DDP_SHORT = 0x01, - LAP_DDP_LONG = 0x02 -}; - -enum DDP_SOCKETS { /* reference C-7 */ - DDP_SOCKET_INVALID_00 = 0x00, - DDP_SOCKET_RTMP = 0x01, - DDP_SOCKET_NIS = 0x02, - DDP_SOCKET_ECHO = 0x04, - DDP_SOCKET_ZIS = 0x06, - DDP_SOCKET_INVALID_FF = 0xFF, -}; - -enum DDP_TYPES { /* reference C-6 */ - DDP_TYPE_INVALID = 0x00, - DDP_TYPE_RTMP = 0x01, - DDP_TYPE_NBP = 0x02, - DDP_TYPE_ATP = 0x03, - DDP_TYPE_AEP = 0x04, - DDP_TYPE_RTMP_REQUEST = 0x05, - DDP_TYPE_ZIP = 0x06, - DDP_TYPE_ADSP = 0x07, - DDP_TYPE_RESERVED_08 = 0x08, - DDP_TYPE_RESERVED_09 = 0x09, - DDP_TYPE_RESERVED_0A = 0x0A, - DDP_TYPE_RESERVED_0B = 0x0B, - DDP_TYPE_RESERVED_0C = 0x0C, - DDP_TYPE_RESERVED_0D = 0x0D, - DDP_TYPE_RESERVED_0E = 0x0E, - DDP_TYPE_RESERVED_0F = 0x0F -}; - -#pragma pack(push, 1) -struct DDP_LONG -{ - byte length[2]; - word16 checksum; - at_network_t dest_net; - at_network_t source_net; - at_node_t dest_node; - at_node_t source_node; - byte dest_socket; - byte source_socket; - byte type; -}; - -struct DDP_SHORT -{ - byte length[2]; - byte dest_socket; - byte source_socket; - byte type; -}; - -enum RTMP_FUNCTIONS { /* reference C-8*/ - RTMP_FUNCTION_REQUEST = 0x01, - RTMP_FUNCTION_RDR_SPLIT = 0x02, - RTMP_FUNCTION_RDR_NO_SPLIT = 0x03 -}; - -struct rtmp_request_t -{ - byte function; -}; - -struct rtmp_nonextended_data_t -{ - at_network_t net; - byte id_length; - at_node_t node; - word16 zero; - byte delimiter; -}; - -struct rtmp_nonextended_response_t -{ - at_network_t net; - byte id_length; - at_node_t node; -}; - -struct rtmp_extended_data_t -{ - at_network_t net; - byte id_length; - at_node_t node; -}; - -struct rtmp_nonextended_tuple_t -{ - at_network_t net; - byte distance; -}; - -struct rtmp_extended_tuple_t -{ - at_network_t range_start; - byte distance; - at_network_t range_end; - byte delimiter; -}; - -static const byte RTMP_TUPLE_DELIMITER = 0x82; -#pragma pack(pop) \ No newline at end of file +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +typedef byte at_node_t; +static const at_node_t at_broadcast_node = 0xFF; + +typedef word16 at_network_t; + +#pragma pack(push, 1) +struct at_addr_t +{ + at_network_t network; + at_node_t node; +}; +#pragma pack(pop) + +enum LAP_TYPES { /* reference C-6 */ + LAP_DDP_SHORT = 0x01, + LAP_DDP_LONG = 0x02 +}; + +enum DDP_SOCKETS { /* reference C-7 */ + DDP_SOCKET_INVALID_00 = 0x00, + DDP_SOCKET_RTMP = 0x01, + DDP_SOCKET_NIS = 0x02, + DDP_SOCKET_ECHO = 0x04, + DDP_SOCKET_ZIS = 0x06, + DDP_SOCKET_INVALID_FF = 0xFF, +}; + +enum DDP_TYPES { /* reference C-6 */ + DDP_TYPE_INVALID = 0x00, + DDP_TYPE_RTMP = 0x01, + DDP_TYPE_NBP = 0x02, + DDP_TYPE_ATP = 0x03, + DDP_TYPE_AEP = 0x04, + DDP_TYPE_RTMP_REQUEST = 0x05, + DDP_TYPE_ZIP = 0x06, + DDP_TYPE_ADSP = 0x07, + DDP_TYPE_RESERVED_08 = 0x08, + DDP_TYPE_RESERVED_09 = 0x09, + DDP_TYPE_RESERVED_0A = 0x0A, + DDP_TYPE_RESERVED_0B = 0x0B, + DDP_TYPE_RESERVED_0C = 0x0C, + DDP_TYPE_RESERVED_0D = 0x0D, + DDP_TYPE_RESERVED_0E = 0x0E, + DDP_TYPE_RESERVED_0F = 0x0F +}; + +#pragma pack(push, 1) +struct DDP_LONG +{ + byte length[2]; + word16 checksum; + at_network_t dest_net; + at_network_t source_net; + at_node_t dest_node; + at_node_t source_node; + byte dest_socket; + byte source_socket; + byte type; +}; + +struct DDP_SHORT +{ + byte length[2]; + byte dest_socket; + byte source_socket; + byte type; +}; + +enum RTMP_FUNCTIONS { /* reference C-8*/ + RTMP_FUNCTION_REQUEST = 0x01, + RTMP_FUNCTION_RDR_SPLIT = 0x02, + RTMP_FUNCTION_RDR_NO_SPLIT = 0x03 +}; + +struct rtmp_request_t +{ + byte function; +}; + +struct rtmp_nonextended_data_t +{ + at_network_t net; + byte id_length; + at_node_t node; + word16 zero; + byte delimiter; +}; + +struct rtmp_nonextended_response_t +{ + at_network_t net; + byte id_length; + at_node_t node; +}; + +struct rtmp_extended_data_t +{ + at_network_t net; + byte id_length; + at_node_t node; +}; + +struct rtmp_nonextended_tuple_t +{ + at_network_t net; + byte distance; +}; + +struct rtmp_extended_tuple_t +{ + at_network_t range_start; + byte distance; + at_network_t range_end; + byte delimiter; +}; + +static const byte RTMP_TUPLE_DELIMITER = 0x82; +#pragma pack(pop) diff --git a/src/atbridge/atbridge.c b/src/atbridge/atbridge.c index b30a617..b3ac5e6 100644 --- a/src/atbridge/atbridge.c +++ b/src/atbridge/atbridge.c @@ -1,426 +1,428 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module is the "heart" of the bridge and provides the connection between the ELAP and LLAP ports. **/ - -#include -#include "../defc.h" -#include -#include -#include "atbridge.h" -#include "port.h" -#include "elap.h" -#include "llap.h" -#include "aarp.h" - -#ifdef WIN32 -#include -#elif __linux__ -#include -#endif - -extern struct packet_port_t elap_port; - -static bool diagnostics = false; -static bool sent_rtmp_request = false; - -static struct at_addr_t local_address = { 0, 0 }; - -static const at_network_t NET_STARTUP_LOW = 0xFF00; -static const at_network_t NET_STARTUP_HIGH = 0xFFFE; -static const at_node_t NODE_STARTUP_LOW = 0x01; -static const at_node_t NODE_STARTUP_HIGH = 0xFE; - -static void send_rtmp_request(); - -bool atbridge_init() -{ - // If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT. - if (local_address.network == 0) - { - // Obtain a provisional node address and startup range network. - // - // This isn't correct for an extended network (like ELAP) but works adequately on small networks. - // The bridge should follow the complicated process on page 4-9 to obtain the network and node number. - srand((unsigned int)time(0)); - local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW); - local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01); - - aarp_init(); - llap_init(); - if (!elap_init()) - { - atbridge_shutdown(); - return false; - } - } - return true; -} - -void atbridge_shutdown() -{ - llap_shutdown(); - elap_shutdown(); - aarp_shutdown(); -} - -void atbridge_set_diagnostics(bool enabled) -{ - diagnostics = enabled; -} - -bool atbridge_get_diagnostics() -{ - return diagnostics; -} - -void atbridge_printf(const char *fmt, ...) -{ - if (atbridge_get_diagnostics()) - { - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - } -} - -const struct at_addr_t* atbridge_get_addr() -{ - return &local_address; -} - -const at_network_t atbridge_get_net() -{ - return local_address.network; -} - -const at_node_t atbridge_get_node() -{ - return local_address.node; -} - -void atbridge_set_net(at_network_t net) -{ - local_address.network = net; -} - -void atbridge_set_node(at_node_t node) -{ - local_address.node = node; -} - -bool atbridge_address_used(const struct at_addr_t* addr) -{ - if (!sent_rtmp_request) - send_rtmp_request(); - return aarp_address_used(addr); -} - -/* Calculate a DDP checksum, per Apple's documented algorithm in 4-17 of "Inside AppleTalk". */ -static word16 get_checksum(size_t size, byte data[]) -{ - word16 cksum = 0; - for (unsigned int i = 0; i < size; i++) - { - cksum += data[i]; - cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left - } - if (cksum == 0) - cksum = 0xffff; - return cksum; -} - -static void calculate_checksum(struct packet_t* packet) -{ - if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG)) - { - struct DDP_LONG* header = (struct DDP_LONG*)(packet->data); - header->checksum = htons(get_checksum( - packet->size - offsetof(struct DDP_LONG, dest_net), - (byte*)&header->dest_net)); - } -} - -/* Convert a long-form DDP header to a short-form header. This function only converts the headers. */ -static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out) -{ - word16 size; - - if (!in || !out) - return 0; - - size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); - - out->length[0] = (size >> 8) & 0x03; - out->length[1] = size & 0xff; - - out->dest_socket = in->dest_socket; - out->source_socket = in->source_socket; - - out->type = in->type; - - return size; -} - -/* Convert a short-form DDP header to a long-form header. ELAP requires long-form, but LLAP often uses short-form. */ -/* This function only converts the headers. */ -static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out) -{ - word16 size; - - if (!in || !out) - return 0; - - size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); - out->length[0] = (size >> 8) & 0x03; - out->length[1] = size & 0xff; - - out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */ - - if (dest.network) - out->dest_net = dest.network; - else - out->dest_net = atbridge_get_net(); - out->dest_net = (at_network_t)htons(out->dest_net); - - if (source.network) - out->source_net = source.network; - else - out->source_net = atbridge_get_net(); - out->source_net = (at_network_t)htons(out->source_net); - - out->dest_node = dest.node; - out->source_node = source.node; - - out->dest_socket = in->dest_socket; - out->source_socket = in->source_socket; - - out->type = in->type; - - return size; -} - -/* Convert a short-form DDP packet to a long-form packet. */ -/* This function converts an entire packet, not just the header. */ -static void convert_ddp_packet_to_long(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT))) - { - struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; - - const size_t payload_size = packet->size - sizeof(struct DDP_SHORT); - byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG)); - struct DDP_LONG* header_long = (struct DDP_LONG*)data; - - const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); - packet->dest.network = ntohs(header_long->dest_net); - packet->source.network = ntohs(header_long->source_net); - - memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size); - - packet->type = LAP_DDP_LONG; - packet->size = size; - - // Replace the original short-form packet data. - free(packet->data); - packet->data = data; - - calculate_checksum(packet); - } -} - -/* Convert a long-form DDP packet to short-form. */ -static void convert_ddp_packet_to_short(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_LONG) && packet->data) - { - struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; - - const size_t payload_size = packet->size - sizeof(struct DDP_LONG); - byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT)); - struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; - - const word16 size = convert_ddp_header_to_short(header_long, header_short); - - memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size); - - packet->type = LAP_DDP_SHORT; - packet->size = size; - - free(packet->data); - packet->data = data; - } -} - -/*static void convert_rtmp_to_extended(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_SHORT) && packet->data) - { - struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; - if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP) - return; - - struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT)); - - // Construct a new long-form DDP packet header. - size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t); - byte* data = (byte*)malloc(size); - struct DDP_LONG* header_long = (struct DDP_LONG*)data; - convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); - - struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG)); - out->net = in->net; - out->id_length = in->id_length; - out->node = in->node; - - // Copy the routing tuples. - struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t)); - struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size); - while ((byte*)in_tuple < (packet->data + packet->size)) - { - size += sizeof(struct rtmp_extended_tuple_t); - realloc(data, size); - out_tuple->range_start = in_tuple->net; - out_tuple->distance = in_tuple->distance | 0x80; - out_tuple->range_end = in_tuple->net; - out_tuple->delimiter = RTMP_TUPLE_DELIMITER; - in_tuple++; - } - - free(packet->data); - packet->data = data; - packet->size = size; - packet->type = LAP_DDP_LONG; - } -}*/ - -static void convert_rtmp_to_nonextended(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_LONG) && packet->data) - { - struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; - if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) - return; - - struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); - - size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t); - byte* data = (byte*)malloc(size); - struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; - convert_ddp_header_to_short(header_long, header_short); - header_short->length[0] = (size >> 8) & 0x03; - header_short->length[1] = size & 0xff; - - struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT)); - out->net = in->net; - out->id_length = in->id_length; - out->node = in->node; - - /*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t)); - rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size); - while ((byte*)in_tuple < (packet->data + packet->size)) - { - size += sizeof(rtmp_nonextended_tuple_t); - realloc(data, size); - out_tuple->net = in_tuple->range_start; - out_tuple->distance = in_tuple->distance & 0x7f; - in_tuple++; - }*/ - - free(packet->data); - packet->data = data; - packet->size = size; - packet->type = LAP_DDP_SHORT; - } -} - -/* Learn our network number from RTMP packets. */ -/* "Inside AppleTalk", section 4-8, describes this approach for non-extended networks. - Technically, we probably should be doing the more complicated extended network approach (also on 4-8), - but the easy approach using RTMP seems adequate for now. */ -static void glean_net_from_rtmp(struct packet_t* packet) -{ - if (packet && (packet->type == LAP_DDP_LONG) && packet->data) - { - struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; - if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) - return; - - struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); - - atbridge_set_net(ntohs(in->net)); - } -} - -static void send_rtmp_request() -{ - struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); - - packet->type = LAP_DDP_LONG; - packet->dest.network = atbridge_get_net(); - packet->dest.node = 255; - packet->source.network = atbridge_get_net(); - packet->source.node = atbridge_get_node(); - packet->next = 0; - packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t); - packet->data = (byte*)malloc(packet->size); - - struct DDP_LONG* header = (struct DDP_LONG*)packet->data; - header->type = DDP_TYPE_RTMP_REQUEST; - header->source_net = htons(packet->source.network); - header->source_node = packet->source.node; - header->source_socket = DDP_SOCKET_RTMP; - header->dest_net = htons(packet->dest.network); - header->dest_node = packet->dest.node; - header->dest_socket = DDP_SOCKET_RTMP; - header->length[0] = (packet->size >> 8) & 0x03; - header->length[1] = packet->size & 0xff; - - struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG)); - request->function = RTMP_FUNCTION_REQUEST; - - calculate_checksum(packet); - - elap_enqueue_out(packet); - sent_rtmp_request = true; -} - -void atbridge_process() -{ - elap_process(); - //llap_process(); - - struct packet_t* packet = elap_dequeue_in(); - if (packet) - { - glean_net_from_rtmp(packet); - convert_rtmp_to_nonextended(packet); - // The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process). - convert_ddp_packet_to_short(packet); - llap_enqueue_out(packet); - } - packet = llap_dequeue_in(); - if (packet) - { - // ELAP does not support short-form DDP, so convert such packets to long-form. - convert_ddp_packet_to_long(packet); - elap_enqueue_out(packet); - } -} \ No newline at end of file +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module is the "heart" of the bridge and provides the connection between the ELAP and LLAP ports. **/ + +#include +#include "../defc.h" +#include +#include +#include "atbridge.h" +#include "port.h" +#include "elap.h" +#include "llap.h" +#include "aarp.h" + +#ifdef WIN32 +#include +#elif __linux__ +#include +#endif + +extern struct packet_port_t elap_port; + +static bool diagnostics = false; +static bool sent_rtmp_request = false; + +static struct at_addr_t local_address = { 0, 0 }; + +static const at_network_t NET_STARTUP_LOW = 0xFF00; +static const at_network_t NET_STARTUP_HIGH = 0xFFFE; +static const at_node_t NODE_STARTUP_LOW = 0x01; +static const at_node_t NODE_STARTUP_HIGH = 0xFE; + +static void send_rtmp_request(); + +bool atbridge_init() +{ + // If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT. + if (local_address.network == 0) + { + // Obtain a provisional node address and startup range network. + // + // This isn't correct for an extended network (like ELAP) but works adequately on small networks. + // The bridge should follow the complicated process on page 4-9 to obtain the network and node number. + srand((unsigned int)time(0)); + local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW); + local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01); + + aarp_init(); + llap_init(); + if (!elap_init()) + { + atbridge_shutdown(); + return false; + } + } + return true; +} + +void atbridge_shutdown() +{ + llap_shutdown(); + elap_shutdown(); + aarp_shutdown(); +} + +void atbridge_set_diagnostics(bool enabled) +{ + diagnostics = enabled; +} + +bool atbridge_get_diagnostics() +{ + return diagnostics; +} + +void atbridge_printf(const char *fmt, ...) +{ + if (atbridge_get_diagnostics()) + { + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + } +} + +const struct at_addr_t* atbridge_get_addr() +{ + return &local_address; +} + +const at_network_t atbridge_get_net() +{ + return local_address.network; +} + +const at_node_t atbridge_get_node() +{ + return local_address.node; +} + +void atbridge_set_net(at_network_t net) +{ + local_address.network = net; +} + +void atbridge_set_node(at_node_t node) +{ + local_address.node = node; +} + +bool atbridge_address_used(const struct at_addr_t* addr) +{ + if (!sent_rtmp_request) + send_rtmp_request(); + return aarp_address_used(addr); +} + +/* Calculate a DDP checksum, per Apple's documented algorithm in 4-17 of "Inside AppleTalk". */ +static word16 get_checksum(size_t size, byte data[]) +{ + word16 cksum = 0; + for (unsigned int i = 0; i < size; i++) + { + cksum += data[i]; + cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left + } + if (cksum == 0) + cksum = 0xffff; + return cksum; +} + +static void calculate_checksum(struct packet_t* packet) +{ + if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG)) + { + struct DDP_LONG* header = (struct DDP_LONG*)(packet->data); + header->checksum = htons(get_checksum( + packet->size - offsetof(struct DDP_LONG, dest_net), + (byte*)&header->dest_net)); + } +} + +/* Convert a long-form DDP header to a short-form header. This function only converts the headers. */ +static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out) +{ + word16 size; + + if (!in || !out) + return 0; + + size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); + + out->length[0] = (size >> 8) & 0x03; + out->length[1] = size & 0xff; + + out->dest_socket = in->dest_socket; + out->source_socket = in->source_socket; + + out->type = in->type; + + return size; +} + +/* Convert a short-form DDP header to a long-form header. ELAP requires long-form, but LLAP often uses short-form. */ +/* This function only converts the headers. */ +static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out) +{ + word16 size; + + if (!in || !out) + return 0; + + size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT)); + out->length[0] = (size >> 8) & 0x03; + out->length[1] = size & 0xff; + + out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */ + + if (dest.network) + out->dest_net = dest.network; + else + out->dest_net = atbridge_get_net(); + out->dest_net = (at_network_t)htons(out->dest_net); + + if (source.network) + out->source_net = source.network; + else + out->source_net = atbridge_get_net(); + out->source_net = (at_network_t)htons(out->source_net); + + out->dest_node = dest.node; + out->source_node = source.node; + + out->dest_socket = in->dest_socket; + out->source_socket = in->source_socket; + + out->type = in->type; + + return size; +} + +/* Convert a short-form DDP packet to a long-form packet. */ +/* This function converts an entire packet, not just the header. */ +static void convert_ddp_packet_to_long(struct packet_t* packet) +{ + if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT))) + { + struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; + + const size_t payload_size = packet->size - sizeof(struct DDP_SHORT); + byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG)); + struct DDP_LONG* header_long = (struct DDP_LONG*)data; + + const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); + packet->dest.network = ntohs(header_long->dest_net); + packet->source.network = ntohs(header_long->source_net); + + memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size); + + packet->type = LAP_DDP_LONG; + packet->size = size; + + // Replace the original short-form packet data. + free(packet->data); + packet->data = data; + + calculate_checksum(packet); + } +} + +/* Convert a long-form DDP packet to short-form. */ +static void convert_ddp_packet_to_short(struct packet_t* packet) +{ + if (packet && (packet->type == LAP_DDP_LONG) && packet->data) + { + struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; + + const size_t payload_size = packet->size - sizeof(struct DDP_LONG); + byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT)); + struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; + + const word16 size = convert_ddp_header_to_short(header_long, header_short); + + memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size); + + packet->type = LAP_DDP_SHORT; + packet->size = size; + + free(packet->data); + packet->data = data; + } +} + +/*static void convert_rtmp_to_extended(struct packet_t* packet) +{ + if (packet && (packet->type == LAP_DDP_SHORT) && packet->data) + { + struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data; + if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP) + return; + + struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT)); + + // Construct a new long-form DDP packet header. + size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t); + byte* data = (byte*)malloc(size); + struct DDP_LONG* header_long = (struct DDP_LONG*)data; + convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long); + + struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG)); + out->net = in->net; + out->id_length = in->id_length; + out->node = in->node; + + // Copy the routing tuples. + struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t)); + struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size); + while ((byte*)in_tuple < (packet->data + packet->size)) + { + size += sizeof(struct rtmp_extended_tuple_t); + realloc(data, size); + out_tuple->range_start = in_tuple->net; + out_tuple->distance = in_tuple->distance | 0x80; + out_tuple->range_end = in_tuple->net; + out_tuple->delimiter = RTMP_TUPLE_DELIMITER; + in_tuple++; + } + + free(packet->data); + packet->data = data; + packet->size = size; + packet->type = LAP_DDP_LONG; + } +}*/ + +static void convert_rtmp_to_nonextended(struct packet_t* packet) +{ + if (packet && (packet->type == LAP_DDP_LONG) && packet->data) + { + struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; + if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) + return; + + struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); + + size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t); + byte* data = (byte*)malloc(size); + struct DDP_SHORT* header_short = (struct DDP_SHORT*)data; + convert_ddp_header_to_short(header_long, header_short); + header_short->length[0] = (size >> 8) & 0x03; + header_short->length[1] = size & 0xff; + + struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT)); + out->net = in->net; + out->id_length = in->id_length; + out->node = in->node; + + /*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t)); + rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size); + while ((byte*)in_tuple < (packet->data + packet->size)) + { + size += sizeof(rtmp_nonextended_tuple_t); + realloc(data, size); + out_tuple->net = in_tuple->range_start; + out_tuple->distance = in_tuple->distance & 0x7f; + in_tuple++; + }*/ + + free(packet->data); + packet->data = data; + packet->size = size; + packet->type = LAP_DDP_SHORT; + } +} + +/* Learn our network number from RTMP packets. */ +/* "Inside AppleTalk", section 4-8, describes this approach for non-extended networks. + Technically, we probably should be doing the more complicated extended network approach (also on 4-8), + but the easy approach using RTMP seems adequate for now. */ +static void glean_net_from_rtmp(struct packet_t* packet) +{ + if (packet && (packet->type == LAP_DDP_LONG) && packet->data) + { + struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data; + if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP) + return; + + struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG)); + + atbridge_set_net(ntohs(in->net)); + } +} + +static void send_rtmp_request() +{ + struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); + + packet->type = LAP_DDP_LONG; + packet->dest.network = atbridge_get_net(); + packet->dest.node = 255; + packet->source.network = atbridge_get_net(); + packet->source.node = atbridge_get_node(); + packet->next = 0; + packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t); + packet->data = (byte*)malloc(packet->size); + + struct DDP_LONG* header = (struct DDP_LONG*)packet->data; + header->type = DDP_TYPE_RTMP_REQUEST; + header->source_net = htons(packet->source.network); + header->source_node = packet->source.node; + header->source_socket = DDP_SOCKET_RTMP; + header->dest_net = htons(packet->dest.network); + header->dest_node = packet->dest.node; + header->dest_socket = DDP_SOCKET_RTMP; + header->length[0] = (packet->size >> 8) & 0x03; + header->length[1] = packet->size & 0xff; + + struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG)); + request->function = RTMP_FUNCTION_REQUEST; + + calculate_checksum(packet); + + elap_enqueue_out(packet); + sent_rtmp_request = true; +} + +void atbridge_process() +{ + elap_process(); + //llap_process(); + + struct packet_t* packet = elap_dequeue_in(); + if (packet) + { + glean_net_from_rtmp(packet); + convert_rtmp_to_nonextended(packet); + // The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process). + convert_ddp_packet_to_short(packet); + llap_enqueue_out(packet); + } + packet = llap_dequeue_in(); + if (packet) + { + // ELAP does not support short-form DDP, so convert such packets to long-form. + convert_ddp_packet_to_long(packet); + elap_enqueue_out(packet); + } +} diff --git a/src/atbridge/atbridge.h b/src/atbridge/atbridge.h index 5098d56..16a0a45 100644 --- a/src/atbridge/atbridge.h +++ b/src/atbridge/atbridge.h @@ -1,47 +1,49 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** -ATBridge is a limited function AppleTalk bridge that allows GSPort to connect to an -EtherTalk network. The bridge has two ports, one the emulated LocalTalk port and the -other an EtherTalk Phase II port. - -Due to timing requirements of LocalTalk, it is not reasonable to transparently bridge -LLAP traffic to ELAP. For example, implementing the lapENQ/lapACK LLAP control packets -requires AARP queries on the ELAP port, which can't be reasonably done within the 200us -LLAP interframe gap. So, we must implement the local bridge functionality detailed -in "Inside AppleTalk", including AARP, RTMP, ZIP, and DDP routing. -**/ -#include "atalk.h" - -bool atbridge_init(); -void atbridge_shutdown(); -void atbridge_process(); - -void atbridge_set_diagnostics(bool enabled); -bool atbridge_get_diagnostics(); -void atbridge_printf(const char *fmt, ...); - -const struct at_addr_t* atbridge_get_addr(); -const at_network_t atbridge_get_net(); -const at_node_t atbridge_get_node(); -void atbridge_set_net(at_network_t net); -void atbridge_set_node(at_node_t node); -bool atbridge_address_used(const struct at_addr_t* addr); - +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** +ATBridge is a limited function AppleTalk bridge that allows GSPort to connect to an +EtherTalk network. The bridge has two ports, one the emulated LocalTalk port and the +other an EtherTalk Phase II port. + +Due to timing requirements of LocalTalk, it is not reasonable to transparently bridge +LLAP traffic to ELAP. For example, implementing the lapENQ/lapACK LLAP control packets +requires AARP queries on the ELAP port, which can't be reasonably done within the 200us +LLAP interframe gap. So, we must implement the local bridge functionality detailed +in "Inside AppleTalk", including AARP, RTMP, ZIP, and DDP routing. +**/ +#include "atalk.h" + +bool atbridge_init(); +void atbridge_shutdown(); +void atbridge_process(); + +void atbridge_set_diagnostics(bool enabled); +bool atbridge_get_diagnostics(); +void atbridge_printf(const char *fmt, ...); + +const struct at_addr_t* atbridge_get_addr(); +const at_network_t atbridge_get_net(); +const at_node_t atbridge_get_node(); +void atbridge_set_net(at_network_t net); +void atbridge_set_node(at_node_t node); +bool atbridge_address_used(const struct at_addr_t* addr); + diff --git a/src/atbridge/atbridge.vcxproj b/src/atbridge/atbridge.vcxproj index 244ff40..8654124 100644 --- a/src/atbridge/atbridge.vcxproj +++ b/src/atbridge/atbridge.vcxproj @@ -1,108 +1,108 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - - - - - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} - Win32Proj - atbridge - - - - StaticLibrary - true - v120 - MultiByte - - - StaticLibrary - false - v120 - true - MultiByte - - - - - - - - - - - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - Default - false - - - Windows - true - - - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - Speed - StreamingSIMDExtensions2 - Default - - - Windows - true - true - true - - - %(AdditionalDependencies) - - - - - - \ No newline at end of file + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} + Win32Proj + atbridge + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Default + false + + + Windows + true + + + %(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Speed + StreamingSIMDExtensions2 + Default + + + Windows + true + true + true + + + %(AdditionalDependencies) + + + + + + diff --git a/src/atbridge/atbridge.vcxproj.filters b/src/atbridge/atbridge.vcxproj.filters index 1c12228..3cbdd44 100644 --- a/src/atbridge/atbridge.vcxproj.filters +++ b/src/atbridge/atbridge.vcxproj.filters @@ -1,66 +1,66 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/src/atbridge/elap.c b/src/atbridge/elap.c index 3a155d1..5e8fb8b 100644 --- a/src/atbridge/elap.c +++ b/src/atbridge/elap.c @@ -1,398 +1,400 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements the ELAP port of the bridge. **/ - -#include -#include "../defc.h" -#include "atbridge.h" -#include "elap.h" -#include "port.h" -#include "aarp.h" -#include "elap_defs.h" -#include "pcap_delay.h" - -#ifdef __CYGWIN__ -#include -#include -#endif -#ifdef WIN32 -#include -#include -#endif -#ifdef __linux__ -#include -#include -#endif - -extern int g_ethernet_interface; - -static pcap_t* pcap_session; - -static struct packet_port_t elap_port; -static struct ether_addr_t HW_LOCAL; - -/*static void dump_device_list(pcap_if_t* devices) -{ - int i = 0; - for(pcap_if_t* device = devices; device; device = device->next) - { - printf("%d. %s", ++i, device->name); - if (device->description) - printf(" (%s)\n", device->description); - else - printf(" (No description available)\n"); - } -}*/ - -static void elap_clone_host_mac(pcap_if_t* device) -{ - if (!device) - return; - -#ifdef WIN32 - //// - // Extract the device GUID, which Windows uses to identify the device. - char* name = device->name; - while (name && *name != '{') - name++; - size_t guidLen = strlen(name); - - //// - // Find and copy the device MAC address. - ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15; - IP_ADAPTER_ADDRESSES* addresses = malloc(size); - - ULONG result = GetAdaptersAddresses(AF_UNSPEC, - GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); - - if (result == ERROR_BUFFER_OVERFLOW) - { - // The addresses buffer is too small. Allocate a bigger buffer. - free(addresses); - addresses = malloc(size); - result = GetAdaptersAddresses(AF_UNSPEC, - GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); - } - - if (result == NO_ERROR) - { - // Search for the desired adapter address. - IP_ADAPTER_ADDRESSES* current = addresses; - while (current) - { - if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0) - { - memcpy(&HW_LOCAL.mac, ¤t->PhysicalAddress, sizeof(HW_LOCAL.mac)); - break; - } - current = current->Next; - } - } - else - { - halt_printf("ATBridge: Failed to find host MAC address (%d).", result); - } - - free(addresses); -#else +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements the ELAP port of the bridge. **/ + +#include +#include "../defc.h" +#include "atbridge.h" +#include "elap.h" +#include "port.h" +#include "aarp.h" +#include "elap_defs.h" +#include "pcap_delay.h" + +#ifdef __CYGWIN__ +#include +#include +#endif +#ifdef WIN32 +#include +#include +#endif +#ifdef __linux__ +#include +#include +#endif + +extern int g_ethernet_interface; + +static pcap_t* pcap_session; + +static struct packet_port_t elap_port; +static struct ether_addr_t HW_LOCAL; + +/*static void dump_device_list(pcap_if_t* devices) +{ + int i = 0; + for(pcap_if_t* device = devices; device; device = device->next) + { + printf("%d. %s", ++i, device->name); + if (device->description) + printf(" (%s)\n", device->description); + else + printf(" (No description available)\n"); + } +}*/ + +static void elap_clone_host_mac(pcap_if_t* device) +{ + if (!device) + return; + +#ifdef WIN32 + //// + // Extract the device GUID, which Windows uses to identify the device. + char* name = device->name; + while (name && *name != '{') + name++; + size_t guidLen = strlen(name); + + //// + // Find and copy the device MAC address. + ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15; + IP_ADAPTER_ADDRESSES* addresses = malloc(size); + + ULONG result = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); + + if (result == ERROR_BUFFER_OVERFLOW) + { + // The addresses buffer is too small. Allocate a bigger buffer. + free(addresses); + addresses = malloc(size); + result = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size); + } + + if (result == NO_ERROR) + { + // Search for the desired adapter address. + IP_ADAPTER_ADDRESSES* current = addresses; + while (current) + { + if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0) + { + memcpy(&HW_LOCAL.mac, ¤t->PhysicalAddress, sizeof(HW_LOCAL.mac)); + break; + } + current = current->Next; + } + } + else + { + halt_printf("ATBridge: Failed to find host MAC address (%d).", result); + } + + free(addresses); +#else #ifdef AF_PACKET - struct pcap_addr* address; - for (address = device->addresses; address != 0; address = address->next) - if (address->addr->sa_family == AF_PACKET) - { - struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr; - memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac)); - } + struct pcap_addr* address; + for (address = device->addresses; address != 0; address = address->next) + if (address->addr->sa_family == AF_PACKET) + { + struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr; + memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac)); + } #endif -#endif -} - -const struct ether_addr_t* elap_get_mac() -{ - return &HW_LOCAL; -} - -bool elap_init() -{ - port_init(&elap_port); - - memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL)); - - pcap_if_t* device; - pcap_if_t* alldevs; - int i = 0; - - char errbuf[PCAP_ERRBUF_SIZE]; - - // Load the PCAP library. - if (!pcapdelay_load()) - { - halt_printf("ATBridge: PCAP not available.\n"); - return false; - } - - // Retrieve the device list. - if(pcapdelay_findalldevs(&alldevs, errbuf) == -1) - { - atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf); - return false; - } - //dump_device_list(alldevs); - - // Jump to the selected adapter. - for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++); - if (!device) - { - halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n"); - return false; - } - - // Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback - // interface), the interface, even in promiscous mode, filters foreign MAC addresses. - elap_clone_host_mac(device); - - // Open the adapter, - if ((pcap_session = pcapdelay_open_live(device->name, // name of the device - 65536, // portion of the packet to capture. - // 65536 grants that the whole packet will be captured on all the MACs. - 1, // promiscuous mode (nonzero means promiscuous) - 1, // read timeout - errbuf // error buffer - )) == NULL) - { - halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name); - pcapdelay_freealldevs(alldevs); - return false; - } +#endif +} + +const struct ether_addr_t* elap_get_mac() +{ + return &HW_LOCAL; +} + +bool elap_init() +{ + port_init(&elap_port); + + memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL)); + + pcap_if_t* device; + pcap_if_t* alldevs; + int i = 0; + + char errbuf[PCAP_ERRBUF_SIZE]; + + // Load the PCAP library. + if (!pcapdelay_load()) + { + halt_printf("ATBridge: PCAP not available.\n"); + return false; + } + + // Retrieve the device list. + if(pcapdelay_findalldevs(&alldevs, errbuf) == -1) + { + atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf); + return false; + } + //dump_device_list(alldevs); + + // Jump to the selected adapter. + for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++); + if (!device) + { + halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n"); + return false; + } + + // Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback + // interface), the interface, even in promiscous mode, filters foreign MAC addresses. + elap_clone_host_mac(device); + + // Open the adapter, + if ((pcap_session = pcapdelay_open_live(device->name, // name of the device + 65536, // portion of the packet to capture. + // 65536 grants that the whole packet will be captured on all the MACs. + 1, // promiscuous mode (nonzero means promiscuous) + 1, // read timeout + errbuf // error buffer + )) == NULL) + { + halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name); + pcapdelay_freealldevs(alldevs); + return false; + } // The device must support Ethernet because the bridge "speaks" EtherTalk. if (pcapdelay_datalink(pcap_session) == DLT_EN10MB) - { - pcapdelay_setnonblock(pcap_session, 1, errbuf); - - atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n", - device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]); - - pcapdelay_freealldevs(alldevs); - return true; - } - else - { - pcapdelay_close(pcap_session); - pcap_session = 0; - halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description); - pcapdelay_freealldevs(alldevs); - return false; - } -} - -void elap_shutdown() -{ - port_shutdown(&elap_port); - if (pcap_session) - { - pcapdelay_close(pcap_session); - pcap_session = 0; - } - pcapdelay_unload(); -} - -void elap_enqueue_out(struct packet_t* packet) -{ - enqueue_packet(&elap_port.out, packet); -} - -struct packet_t* elap_dequeue_in() -{ - return dequeue(&elap_port.in); -} - -void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]) -{ - if (pcap_session && dest && discriminator) - { - // Allocate heap space for the frame. - const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size; - u_char* frame_data; - size_t pad = 0; - if (frame_size < ETHER_MIN_SIZE) - pad = ETHER_MIN_SIZE - frame_size; - frame_data = (u_char*)malloc(frame_size + pad); - - // Build the 802.3 header. - struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data; - memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac)); - memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac)); - ether->length = htons(frame_size - sizeof(struct ethernet_header_t)); - - // Build the 802.2 header. - struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t)); - snap->dsap = SNAP_DSAP; - snap->ssap = SNAP_SSAP; - snap->control = SNAP_CONTROL; - memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator)); - - // Add the data payload. - struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); - memcpy(payload, data, size); - - // Add padding to meet minimum Ethernet frame size. - if (pad > 0) - memset(frame_data + frame_size, 0, pad); - - pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad); - } -} - -static bool elap_send_one_queued() -{ - // Attempt to send one packet out the host network interface. - struct packet_t* packet = queue_peek(&elap_port.out); - if (packet) - { - // Find the MAC address. - const struct ether_addr_t* dest; - if (packet->dest.node == at_broadcast_node) - dest = &HW_APPLETALK_BROADCAST; - else - dest = aarp_request_hardware(&packet->dest); - - // Send it. - if (dest) - { - elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data); - - dequeue(&elap_port.out); - free(packet->data); - free(packet); - } - else - { - // AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet. - if (!aarp_retry()) - { - // However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on. - atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node); - aarp_retry_reset(); - dequeue(&elap_port.out); - free(packet->data); - free(packet); - } - } - return true; - } - else - return false; -} - -static void elap_send_all_queued() -{ - while (elap_send_one_queued()); -} - -static bool elap_receive_one() -{ - if (!pcap_session) - return false; - - struct pcap_pkthdr header; - const u_char* packet = pcapdelay_next(pcap_session, &header); - if (packet) - { - // Receive and process one packet from the host network interface. - //// - - // Check the Ethernet 802.3 header. - const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet; - if (header.len > sizeof(struct ethernet_header_t) && - ntohs(ether->length) <= ETHER_MAX_SIZE && - ntohs(ether->length) > sizeof(struct snap_header_t) && - (memcmp(ðer->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */ - (memcmp(ðer->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */ - memcmp(ðer->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */) - ) - { - // Check the 802.2 SNAP header. - const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t)); - if (snap->dsap == SNAP_DSAP && - snap->ssap == SNAP_SSAP && - snap->control == SNAP_CONTROL) - { - if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0) - { - // Handle an AppleTalk packet. - const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t); - const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t); - - byte* copy = (byte*)malloc(payload_size); - memcpy(copy, payload, payload_size); - - // ELAP does not support short-form DDP, so this must be a long-form DDP packet. - struct at_addr_t source, dest; - if (payload_size >= sizeof(struct DDP_LONG)) - { - // Extract the protocol address from the header. - // - // ELAP really shouldn't be looking at the header for the next level of the protocol stack, - // but this is a convenient place to glean addresses for the AMT, a process that needs both - // hardware and protocol addresses. - struct DDP_LONG* header = (struct DDP_LONG*)copy; - dest.network = (at_network_t)ntohs(header->dest_net); - source.network = (at_network_t)ntohs(header->source_net); - dest.node = header->dest_node; - source.node = header->source_node; - - enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy); - - aarp_glean(&source, ðer->source); - } - else - atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n"); - } - else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0) - { - // Handle an AARP packet. - struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); - aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network); - aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network); - aarp->function = ntohs(aarp->function); - aarp->hardware_type = ntohs(aarp->hardware_type); - aarp->protocol_type = ntohs(aarp->protocol_type); - aarp_handle_packet(aarp); - } - } - } - - return true; - } - else - return false; -} - -static void elap_receive_all() -{ - while (elap_receive_one()); -} - -void elap_process() -{ - elap_receive_all(); - elap_send_all_queued(); + { + pcapdelay_setnonblock(pcap_session, 1, errbuf); + + atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n", + device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]); + + pcapdelay_freealldevs(alldevs); + return true; + } + else + { + pcapdelay_close(pcap_session); + pcap_session = 0; + halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description); + pcapdelay_freealldevs(alldevs); + return false; + } +} + +void elap_shutdown() +{ + port_shutdown(&elap_port); + if (pcap_session) + { + pcapdelay_close(pcap_session); + pcap_session = 0; + } + pcapdelay_unload(); +} + +void elap_enqueue_out(struct packet_t* packet) +{ + enqueue_packet(&elap_port.out, packet); +} + +struct packet_t* elap_dequeue_in() +{ + return dequeue(&elap_port.in); +} + +void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]) +{ + if (pcap_session && dest && discriminator) + { + // Allocate heap space for the frame. + const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size; + u_char* frame_data; + size_t pad = 0; + if (frame_size < ETHER_MIN_SIZE) + pad = ETHER_MIN_SIZE - frame_size; + frame_data = (u_char*)malloc(frame_size + pad); + + // Build the 802.3 header. + struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data; + memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac)); + memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac)); + ether->length = htons(frame_size - sizeof(struct ethernet_header_t)); + + // Build the 802.2 header. + struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t)); + snap->dsap = SNAP_DSAP; + snap->ssap = SNAP_SSAP; + snap->control = SNAP_CONTROL; + memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator)); + + // Add the data payload. + struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); + memcpy(payload, data, size); + + // Add padding to meet minimum Ethernet frame size. + if (pad > 0) + memset(frame_data + frame_size, 0, pad); + + pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad); + } +} + +static bool elap_send_one_queued() +{ + // Attempt to send one packet out the host network interface. + struct packet_t* packet = queue_peek(&elap_port.out); + if (packet) + { + // Find the MAC address. + const struct ether_addr_t* dest; + if (packet->dest.node == at_broadcast_node) + dest = &HW_APPLETALK_BROADCAST; + else + dest = aarp_request_hardware(&packet->dest); + + // Send it. + if (dest) + { + elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data); + + dequeue(&elap_port.out); + free(packet->data); + free(packet); + } + else + { + // AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet. + if (!aarp_retry()) + { + // However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on. + atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node); + aarp_retry_reset(); + dequeue(&elap_port.out); + free(packet->data); + free(packet); + } + } + return true; + } + else + return false; +} + +static void elap_send_all_queued() +{ + while (elap_send_one_queued()); +} + +static bool elap_receive_one() +{ + if (!pcap_session) + return false; + + struct pcap_pkthdr header; + const u_char* packet = pcapdelay_next(pcap_session, &header); + if (packet) + { + // Receive and process one packet from the host network interface. + //// + + // Check the Ethernet 802.3 header. + const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet; + if (header.len > sizeof(struct ethernet_header_t) && + ntohs(ether->length) <= ETHER_MAX_SIZE && + ntohs(ether->length) > sizeof(struct snap_header_t) && + (memcmp(ðer->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */ + (memcmp(ðer->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */ + memcmp(ðer->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */) + ) + { + // Check the 802.2 SNAP header. + const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t)); + if (snap->dsap == SNAP_DSAP && + snap->ssap == SNAP_SSAP && + snap->control == SNAP_CONTROL) + { + if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0) + { + // Handle an AppleTalk packet. + const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t); + const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t); + + byte* copy = (byte*)malloc(payload_size); + memcpy(copy, payload, payload_size); + + // ELAP does not support short-form DDP, so this must be a long-form DDP packet. + struct at_addr_t source, dest; + if (payload_size >= sizeof(struct DDP_LONG)) + { + // Extract the protocol address from the header. + // + // ELAP really shouldn't be looking at the header for the next level of the protocol stack, + // but this is a convenient place to glean addresses for the AMT, a process that needs both + // hardware and protocol addresses. + struct DDP_LONG* header = (struct DDP_LONG*)copy; + dest.network = (at_network_t)ntohs(header->dest_net); + source.network = (at_network_t)ntohs(header->source_net); + dest.node = header->dest_node; + source.node = header->source_node; + + enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy); + + aarp_glean(&source, ðer->source); + } + else + atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n"); + } + else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0) + { + // Handle an AARP packet. + struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t)); + aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network); + aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network); + aarp->function = ntohs(aarp->function); + aarp->hardware_type = ntohs(aarp->hardware_type); + aarp->protocol_type = ntohs(aarp->protocol_type); + aarp_handle_packet(aarp); + } + } + } + + return true; + } + else + return false; +} + +static void elap_receive_all() +{ + while (elap_receive_one()); +} + +void elap_process() +{ + elap_receive_all(); + elap_send_all_queued(); } diff --git a/src/atbridge/elap.h b/src/atbridge/elap.h index bf04abc..ba0fdd0 100644 --- a/src/atbridge/elap.h +++ b/src/atbridge/elap.h @@ -1,36 +1,38 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** ELAP port of the AppleTalk Bridge **/ - -bool elap_init(); -void elap_shutdown(); -void elap_process(); - -struct packet_t; - -void elap_enqueue_out(struct packet_t* packet); -struct packet_t* elap_dequeue_in(); - -struct ether_addr_t; -struct snap_discriminator_t; - -void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]); - -const struct ether_addr_t* elap_get_mac(); \ No newline at end of file +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** ELAP port of the AppleTalk Bridge **/ + +bool elap_init(); +void elap_shutdown(); +void elap_process(); + +struct packet_t; + +void elap_enqueue_out(struct packet_t* packet); +struct packet_t* elap_dequeue_in(); + +struct ether_addr_t; +struct snap_discriminator_t; + +void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]); + +const struct ether_addr_t* elap_get_mac(); diff --git a/src/atbridge/elap_defs.h b/src/atbridge/elap_defs.h index 306e519..0858795 100644 --- a/src/atbridge/elap_defs.h +++ b/src/atbridge/elap_defs.h @@ -1,117 +1,119 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* Ethernet addresses are 6 bytes */ -#define ETHER_ADDR_LEN 6 - -static const word16 ETHER_MAX_SIZE = 0x5DC; -static const word16 ETHER_MIN_SIZE = 60; -static const byte SNAP_DSAP = 0xAA; -static const byte SNAP_SSAP = 0xAA; -static const byte SNAP_CONTROL = 0x03; - -#define OUI_APPLETALK_1 0x08 -#define OUI_APPLETALK_2 0x00 -#define OUI_APPLETALK_3 0x07 -#define TYPE_APPLETALK_1 0x80 -#define TYPE_APPLETALK_2 0x9B - -#define OUI_AARP_1 0x00 -#define OUI_AARP_2 0x00 -#define OUI_AARP_3 0x00 -#define TYPE_AARP_1 0x80 -#define TYPE_AARP_2 0xF3 - -static const byte AARP_HARDWARE_ETHER = 0x01; -static const word16 AARP_PROTOCOL_TYPE = 0x809B; -static const byte AARP_HW_ADDR_LEN = 6; -static const byte AARP_PROTOCOL_ADDR_LEN = 4; -enum AARP_FUNCTION -{ - AARP_FUNCTION_REQUEST = 0x01, - AARP_FUNCTION_RESPONSE = 0x02, - AARP_FUNCTION_PROBE = 0x03 -}; - -// reference C-4 -static const long AARP_PROBE_INTERVAL = 200; /* milliseconds */ -static const unsigned int AARP_PROBE_COUNT = 10; - -// reference 2-9 and 3-9, optional and at developer discretion -static const long AARP_REQUEST_INTERVAL = 200; /* milliseconds */ -static const unsigned int AARP_REQUEST_COUNT = 10; - -#pragma pack(push, 1) -struct ether_addr_t -{ - byte mac[ETHER_ADDR_LEN]; -}; - -/* Ethernet 802.2/802.3/SNAP header */ -struct ethernet_header_t -{ - // 802.3 header - struct ether_addr_t dest; - struct ether_addr_t source; - word16 length; -}; - -struct snap_discriminator_t -{ - byte oui[3]; - byte type[2]; -}; - -struct snap_header_t -{ - // 802.2 header - byte dsap; - byte ssap; - byte control; - - // SNAP header - struct snap_discriminator_t discriminator; -}; - -struct protocol_addr_t -{ - byte zero; // Reference C-4 and 3-11: The protocol address is four bytes with the high byte zero. - struct at_addr_t addr; -}; - -struct aarp_header_t -{ - word16 hardware_type; - word16 protocol_type; - byte hw_addr_len; - byte protocol_addr_len; - word16 function; - struct ether_addr_t source_hw_addr; - struct protocol_addr_t source_proto_addr; - struct ether_addr_t dest_hw_addr; - struct protocol_addr_t dest_proto_addr; -}; -#pragma pack(pop) - -static const struct ether_addr_t HW_APPLETALK_BROADCAST = {{ 0x09, 0x00, 0x07, 0xff, 0xff, 0xff }}; -static const struct ether_addr_t HW_LOCAL_DEFAULT = {{0x02 /* unicast, locally administered */, 'A', '2', 'G', 'S', 0x00}}; -//static const struct ether_addr_t HW_LOCAL = {{ 0x02 /* unicast, locally administered */, 0x00, 0x4c, 0x4f, 0x4f, 0x50 }}; -static const struct ether_addr_t HW_ZERO = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; -static const struct snap_discriminator_t SNAP_APPLETALK = {{ OUI_APPLETALK_1, OUI_APPLETALK_2, OUI_APPLETALK_3}, {TYPE_APPLETALK_1, TYPE_APPLETALK_2 }}; -static const struct snap_discriminator_t SNAP_AARP = {{ OUI_AARP_1, OUI_AARP_2, OUI_AARP_3}, {TYPE_AARP_1, TYPE_AARP_2 }}; \ No newline at end of file +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Ethernet addresses are 6 bytes */ +#define ETHER_ADDR_LEN 6 + +static const word16 ETHER_MAX_SIZE = 0x5DC; +static const word16 ETHER_MIN_SIZE = 60; +static const byte SNAP_DSAP = 0xAA; +static const byte SNAP_SSAP = 0xAA; +static const byte SNAP_CONTROL = 0x03; + +#define OUI_APPLETALK_1 0x08 +#define OUI_APPLETALK_2 0x00 +#define OUI_APPLETALK_3 0x07 +#define TYPE_APPLETALK_1 0x80 +#define TYPE_APPLETALK_2 0x9B + +#define OUI_AARP_1 0x00 +#define OUI_AARP_2 0x00 +#define OUI_AARP_3 0x00 +#define TYPE_AARP_1 0x80 +#define TYPE_AARP_2 0xF3 + +static const byte AARP_HARDWARE_ETHER = 0x01; +static const word16 AARP_PROTOCOL_TYPE = 0x809B; +static const byte AARP_HW_ADDR_LEN = 6; +static const byte AARP_PROTOCOL_ADDR_LEN = 4; +enum AARP_FUNCTION +{ + AARP_FUNCTION_REQUEST = 0x01, + AARP_FUNCTION_RESPONSE = 0x02, + AARP_FUNCTION_PROBE = 0x03 +}; + +// reference C-4 +static const long AARP_PROBE_INTERVAL = 200; /* milliseconds */ +static const unsigned int AARP_PROBE_COUNT = 10; + +// reference 2-9 and 3-9, optional and at developer discretion +static const long AARP_REQUEST_INTERVAL = 200; /* milliseconds */ +static const unsigned int AARP_REQUEST_COUNT = 10; + +#pragma pack(push, 1) +struct ether_addr_t +{ + byte mac[ETHER_ADDR_LEN]; +}; + +/* Ethernet 802.2/802.3/SNAP header */ +struct ethernet_header_t +{ + // 802.3 header + struct ether_addr_t dest; + struct ether_addr_t source; + word16 length; +}; + +struct snap_discriminator_t +{ + byte oui[3]; + byte type[2]; +}; + +struct snap_header_t +{ + // 802.2 header + byte dsap; + byte ssap; + byte control; + + // SNAP header + struct snap_discriminator_t discriminator; +}; + +struct protocol_addr_t +{ + byte zero; // Reference C-4 and 3-11: The protocol address is four bytes with the high byte zero. + struct at_addr_t addr; +}; + +struct aarp_header_t +{ + word16 hardware_type; + word16 protocol_type; + byte hw_addr_len; + byte protocol_addr_len; + word16 function; + struct ether_addr_t source_hw_addr; + struct protocol_addr_t source_proto_addr; + struct ether_addr_t dest_hw_addr; + struct protocol_addr_t dest_proto_addr; +}; +#pragma pack(pop) + +static const struct ether_addr_t HW_APPLETALK_BROADCAST = {{ 0x09, 0x00, 0x07, 0xff, 0xff, 0xff }}; +static const struct ether_addr_t HW_LOCAL_DEFAULT = {{0x02 /* unicast, locally administered */, 'A', '2', 'G', 'S', 0x00}}; +//static const struct ether_addr_t HW_LOCAL = {{ 0x02 /* unicast, locally administered */, 0x00, 0x4c, 0x4f, 0x4f, 0x50 }}; +static const struct ether_addr_t HW_ZERO = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; +static const struct snap_discriminator_t SNAP_APPLETALK = {{ OUI_APPLETALK_1, OUI_APPLETALK_2, OUI_APPLETALK_3}, {TYPE_APPLETALK_1, TYPE_APPLETALK_2 }}; +static const struct snap_discriminator_t SNAP_AARP = {{ OUI_AARP_1, OUI_AARP_2, OUI_AARP_3}, {TYPE_AARP_1, TYPE_AARP_2 }}; diff --git a/src/atbridge/llap.c b/src/atbridge/llap.c index 7fc2cde..a194d64 100644 --- a/src/atbridge/llap.c +++ b/src/atbridge/llap.c @@ -1,332 +1,334 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements the LLAP port of the bridge. **/ - -#include -#include "../defc.h" -#include "atbridge.h" -#include "port.h" -#include "llap.h" - -typedef enum { - LLAP_DDP_SHORT = 0x01, - LLAP_DDP_LONG = 0x02, - LLAP_ENQ = 0x81, - LLAP_ACK = 0x82, - LLAP_RTS = 0x84, - LLAP_CTS = 0x85 -} LLAP_TYPES; - -const unsigned int LLAP_PACKET_MAX = 603 /* bytes */; -const unsigned int LLAP_PACKET_MIN = 3 /* bytes */; -const double LLAP_IDG = 400 /* microseconds */; -const double LLAP_IFG = 200 /* microseconds */; -const double GAP_TOLERANCE = 4.0; - -static struct packet_port_t llap_port; - -typedef enum { - DIALOG_READY, - DIALOG_GOT_CTS, - DIALOG_WAIT_IDG -} DIALOG_STATE; -static DIALOG_STATE dialog_state; -static double dialog_end_dcycs; -static double last_frame_dcycs; - -void llap_init() -{ - dialog_state = DIALOG_READY; - last_frame_dcycs = 0; - port_init(&llap_port); -} - -void llap_shutdown() -{ - port_shutdown(&llap_port); -} - - -/** Queue one data packet out from the bridge's LLAP port and into the guest. **/ -void llap_enqueue_out(struct packet_t* packet) -{ - // Generate the RTS. - struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t)); - rts->source.network = packet->source.network; - rts->source.node = packet->source.node; - rts->dest.network = packet->dest.network; - rts->dest.node = packet->dest.node; - rts->size = 0; - rts->data = 0; - rts->type = LLAP_RTS; - enqueue_packet(&llap_port.out, rts); - - // Enqueue the data. - enqueue_packet(&llap_port.out, packet); -} - -struct packet_t* llap_dequeue_in() -{ - return dequeue(&llap_port.in); -} - -static void llap_dump_packet(size_t size, byte data[]) -{ - if (size < LLAP_PACKET_MIN) - atbridge_printf("LLAP short packet.\n"); - else if (size > LLAP_PACKET_MAX) - atbridge_printf("LLAP long packet.\n"); - else - { - at_node_t dest = data[0]; - at_node_t source = data[1]; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - const char* typeName = 0; - switch (type) - { - case LLAP_DDP_SHORT: - typeName = "DDP (short)"; - break; - case LLAP_DDP_LONG: - typeName = "DDP (long)"; - break; - case LLAP_ENQ: - typeName = "lapENQ"; - break; - case LLAP_ACK: - typeName = "lapACK"; - break; - case LLAP_RTS: - typeName = "lapRTS"; - break; - case LLAP_CTS: - typeName = "lapCTS"; - break; - } - - if (typeName) - atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size); - else - atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size); - - /*for (size_t i = 0; i < size; i++) - atbridge_printf("%02x ", data[i]); - atbridge_printf("\n");*/ - } -} - -/** Reply to a control packet from the GS **/ -static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type) -{ - struct at_addr_t dest_addr = { 0, dest }; - struct at_addr_t source_addr = { 0, source }; - - // Insert control packets at the head of the queue contrary to normal FIFO queue operation - // to ensure that control frames arrive in the intended order. - insert(&llap_port.out, dest_addr, source_addr, type, 0, 0); -} - -/** Accept a data packet from the GS. **/ -static void llap_handle_data(size_t size, byte data[]) -{ - at_node_t dest = data[0]; - at_node_t source = data[1]; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - const size_t data_size = size - 3; - byte* data_copy = (byte*)malloc(data_size); - memcpy(data_copy, data + 3, data_size); - - struct at_addr_t dest_addr = { 0, dest }; - struct at_addr_t source_addr = { 0, source }; - enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy); -} - -/** Accept a control packet from the GS. **/ -static void llap_handle_control(size_t size, byte data[]) -{ - at_node_t dest = data[0]; - at_node_t source = data[1]; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - struct at_addr_t addr = { atbridge_get_net(), dest }; - - switch (type) - { - case LLAP_ENQ: - // Require the GS to take a valid "client" address not known to be in use. - if (dest > 127 || dest == 0 || atbridge_address_used(&addr)) - llap_reply_control(source, dest, LLAP_ACK); - break; - case LLAP_ACK: - break; - case LLAP_RTS: - if (dest != at_broadcast_node) - // The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake. - // Note that broadcast packets do not require a CTS. - llap_reply_control(source, dest, LLAP_CTS); - break; - case LLAP_CTS: - // The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet. - dialog_state = DIALOG_GOT_CTS; - break; - default: - break; - } -} - -/** Occassionally, we receive an invalid packet from the GS. I'm unsure if this is due to a bug in GS/OS - or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the - current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover. - **/ -static void llap_reset_dialog() -{ - dialog_state = DIALOG_READY; - last_frame_dcycs = 0; - - // Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS). - while (true) - { - struct packet_t* packet = queue_peek(&llap_port.out); - - if (packet && (packet->type != LLAP_RTS)) - { - packet = dequeue(&llap_port.out); - if (packet->data) - free(packet->data); - free(packet); - } - else - break; - } -} - -/** Transfer (send) one LLAP packet from the GS. **/ -void llap_enqueue_in(double dcycs, size_t size, byte data[]) -{ - atbridge_printf("<%0.0f> TX: ", dcycs); - llap_dump_packet(size, data); - - if (size < LLAP_PACKET_MIN) - atbridge_printf("ATBridge: Dropping LLAP short packet.\n"); - else if (size > LLAP_PACKET_MAX) - atbridge_printf("ATBridge: Dropping LLAP long packet.\n"); - else - { - last_frame_dcycs = dcycs; - LLAP_TYPES type = (LLAP_TYPES)(data[2]); - - switch (type) - { - case LLAP_DDP_SHORT: - case LLAP_DDP_LONG: - llap_handle_data(size, data); - break; - case LLAP_ENQ: - case LLAP_ACK: - case LLAP_RTS: - case LLAP_CTS: - llap_handle_control(size, data); - break; - default: - // Intentionally check for valid types and ingore packets with invalid types. - // Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge. - atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n"); - llap_reset_dialog(); - } - } -} - -/** Transfer (receive) one LLAP packet to the GS. **/ -void llap_dequeue_out(double dcycs, size_t* size, byte* data[]) -{ - *size = 0; - - // The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG). - // If necessary, wait for the IDG. - if (dialog_state == DIALOG_WAIT_IDG) - { - if ((dcycs - dialog_end_dcycs) >= LLAP_IDG) - // The IDG is done. - dialog_state = DIALOG_READY; - else - // Continue waiting for the IDG. - return; - } - // The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG). - // If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case, - // discard the current dialog and try again. - if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG))) - { - llap_reset_dialog(); - atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n"); - } - - struct packet_t* packet = queue_peek(&llap_port.out); - - if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG))) - { - llap_reset_dialog(); - packet = queue_peek(&llap_port.out); - atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n"); - } - - if (packet && - ((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */ - (!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */ - (!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */ - { - dequeue(&llap_port.out); - - // Prepend the LLAP header. - *size = packet->size + 3 + 2; - *data = (byte*)malloc(*size); - (*data)[0] = packet->dest.node; - (*data)[1] = packet->source.node; - (*data)[2] = packet->type; - - // Insert the data into the new LLAP packet. - if (*size) - memcpy((*data) + 3, packet->data, packet->size); - - // Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually - // check the FCS, the value of the FCS doesn't matter. - (*data)[packet->size + 3 + 0] = 0xff; - (*data)[packet->size + 3 + 1] = 0xff; - - atbridge_printf("<%0.0f> RX: ", dcycs); - llap_dump_packet(*size, *data); - - if (packet->type & 0x80) - dialog_state = DIALOG_READY; - else - { - // This was the last packet in the dialog. - dialog_state = DIALOG_WAIT_IDG; - dialog_end_dcycs = dcycs; - } - - last_frame_dcycs = dcycs; - - free(packet->data); - free(packet); - } -} +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements the LLAP port of the bridge. **/ + +#include +#include "../defc.h" +#include "atbridge.h" +#include "port.h" +#include "llap.h" + +typedef enum { + LLAP_DDP_SHORT = 0x01, + LLAP_DDP_LONG = 0x02, + LLAP_ENQ = 0x81, + LLAP_ACK = 0x82, + LLAP_RTS = 0x84, + LLAP_CTS = 0x85 +} LLAP_TYPES; + +const unsigned int LLAP_PACKET_MAX = 603 /* bytes */; +const unsigned int LLAP_PACKET_MIN = 3 /* bytes */; +const double LLAP_IDG = 400 /* microseconds */; +const double LLAP_IFG = 200 /* microseconds */; +const double GAP_TOLERANCE = 4.0; + +static struct packet_port_t llap_port; + +typedef enum { + DIALOG_READY, + DIALOG_GOT_CTS, + DIALOG_WAIT_IDG +} DIALOG_STATE; +static DIALOG_STATE dialog_state; +static double dialog_end_dcycs; +static double last_frame_dcycs; + +void llap_init() +{ + dialog_state = DIALOG_READY; + last_frame_dcycs = 0; + port_init(&llap_port); +} + +void llap_shutdown() +{ + port_shutdown(&llap_port); +} + + +/** Queue one data packet out from the bridge's LLAP port and into the guest. **/ +void llap_enqueue_out(struct packet_t* packet) +{ + // Generate the RTS. + struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t)); + rts->source.network = packet->source.network; + rts->source.node = packet->source.node; + rts->dest.network = packet->dest.network; + rts->dest.node = packet->dest.node; + rts->size = 0; + rts->data = 0; + rts->type = LLAP_RTS; + enqueue_packet(&llap_port.out, rts); + + // Enqueue the data. + enqueue_packet(&llap_port.out, packet); +} + +struct packet_t* llap_dequeue_in() +{ + return dequeue(&llap_port.in); +} + +static void llap_dump_packet(size_t size, byte data[]) +{ + if (size < LLAP_PACKET_MIN) + atbridge_printf("LLAP short packet.\n"); + else if (size > LLAP_PACKET_MAX) + atbridge_printf("LLAP long packet.\n"); + else + { + at_node_t dest = data[0]; + at_node_t source = data[1]; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + const char* typeName = 0; + switch (type) + { + case LLAP_DDP_SHORT: + typeName = "DDP (short)"; + break; + case LLAP_DDP_LONG: + typeName = "DDP (long)"; + break; + case LLAP_ENQ: + typeName = "lapENQ"; + break; + case LLAP_ACK: + typeName = "lapACK"; + break; + case LLAP_RTS: + typeName = "lapRTS"; + break; + case LLAP_CTS: + typeName = "lapCTS"; + break; + } + + if (typeName) + atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size); + else + atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size); + + /*for (size_t i = 0; i < size; i++) + atbridge_printf("%02x ", data[i]); + atbridge_printf("\n");*/ + } +} + +/** Reply to a control packet from the GS **/ +static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type) +{ + struct at_addr_t dest_addr = { 0, dest }; + struct at_addr_t source_addr = { 0, source }; + + // Insert control packets at the head of the queue contrary to normal FIFO queue operation + // to ensure that control frames arrive in the intended order. + insert(&llap_port.out, dest_addr, source_addr, type, 0, 0); +} + +/** Accept a data packet from the GS. **/ +static void llap_handle_data(size_t size, byte data[]) +{ + at_node_t dest = data[0]; + at_node_t source = data[1]; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + const size_t data_size = size - 3; + byte* data_copy = (byte*)malloc(data_size); + memcpy(data_copy, data + 3, data_size); + + struct at_addr_t dest_addr = { 0, dest }; + struct at_addr_t source_addr = { 0, source }; + enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy); +} + +/** Accept a control packet from the GS. **/ +static void llap_handle_control(size_t size, byte data[]) +{ + at_node_t dest = data[0]; + at_node_t source = data[1]; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + struct at_addr_t addr = { atbridge_get_net(), dest }; + + switch (type) + { + case LLAP_ENQ: + // Require the GS to take a valid "client" address not known to be in use. + if (dest > 127 || dest == 0 || atbridge_address_used(&addr)) + llap_reply_control(source, dest, LLAP_ACK); + break; + case LLAP_ACK: + break; + case LLAP_RTS: + if (dest != at_broadcast_node) + // The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake. + // Note that broadcast packets do not require a CTS. + llap_reply_control(source, dest, LLAP_CTS); + break; + case LLAP_CTS: + // The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet. + dialog_state = DIALOG_GOT_CTS; + break; + default: + break; + } +} + +/** Occassionally, we receive an invalid packet from the GS. I'm unsure if this is due to a bug in GS/OS + or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the + current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover. + **/ +static void llap_reset_dialog() +{ + dialog_state = DIALOG_READY; + last_frame_dcycs = 0; + + // Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS). + while (true) + { + struct packet_t* packet = queue_peek(&llap_port.out); + + if (packet && (packet->type != LLAP_RTS)) + { + packet = dequeue(&llap_port.out); + if (packet->data) + free(packet->data); + free(packet); + } + else + break; + } +} + +/** Transfer (send) one LLAP packet from the GS. **/ +void llap_enqueue_in(double dcycs, size_t size, byte data[]) +{ + atbridge_printf("<%0.0f> TX: ", dcycs); + llap_dump_packet(size, data); + + if (size < LLAP_PACKET_MIN) + atbridge_printf("ATBridge: Dropping LLAP short packet.\n"); + else if (size > LLAP_PACKET_MAX) + atbridge_printf("ATBridge: Dropping LLAP long packet.\n"); + else + { + last_frame_dcycs = dcycs; + LLAP_TYPES type = (LLAP_TYPES)(data[2]); + + switch (type) + { + case LLAP_DDP_SHORT: + case LLAP_DDP_LONG: + llap_handle_data(size, data); + break; + case LLAP_ENQ: + case LLAP_ACK: + case LLAP_RTS: + case LLAP_CTS: + llap_handle_control(size, data); + break; + default: + // Intentionally check for valid types and ingore packets with invalid types. + // Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge. + atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n"); + llap_reset_dialog(); + } + } +} + +/** Transfer (receive) one LLAP packet to the GS. **/ +void llap_dequeue_out(double dcycs, size_t* size, byte* data[]) +{ + *size = 0; + + // The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG). + // If necessary, wait for the IDG. + if (dialog_state == DIALOG_WAIT_IDG) + { + if ((dcycs - dialog_end_dcycs) >= LLAP_IDG) + // The IDG is done. + dialog_state = DIALOG_READY; + else + // Continue waiting for the IDG. + return; + } + // The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG). + // If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case, + // discard the current dialog and try again. + if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG))) + { + llap_reset_dialog(); + atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n"); + } + + struct packet_t* packet = queue_peek(&llap_port.out); + + if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG))) + { + llap_reset_dialog(); + packet = queue_peek(&llap_port.out); + atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n"); + } + + if (packet && + ((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */ + (!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */ + (!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */ + { + dequeue(&llap_port.out); + + // Prepend the LLAP header. + *size = packet->size + 3 + 2; + *data = (byte*)malloc(*size); + (*data)[0] = packet->dest.node; + (*data)[1] = packet->source.node; + (*data)[2] = packet->type; + + // Insert the data into the new LLAP packet. + if (*size) + memcpy((*data) + 3, packet->data, packet->size); + + // Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually + // check the FCS, the value of the FCS doesn't matter. + (*data)[packet->size + 3 + 0] = 0xff; + (*data)[packet->size + 3 + 1] = 0xff; + + atbridge_printf("<%0.0f> RX: ", dcycs); + llap_dump_packet(*size, *data); + + if (packet->type & 0x80) + dialog_state = DIALOG_READY; + else + { + // This was the last packet in the dialog. + dialog_state = DIALOG_WAIT_IDG; + dialog_end_dcycs = dcycs; + } + + last_frame_dcycs = dcycs; + + free(packet->data); + free(packet); + } +} diff --git a/src/atbridge/llap.h b/src/atbridge/llap.h index c847170..b8692ae 100644 --- a/src/atbridge/llap.h +++ b/src/atbridge/llap.h @@ -1,37 +1,39 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct packet_t; - -/** LLAP port of the AppleTalk Bridge **/ - -void llap_init(); -void llap_shutdown(); - -/** Send one LLAP packet from the GS - */ -void llap_enqueue_in(double dcycs, size_t size, byte data[]); - -/** Receive one LLAP packet from the world to the GS and return the size - */ -void llap_dequeue_out(double dcycs, size_t* size, byte* data[]); - - -void llap_enqueue_out(struct packet_t* packet); -struct packet_t* llap_dequeue_in(); +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct packet_t; + +/** LLAP port of the AppleTalk Bridge **/ + +void llap_init(); +void llap_shutdown(); + +/** Send one LLAP packet from the GS + */ +void llap_enqueue_in(double dcycs, size_t size, byte data[]); + +/** Receive one LLAP packet from the world to the GS and return the size + */ +void llap_dequeue_out(double dcycs, size_t* size, byte* data[]); + + +void llap_enqueue_out(struct packet_t* packet); +struct packet_t* llap_dequeue_in(); diff --git a/src/atbridge/pcap_delay.c b/src/atbridge/pcap_delay.c index d71ebad..3a88255 100644 --- a/src/atbridge/pcap_delay.c +++ b/src/atbridge/pcap_delay.c @@ -1,171 +1,173 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include "pcap_delay.h" - -#ifdef WIN32 -#include -static HMODULE module = NULL; -#elif __linux__ -#include -static void* module = 0; -#endif - - -bool pcapdelay_load() -{ - if (!pcapdelay_is_loaded()) - { -#ifdef WIN32 - module = LoadLibrary("wpcap.dll"); -#elif __linux__ - module = dlopen("libpcap.so", RTLD_LAZY); -#endif - } - return pcapdelay_is_loaded(); -} - -bool pcapdelay_is_loaded() -{ -#ifdef WIN32 - return module != NULL; -#elif __linux__ - return module != 0; -#endif - return 0; -} - -void pcapdelay_unload() -{ - if (pcapdelay_is_loaded()) - { -#ifdef WIN32 - FreeLibrary(module); - module = NULL; -#elif __linux__ - dlclose(module); - module = 0; -#endif - } -} - -typedef void (*PFNVOID)(); - -static PFNVOID delay_load(const char* proc, PFNVOID* ppfn) -{ - if (pcapdelay_load() && proc && ppfn && !*ppfn) - { -#ifdef WIN32 - *ppfn = (PFNVOID)GetProcAddress(module, proc); -#elif __linux__ - *ppfn = (PFNVOID)dlsym(module, proc); -#endif - } - if (ppfn) - return *ppfn; - else - return 0; -} - -void pcapdelay_freealldevs(pcap_if_t* a0) -{ - typedef void (*PFN)(pcap_if_t*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn))) - (*pfn)(a0); -} - -pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4) -{ - typedef pcap_t* (*PFN)(const char*, int, int, int, char*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2, a3, a4); - else - return 0; -} - -void pcapdelay_close(pcap_t* a0) -{ - typedef void (*PFN)(pcap_t*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn))) - (*pfn)(a0); -} - -int pcapdelay_findalldevs(pcap_if_t** a0, char* a1) -{ - typedef int (*PFN)(pcap_if_t**, char*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1); - else - return 0; -} - -int pcapdelay_datalink(pcap_t* a0) -{ - typedef int(*PFN)(pcap_t*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn))) - return (*pfn)(a0); - else - return 0; -} - -int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2) -{ - typedef int(*PFN)(pcap_t*, int, char*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2); - else - return 0; -} - -int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2) -{ - typedef int(*PFN)(pcap_t*, u_char*, int); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2); - else - return 0; -} - -const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1) -{ - typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1); - else - return 0; -} - -int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3) -{ - typedef const int(*PFN)(pcap_t *, int, pcap_handler, u_char *); - static PFN pfn = 0; - if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn))) - return (*pfn)(a0, a1, a2, a3); - else - return 0; -} +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "pcap_delay.h" + +#ifdef WIN32 +#include +static HMODULE module = NULL; +#elif __linux__ +#include +static void* module = 0; +#endif + + +bool pcapdelay_load() +{ + if (!pcapdelay_is_loaded()) + { +#ifdef WIN32 + module = LoadLibrary("wpcap.dll"); +#elif __linux__ + module = dlopen("libpcap.so", RTLD_LAZY); +#endif + } + return pcapdelay_is_loaded(); +} + +bool pcapdelay_is_loaded() +{ +#ifdef WIN32 + return module != NULL; +#elif __linux__ + return module != 0; +#endif + return 0; +} + +void pcapdelay_unload() +{ + if (pcapdelay_is_loaded()) + { +#ifdef WIN32 + FreeLibrary(module); + module = NULL; +#elif __linux__ + dlclose(module); + module = 0; +#endif + } +} + +typedef void (*PFNVOID)(); + +static PFNVOID delay_load(const char* proc, PFNVOID* ppfn) +{ + if (pcapdelay_load() && proc && ppfn && !*ppfn) + { +#ifdef WIN32 + *ppfn = (PFNVOID)GetProcAddress(module, proc); +#elif __linux__ + *ppfn = (PFNVOID)dlsym(module, proc); +#endif + } + if (ppfn) + return *ppfn; + else + return 0; +} + +void pcapdelay_freealldevs(pcap_if_t* a0) +{ + typedef void (*PFN)(pcap_if_t*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn))) + (*pfn)(a0); +} + +pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4) +{ + typedef pcap_t* (*PFN)(const char*, int, int, int, char*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2, a3, a4); + else + return 0; +} + +void pcapdelay_close(pcap_t* a0) +{ + typedef void (*PFN)(pcap_t*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn))) + (*pfn)(a0); +} + +int pcapdelay_findalldevs(pcap_if_t** a0, char* a1) +{ + typedef int (*PFN)(pcap_if_t**, char*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1); + else + return 0; +} + +int pcapdelay_datalink(pcap_t* a0) +{ + typedef int(*PFN)(pcap_t*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn))) + return (*pfn)(a0); + else + return 0; +} + +int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2) +{ + typedef int(*PFN)(pcap_t*, int, char*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2); + else + return 0; +} + +int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2) +{ + typedef int(*PFN)(pcap_t*, u_char*, int); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2); + else + return 0; +} + +const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1) +{ + typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1); + else + return 0; +} + +int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3) +{ + typedef const int(*PFN)(pcap_t *, int, pcap_handler, u_char *); + static PFN pfn = 0; + if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn))) + return (*pfn)(a0, a1, a2, a3); + else + return 0; +} diff --git a/src/atbridge/pcap_delay.h b/src/atbridge/pcap_delay.h index 1c9baad..4435dd6 100644 --- a/src/atbridge/pcap_delay.h +++ b/src/atbridge/pcap_delay.h @@ -1,48 +1,50 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/* -This interface provides a thin, delay-loaded wrapper around the PCAP library so that -you may start GSport without intalling PCAP. Of course, some features that require -PCAP won't be available. - -This wrapper provides a subset of the available PCAP APIs necessary for ATBridge. -Feel free to extend the wrapper. -*/ - -#ifdef WIN32 -#include "../arch/win32/pcap.h" -#elif __linux__ -#include -#elif __APPLE__ -#include -#endif - -bool pcapdelay_load(); -bool pcapdelay_is_loaded(); -void pcapdelay_unload(); - -void pcapdelay_freealldevs(pcap_if_t *); -pcap_t* pcapdelay_open_live(const char *, int, int, int, char *); -void pcapdelay_close(pcap_t *); -int pcapdelay_findalldevs(pcap_if_t **, char *); -int pcapdelay_datalink(pcap_t *); -int pcapdelay_setnonblock(pcap_t *, int, char *); -int pcapdelay_sendpacket(pcap_t *p, u_char *buf, int size); -const u_char* pcapdelay_next(pcap_t *, struct pcap_pkthdr *); -int pcapdelay_dispatch(pcap_t *, int, pcap_handler, u_char *); +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* +This interface provides a thin, delay-loaded wrapper around the PCAP library so that +you may start GSport without intalling PCAP. Of course, some features that require +PCAP won't be available. + +This wrapper provides a subset of the available PCAP APIs necessary for ATBridge. +Feel free to extend the wrapper. +*/ + +#ifdef WIN32 +#include "../arch/win32/pcap.h" +#elif __linux__ +#include +#elif __APPLE__ +#include +#endif + +bool pcapdelay_load(); +bool pcapdelay_is_loaded(); +void pcapdelay_unload(); + +void pcapdelay_freealldevs(pcap_if_t *); +pcap_t* pcapdelay_open_live(const char *, int, int, int, char *); +void pcapdelay_close(pcap_t *); +int pcapdelay_findalldevs(pcap_if_t **, char *); +int pcapdelay_datalink(pcap_t *); +int pcapdelay_setnonblock(pcap_t *, int, char *); +int pcapdelay_sendpacket(pcap_t *p, u_char *buf, int size); +const u_char* pcapdelay_next(pcap_t *, struct pcap_pkthdr *); +int pcapdelay_dispatch(pcap_t *, int, pcap_handler, u_char *); diff --git a/src/atbridge/port.c b/src/atbridge/port.c index eda4901..41c395a 100644 --- a/src/atbridge/port.c +++ b/src/atbridge/port.c @@ -1,139 +1,141 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** This module implements queues for storing and transferring packets within the bridge. **/ - -#include "../defc.h" -#include "atalk.h" -#include "port.h" - -void port_init(struct packet_port_t* port) -{ - if (port) - { - queue_init(&port->in); - queue_init(&port->out); - } -} - -void port_shutdown(struct packet_port_t* port) -{ - if (port) - { - queue_shutdown(&port->in); - queue_shutdown(&port->out); - } -} - -void queue_init(struct packet_queue_t* queue) -{ - if (queue) - { - queue->head = queue->tail = 0; - } -} - -void queue_shutdown(struct packet_queue_t* queue) -{ - if (queue) - { - struct packet_t* packet = dequeue(queue); - while (packet) - { - if (packet->data) - free(packet->data); - free(packet); - packet = dequeue(queue); - } - } -} - -void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) -{ - if (!queue) - return; - - struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); - packet->dest.network = dest.network; - packet->dest.node = dest.node; - packet->source.network = source.network; - packet->source.node = source.node; - packet->type = type; - packet->size = size; - packet->data = data; - enqueue_packet(queue, packet); -} - -void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet) -{ - packet->next = 0; - - if (queue->tail) - queue->tail->next = packet; - else - queue->head = packet; - queue->tail = packet; -} - -void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) -{ - if (!queue) - return; - - struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); - packet->dest.network = dest.network; - packet->dest.node = dest.node; - packet->source.network = source.network; - packet->source.node = source.node; - packet->type = type; - packet->size = size; - packet->data = data; - insert_packet(queue, packet); -} - -void insert_packet(struct packet_queue_t* queue, struct packet_t* packet) -{ - packet->next = queue->head; - queue->head = packet; - if (!queue->tail) - queue->tail = queue->head; -} - -struct packet_t* dequeue(struct packet_queue_t* queue) -{ - if (queue && queue->head) - { - struct packet_t* packet = queue->head; - if (queue->tail == queue->head) - queue->tail = queue->head = 0; - else - queue->head = packet->next; - return packet; - } - else - return 0; -} - -struct packet_t* queue_peek(struct packet_queue_t* queue) -{ - if (queue) - return queue->head; - else - return 0; -} +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** This module implements queues for storing and transferring packets within the bridge. **/ + +#include "../defc.h" +#include "atalk.h" +#include "port.h" + +void port_init(struct packet_port_t* port) +{ + if (port) + { + queue_init(&port->in); + queue_init(&port->out); + } +} + +void port_shutdown(struct packet_port_t* port) +{ + if (port) + { + queue_shutdown(&port->in); + queue_shutdown(&port->out); + } +} + +void queue_init(struct packet_queue_t* queue) +{ + if (queue) + { + queue->head = queue->tail = 0; + } +} + +void queue_shutdown(struct packet_queue_t* queue) +{ + if (queue) + { + struct packet_t* packet = dequeue(queue); + while (packet) + { + if (packet->data) + free(packet->data); + free(packet); + packet = dequeue(queue); + } + } +} + +void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) +{ + if (!queue) + return; + + struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); + packet->dest.network = dest.network; + packet->dest.node = dest.node; + packet->source.network = source.network; + packet->source.node = source.node; + packet->type = type; + packet->size = size; + packet->data = data; + enqueue_packet(queue, packet); +} + +void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet) +{ + packet->next = 0; + + if (queue->tail) + queue->tail->next = packet; + else + queue->head = packet; + queue->tail = packet; +} + +void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) +{ + if (!queue) + return; + + struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t)); + packet->dest.network = dest.network; + packet->dest.node = dest.node; + packet->source.network = source.network; + packet->source.node = source.node; + packet->type = type; + packet->size = size; + packet->data = data; + insert_packet(queue, packet); +} + +void insert_packet(struct packet_queue_t* queue, struct packet_t* packet) +{ + packet->next = queue->head; + queue->head = packet; + if (!queue->tail) + queue->tail = queue->head; +} + +struct packet_t* dequeue(struct packet_queue_t* queue) +{ + if (queue && queue->head) + { + struct packet_t* packet = queue->head; + if (queue->tail == queue->head) + queue->tail = queue->head = 0; + else + queue->head = packet->next; + return packet; + } + else + return 0; +} + +struct packet_t* queue_peek(struct packet_queue_t* queue) +{ + if (queue) + return queue->head; + else + return 0; +} diff --git a/src/atbridge/port.h b/src/atbridge/port.h index 6725b2b..52fa412 100644 --- a/src/atbridge/port.h +++ b/src/atbridge/port.h @@ -1,58 +1,60 @@ -/* -GSPLUS - Advanced Apple IIGS Emulator Environment -Copyright (C) 2013-2014 by Peter Neubauer - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2 of the License, or (at your -option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct packet_t -{ - struct at_addr_t dest; - struct at_addr_t source; - byte type; - size_t size; - byte* data; - struct packet_t* next; -}; - -struct packet_queue_t -{ - struct packet_t* head; - struct packet_t* tail; -}; - -void queue_init(struct packet_queue_t* queue); -void queue_shutdown(struct packet_queue_t* queue); - -void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); -void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet); - -struct packet_t* dequeue(struct packet_queue_t* queue); -struct packet_t* queue_peek(struct packet_queue_t* queue); - -// Insert the packet at the head of the queue, contrary to normal FIFO operation. -void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); -void insert_packet(struct packet_queue_t* queue, struct packet_t* packet); - - - -struct packet_port_t -{ - struct packet_queue_t in; - struct packet_queue_t out; -}; - -void port_init(struct packet_port_t* port); -void port_shutdown(struct packet_port_t* port); \ No newline at end of file +/* +GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + +Copyright (C) 2013-2014 by Peter Neubauer + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct packet_t +{ + struct at_addr_t dest; + struct at_addr_t source; + byte type; + size_t size; + byte* data; + struct packet_t* next; +}; + +struct packet_queue_t +{ + struct packet_t* head; + struct packet_t* tail; +}; + +void queue_init(struct packet_queue_t* queue); +void queue_shutdown(struct packet_queue_t* queue); + +void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); +void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet); + +struct packet_t* dequeue(struct packet_queue_t* queue); +struct packet_t* queue_peek(struct packet_queue_t* queue); + +// Insert the packet at the head of the queue, contrary to normal FIFO operation. +void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]); +void insert_packet(struct packet_queue_t* queue, struct packet_t* packet); + + + +struct packet_port_t +{ + struct packet_queue_t in; + struct packet_queue_t out; +}; + +void port_init(struct packet_port_t* port); +void port_shutdown(struct packet_port_t* port); diff --git a/src/clock.c b/src/clock.c index 91f1d9b..25f630d 100644 --- a/src/clock.c +++ b/src/clock.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -29,7 +31,7 @@ #endif extern int Verbose; -extern word32 g_vbl_count; // OG change int to word32 +extern word32 g_vbl_count; // OG change int to word32 extern int g_rom_version; extern int g_config_gsport_update_needed; @@ -108,7 +110,7 @@ micro_sleep(double dtime) #endif #ifdef _WIN32 - Sleep((DWORD)(dtime * 1000)); + Sleep((DWORD)(dtime * 1000)); #else Timer.tv_sec = 0; Timer.tv_usec = (dtime * 1000000.0); @@ -141,13 +143,13 @@ clk_bram_set(int bram_num, int offset, int val) g_bram[bram_num][offset] = val; } - -extern void x_clk_setup_bram_version(); - + +extern void x_clk_setup_bram_version(); + void clk_setup_bram_version() { - x_clk_setup_bram_version(); + x_clk_setup_bram_version(); } void @@ -204,29 +206,29 @@ update_cur_time() time_t cur_time; unsigned int secs, secs2; - -#ifdef UNDER_CE // OG Not supported on WIndows CE - /* - SYSTEMTIME stime; - FILETIME ftime; - GetLocalTime(&stime); - SystemTimeToFileTime(&stime,&ftime); - cur_time = ftime.dwLowDateTime; - */ - cur_time = time(0); - - secs=0; - secs2=0; - -#else + +#ifdef UNDER_CE // OG Not supported on WIndows CE + /* + SYSTEMTIME stime; + FILETIME ftime; + GetLocalTime(&stime); + SystemTimeToFileTime(&stime,&ftime); + cur_time = ftime.dwLowDateTime; + */ + cur_time = time(0); + + secs=0; + secs2=0; + +#else cur_time = time(0); /* Figure out the timezone (effectively) by diffing two times. */ /* this is probably not right for a few hours around daylight savings*/ /* time transition */ - secs2 = (unsigned int)mktime(gmtime(&cur_time)); + secs2 = (unsigned int)mktime(gmtime(&cur_time)); tm_ptr = localtime(&cur_time); - secs = (unsigned int)mktime(tm_ptr); + secs = (unsigned int)mktime(tm_ptr); #ifdef MAC /* Mac OS X's mktime function modifies the tm_ptr passed in for */ @@ -241,7 +243,7 @@ update_cur_time() secs += 3600; } #endif -#endif +#endif /* add in secs to make date based on Apple Jan 1, 1904 instead of */ /* Unix's Jan 1, 1970 */ /* So add in 66 years and 17 leap year days (1904 is a leap year) */ diff --git a/src/compile_time.c b/src/compile_time.c index 83c9dc5..2de63d4 100644 --- a/src/compile_time.c +++ b/src/compile_time.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/config.c b/src/config.c index 47e1bc6..3e017a8 100644 --- a/src/config.c +++ b/src/config.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2014 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -97,17 +99,17 @@ extern char* g_printer_font_courier; extern char* g_printer_font_script; extern char* g_printer_font_ocra; extern int g_printer_timeout; - + extern int g_imagewriter; extern int g_imagewriter_dpi; extern char* g_imagewriter_output; extern int g_imagewriter_multipage; extern int g_imagewriter_timeout; extern char* g_imagewriter_fixed_font; -extern char* g_imagewriter_prop_font; +extern char* g_imagewriter_prop_font; extern int g_imagewriter_paper; -extern int g_imagewriter_banner; - +extern int g_imagewriter_banner; + #if defined(_WIN32) || defined(__CYGWIN__) extern int g_win_show_console_request; extern int g_win_status_debug_request; @@ -197,14 +199,14 @@ Cfg_menu g_cfg_disk_menu[] = { { 0, 0, 0, 0, 0 }, }; -// OG Use define instead of const for joystick_types -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) - +// OG Use define instead of const for joystick_types +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + Cfg_menu g_cfg_joystick_menu[] = { { "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, -{ "Joystick Emulation,"TOSTRING(JOYSTICK_TYPE_KEYPAD)",Keypad Joystick,"TOSTRING(JOYSTICK_TYPE_MOUSE)",Mouse Joystick,"TOSTRING(JOYSTICK_TYPE_NATIVE_1)",Native Joystick 1," - TOSTRING(JOYSTICK_TYPE_NATIVE_2)",Native Joystick 2,"TOSTRING(JOYSTICK_TYPE_NONE)",No Joystick", KNMP(g_joystick_type), CFGTYPE_INT }, +{ "Joystick Emulation,"TOSTRING(JOYSTICK_TYPE_KEYPAD)",Keypad Joystick,"TOSTRING(JOYSTICK_TYPE_MOUSE)",Mouse Joystick,"TOSTRING(JOYSTICK_TYPE_NATIVE_1)",Native Joystick 1," + TOSTRING(JOYSTICK_TYPE_NATIVE_2)",Native Joystick 2,"TOSTRING(JOYSTICK_TYPE_NONE)",No Joystick", KNMP(g_joystick_type), CFGTYPE_INT }, { "Joystick Scale X,0x100,Standard,0x119,+10%,0x133,+20%," "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", KNMP(g_joystick_scale_factor_x), CFGTYPE_INT }, @@ -287,7 +289,7 @@ Cfg_menu g_cfg_ethernet_menu[] = { }; #ifdef HAVE_SDL Cfg_menu g_cfg_printer_menu[] = { -{ "Virtual Epson Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, +{ "Virtual Epson Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, { "Virtual Printer Type,0,Epson LQ", KNMP(g_printer), CFGTYPE_INT }, { "Printer DPI,60,60x60 dpi,180,180x180 dpi,360,360x360 dpi", @@ -313,36 +315,36 @@ Cfg_menu g_cfg_printer_menu[] = { { 0, 0, 0, 0, 0 }, }; -Cfg_menu g_cfg_imagewriter_menu[] = { -{ "Virtual ImageWriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, -{ "Virtual Printer Type,0,ImageWriter II,1,ImageWriter LQ", - KNMP(g_imagewriter), CFGTYPE_INT }, +Cfg_menu g_cfg_imagewriter_menu[] = { +{ "Virtual ImageWriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, +{ "Virtual Printer Type,0,ImageWriter II,1,ImageWriter LQ", + KNMP(g_imagewriter), CFGTYPE_INT }, { "Paper Size,0,US Letter (8.5x11in),1,US Legal (8.5x14in),2,ISO A4 (210 x 297mm),3,ISO B5 (176 x 250mm),4,Wide Fanfold (14 x 11in),5,Ledger (11 x 17in),6,ISO A3 (297 x 420mm)", - KNMP(g_imagewriter_paper), CFGTYPE_INT }, -{ "Printer DPI,360,360x360 dpi (Best for 8-bit software),720,720x720 dpi (Best for GS/OS & IW LQ Modes),1440,1440x1440 dpi", - KNMP(g_imagewriter_dpi), CFGTYPE_INT }, + KNMP(g_imagewriter_paper), CFGTYPE_INT }, +{ "Printer DPI,360,360x360 dpi (Best for 8-bit software),720,720x720 dpi (Best for GS/OS & IW LQ Modes),1440,1440x1440 dpi", + KNMP(g_imagewriter_dpi), CFGTYPE_INT }, { "Banner Printing (Limited To 144x144 dpi Output),0,Banner Printing Off,3,3 Pages Long,4,4 Pages Long,5,5 Pages Long,6,6 Pages Long,7,7 Pages Long,8,8 Pages Long,9,9 Pages Long,10,10 Pages Long", - KNMP(g_imagewriter_banner), CFGTYPE_INT }, -{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),colorps,Postscript (Color),printer,Direct to host printer,text,Text file", - KNMP(g_imagewriter_output), CFGTYPE_STR }, -{ "Multipage Files? (PS and Direct to Host Only),0,No,1,Yes", - KNMP(g_imagewriter_multipage), CFGTYPE_INT }, -{ "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", - KNMP(g_imagewriter_timeout), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "ImageWriter Fonts", 0, 0, 0, 0 }, -{ "-----------------", 0, 0, 0, 0 }, -{ "", 0, 0, 0, 0 }, -{ "Fixed Width Font", KNMP(g_imagewriter_fixed_font), CFGTYPE_FILE }, -{ "", 0, 0, 0, 0 }, -{ "Proportional Font", KNMP(g_imagewriter_prop_font), CFGTYPE_FILE }, + KNMP(g_imagewriter_banner), CFGTYPE_INT }, +{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),colorps,Postscript (Color),printer,Direct to host printer,text,Text file", + KNMP(g_imagewriter_output), CFGTYPE_STR }, +{ "Multipage Files? (PS and Direct to Host Only),0,No,1,Yes", + KNMP(g_imagewriter_multipage), CFGTYPE_INT }, +{ "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", + KNMP(g_imagewriter_timeout), CFGTYPE_INT }, { "", 0, 0, 0, 0 }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; -#endif - +{ "ImageWriter Fonts", 0, 0, 0, 0 }, +{ "-----------------", 0, 0, 0, 0 }, +{ "", 0, 0, 0, 0 }, +{ "Fixed Width Font", KNMP(g_imagewriter_fixed_font), CFGTYPE_FILE }, +{ "", 0, 0, 0, 0 }, +{ "Proportional Font", KNMP(g_imagewriter_prop_font), CFGTYPE_FILE }, +{ "", 0, 0, 0, 0 }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; +#endif + Cfg_menu g_cfg_devel_menu[] = { { "Developer Options", g_cfg_devel_menu, 0, 0, CFGTYPE_MENU }, #if defined(_WIN32) || defined(__CYGWIN__) @@ -2256,9 +2258,9 @@ cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change) defval = -1; curstr = 0; if(type == CFGTYPE_INT) { - iptr = (int*)menuptr->ptr; // OG Added cast + iptr = (int*)menuptr->ptr; // OG Added cast curval = *iptr; - iptr = (int*)menuptr->defptr; // OG Added cast + iptr = (int*)menuptr->defptr; // OG Added cast defval = *iptr; if(curval == defval) { g_cfg_opt_buf[3] = 'D'; /* checkmark */ @@ -2570,10 +2572,10 @@ cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, inc_amt = MAX(64, listhdrptr->max); inc_amt = MIN(inc_amt, 1024); listhdrptr->max += inc_amt; - listhdrptr->direntptr = (Cfg_dirent*)realloc(listhdrptr->direntptr, + listhdrptr->direntptr = (Cfg_dirent*)realloc(listhdrptr->direntptr, listhdrptr->max * sizeof(Cfg_dirent)); } - ptr = (char*)malloc(namelen+1+is_dir); // OG Added cast + ptr = (char*)malloc(namelen+1+is_dir); // OG Added cast strncpy(ptr, nameptr, namelen+1); if(is_dir) { strcat(ptr, "/"); @@ -2599,10 +2601,10 @@ cfg_dirent_sortfn(const void *obj1, const void *obj2) /* Called by qsort to sort directory listings */ direntptr1 = (const Cfg_dirent *)obj1; direntptr2 = (const Cfg_dirent *)obj2; -#if defined(MAC) || defined(_WIN32) - // OG - ret = 0; -// ret = strcasecmp(direntptr1->name, direntptr2->name); +#if defined(MAC) || defined(_WIN32) + // OG + ret = 0; +// ret = strcasecmp(direntptr1->name, direntptr2->name); #else ret = strcmp(direntptr1->name, direntptr2->name); #endif @@ -3042,7 +3044,7 @@ cfg_file_update_ptr(char *str) char *newstr; int len; len = strlen(str) + 1; - newstr = (char*)malloc(len); + newstr = (char*)malloc(len); memcpy(newstr, str, len); if(g_cfg_file_strptr) { if(*g_cfg_file_strptr) { @@ -3415,12 +3417,12 @@ config_control_panel() g_full_refresh_needed = -1; g_a2_screen_buffer_changed = -1; } - -void x_clk_setup_bram_version() -{ - if(g_rom_version < 3) { - g_bram_ptr = (&g_bram[0][0]); // ROM 01 - } else { - g_bram_ptr = (&g_bram[1][0]); // ROM 03 - } -} + +void x_clk_setup_bram_version() +{ + if(g_rom_version < 3) { + g_bram_ptr = (&g_bram[0][0]); // ROM 01 + } else { + g_bram_ptr = (&g_bram[1][0]); // ROM 03 + } +} diff --git a/src/config.h b/src/config.h index 0f79cc4..da97945 100644 --- a/src/config.h +++ b/src/config.h @@ -1,7 +1,9 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock - + + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/defc.h b/src/defc.h index 9ef1982..1666a9e 100644 --- a/src/defc.h +++ b/src/defc.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it @@ -21,15 +23,15 @@ #include "defcomm.h" -// OG redirect printf to console -#ifdef ACTIVEGS -#include -extern "C" int outputInfo(const char* format,...); -extern "C" int fOutputInfo(FILE*,const char* format,...); -#define printf outputInfo -#define fprintf fOutputInfo -#endif - +// OG redirect printf to console +#ifdef ACTIVEGS +#include +extern "C" int outputInfo(const char* format,...); +extern "C" int fOutputInfo(FILE*,const char* format,...); +#define printf outputInfo +#define fprintf fOutputInfo +#endif + #define STRUCT(a) typedef struct _ ## a a; struct _ ## a typedef unsigned char byte; @@ -83,45 +85,45 @@ void U_STACK_TRACE(); #endif #include -#include -#include - -#include -#include -#include - -#ifndef UNDER_CE // OG CE SPecific +#include +#include + +#include +#include +#include + +#ifndef UNDER_CE // OG CE SPecific #include #include #include #include -// OG Adding support for open -#ifdef WIN32 -#include -#endif - -#else -extern int errno; -extern int open(const char* name,int,...); -extern int read(int,char*,int); -extern int close(int); -extern int write( int fd, const void *buffer, unsigned int count ); -extern int lseek(int,int,int); -struct stat { int st_size; }; -extern int stat(const char* name, struct stat*); -extern int fstat(int, struct stat*); -#define O_RDWR 1 -#define O_BINARY 2 -#define O_RDONLY 4 -#define O_WRONLY 8 -#define O_CREAT 16 -#define O_TRUNC 32 -#define EAGAIN 11 -#define EINTR 4 - -#endif - - +// OG Adding support for open +#ifdef WIN32 +#include +#endif + +#else +extern int errno; +extern int open(const char* name,int,...); +extern int read(int,char*,int); +extern int close(int); +extern int write( int fd, const void *buffer, unsigned int count ); +extern int lseek(int,int,int); +struct stat { int st_size; }; +extern int stat(const char* name, struct stat*); +extern int fstat(int, struct stat*); +#define O_RDWR 1 +#define O_BINARY 2 +#define O_RDONLY 4 +#define O_WRONLY 8 +#define O_CREAT 16 +#define O_TRUNC 32 +#define EAGAIN 11 +#define EINTR 4 + +#endif + + #ifdef HPUX # include /* for GET_ITIMER */ #endif @@ -361,10 +363,10 @@ STRUCT(Emustate_word32list) { #include "iwm.h" #include "protos.h" -// OG Added define for joystick -#define JOYSTICK_TYPE_KEYPAD 0 -#define JOYSTICK_TYPE_MOUSE 1 -#define JOYSTICK_TYPE_NATIVE_1 2 -#define JOYSTICK_TYPE_NATIVE_2 3 -#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None -#define NB_JOYSTICK_TYPE 5 +// OG Added define for joystick +#define JOYSTICK_TYPE_KEYPAD 0 +#define JOYSTICK_TYPE_MOUSE 1 +#define JOYSTICK_TYPE_NATIVE_1 2 +#define JOYSTICK_TYPE_NATIVE_2 3 +#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None +#define NB_JOYSTICK_TYPE 5 diff --git a/src/defcomm.h b/src/defcomm.h index ba8c860..12360d1 100644 --- a/src/defcomm.h +++ b/src/defcomm.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it @@ -35,8 +37,8 @@ #define HALT_EVENT 0x10 -#define HALT_WANTTOQUIT 0x20 // OG : added WANTTOQUIT event -#define HALT_WANTTOBRK 0x40 // OG : added WANTTOBRK event +#define HALT_WANTTOQUIT 0x20 // OG : added WANTTOQUIT event +#define HALT_WANTTOBRK 0x40 // OG : added WANTTOBRK event #define MAX_BREAK_POINTS 0x20 @@ -148,11 +150,11 @@ #define BORDER_WIDTH 32 -//#define EFF_BORDER_WIDTH (BORDER_WIDTH + (640-560)) +//#define EFF_BORDER_WIDTH (BORDER_WIDTH + (640-560)) + +// OG Eff_border_widht == border side in A2 mode +#define EFF_BORDER_WIDTH (BORDER_WIDTH + (640-560)/2) -// OG Eff_border_widht == border side in A2 mode -#define EFF_BORDER_WIDTH (BORDER_WIDTH + (640-560)/2) - /* BASE_MARGIN_BOTTOM+MARGIN_TOP must equal 62. There are 262 scan lines */ /* at 60Hz (15.7KHz line rate) and so we just make 62 border lines */ #define BASE_MARGIN_TOP 32 diff --git a/src/defs.h b/src/defs.h index b53114f..6f7dbc2 100644 --- a/src/defs.h +++ b/src/defs.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/defs_instr.h b/src/defs_instr.h index 7d0832a..9fa2816 100644 --- a/src/defs_instr.h +++ b/src/defs_instr.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/dis.c b/src/dis.c index 062d682..03d953b 100644 --- a/src/dis.c +++ b/src/dis.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it @@ -61,8 +63,8 @@ char *line_ptr; int mode,old_mode; int got_num; -// OG replaced by HALT_WANTTOQUIT -//int g_quit_sim_now = 0; +// OG replaced by HALT_WANTTOQUIT +//int g_quit_sim_now = 0; int get_num() @@ -177,9 +179,9 @@ do_debug_intfc() g_fullscreen = 0; x_full_screen(0); - // OG use HALT_WANTTOQUIT instead of g_quit_sim_now - if (halt_sim&HALT_WANTTOQUIT) - { + // OG use HALT_WANTTOQUIT instead of g_quit_sim_now + if (halt_sim&HALT_WANTTOQUIT) + { printf("Exiting immediately\n"); return; } @@ -863,15 +865,15 @@ do_debug_unix() } if(load) { if(a1bank >= 0xe0 && a1bank < 0xe2) { - ret = read(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); + ret = read(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); } else { - ret = read(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); + ret = read(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); } } else { if(a1bank >= 0xe0 && a1bank < 0xe2) { - ret = write(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); + ret = write(fd,(char*)&g_slow_memory_ptr[((a1bank & 1)<<16)+a1],len); } else { - ret = write(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); + ret = write(fd,(char*)&g_memory_ptr[(a1bank << 16) + a1],len); } } printf("Read/write: addr %06x for %04x bytes, ret: %x bytes\n", diff --git a/src/disas.h b/src/disas.h index 54039db..c8f8a0d 100644 --- a/src/disas.h +++ b/src/disas.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/engine_c.c b/src/engine_c.c index a851d1c..2a5664d 100644 --- a/src/engine_c.c +++ b/src/engine_c.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it @@ -583,8 +585,8 @@ get_memory16_c(word32 addr, int cycs) double fcycs; fcycs = 0; - return get_memory_c(addr, (int)fcycs) + - (get_memory_c(addr+1, (int)fcycs) << 8); + return get_memory_c(addr, (int)fcycs) + + (get_memory_c(addr+1, (int)fcycs) << 8); } word32 @@ -593,9 +595,9 @@ get_memory24_c(word32 addr, int cycs) double fcycs; fcycs = 0; - return get_memory_c(addr, (int)fcycs) + - (get_memory_c(addr+1, (int)fcycs) << 8) + - (get_memory_c(addr+2, (int)fcycs) << 16); + return get_memory_c(addr, (int)fcycs) + + (get_memory_c(addr+1, (int)fcycs) << 8) + + (get_memory_c(addr+2, (int)fcycs) << 16); } void @@ -748,11 +750,11 @@ fixed_memory_ptrs_init() /* set g_slow_memory_ptr, g_rom_fc_ff_ptr, g_dummy_memory1_ptr, */ /* and rom_cards_ptr */ - // OG Filled allocated ptr parameter to free the memory - g_slow_memory_ptr = memalloc_align(128*1024, 0, (void**)&g_slow_memory_ptr_allocated); - g_dummy_memory1_ptr = memalloc_align(256, 1024, (void**)&g_dummy_memory1_ptr_allocated); - g_rom_fc_ff_ptr = memalloc_align(256*1024, 512, (void**)&g_rom_fc_ff_ptr_allocated); - g_rom_cards_ptr = memalloc_align(16*256, 256, (void**)&g_rom_cards_ptr_allocated); + // OG Filled allocated ptr parameter to free the memory + g_slow_memory_ptr = memalloc_align(128*1024, 0, (void**)&g_slow_memory_ptr_allocated); + g_dummy_memory1_ptr = memalloc_align(256, 1024, (void**)&g_dummy_memory1_ptr_allocated); + g_rom_fc_ff_ptr = memalloc_align(256*1024, 512, (void**)&g_rom_fc_ff_ptr_allocated); + g_rom_cards_ptr = memalloc_align(16*256, 256, (void**)&g_rom_cards_ptr_allocated); #if 0 printf("g_memory_ptr: %08x, dummy_mem: %08x, slow_mem_ptr: %08x\n", @@ -766,22 +768,22 @@ fixed_memory_ptrs_init() #endif } -// OG added fixed_memory_ptrs_shut -void fixed_memory_ptrs_shut() -{ - - free(g_slow_memory_ptr_allocated); - free(g_dummy_memory1_ptr_allocated); - free(g_rom_fc_ff_ptr_allocated); - free(g_rom_cards_ptr_allocated); - g_slow_memory_ptr=g_slow_memory_ptr_allocated= NULL; - g_dummy_memory1_ptr = g_dummy_memory1_ptr_allocated = NULL; - g_rom_fc_ff_ptr = g_rom_fc_ff_ptr_allocated = NULL; +// OG added fixed_memory_ptrs_shut +void fixed_memory_ptrs_shut() +{ + + free(g_slow_memory_ptr_allocated); + free(g_dummy_memory1_ptr_allocated); + free(g_rom_fc_ff_ptr_allocated); + free(g_rom_cards_ptr_allocated); + g_slow_memory_ptr=g_slow_memory_ptr_allocated= NULL; + g_dummy_memory1_ptr = g_dummy_memory1_ptr_allocated = NULL; + g_rom_fc_ff_ptr = g_rom_fc_ff_ptr_allocated = NULL; // g_rom_cards_ptr = g_rom_cards_ptr = NULL; // a mistake? g_rom_cards_ptr = NULL; -} +} + - word32 get_itimer() { @@ -909,7 +911,7 @@ get_remaining_operands(word32 addr, word32 opcode, word32 psr, Fplus *fplus_ptr) if((addr & 0xfffff0) == 0x00c700) { \ if(addr == 0xc700) { \ FINISH(RET_C700, 0); \ - } else if(addr == 0xc70a) { \ + } else if(addr == 0xc70a) { \ FINISH(RET_C70A, 0); \ } else if(addr == 0xc70d) { \ FINISH(RET_C70D, 0); \ diff --git a/src/fbdriver.c b/src/fbdriver.c index 5c27028..c910ca0 100644 --- a/src/fbdriver.c +++ b/src/fbdriver.c @@ -1,557 +1,559 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2013 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * fbdriver - Linux fullscreen framebuffer graphics driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "defc.h" - -void quitEmulator(); -extern int g_screen_depth; -extern word32 g_palette_8to1624[256]; -extern word32 g_a2palette_8to1624[256]; -extern word32 g_a2_screen_buffer_changed; -extern word32 g_c025_val; -#define SHIFT_DOWN ( (g_c025_val & 0x01) ) -#define CTRL_DOWN ( (g_c025_val & 0x02) ) -#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) -#define OPTION_DOWN ( (g_c025_val & 0x40) ) -#define CMD_DOWN ( (g_c025_val & 0x80) ) -extern int g_video_act_margin_left; -extern int g_video_act_margin_right; -extern int g_video_act_margin_top; -extern int g_video_act_margin_bottom; -extern int g_lores_colors[]; -extern int g_cur_a2_stat; -extern int g_a2vid_palette; -extern int g_installed_full_superhires_colormap; -extern int g_mouse_raw_x; -extern int g_mouse_raw_y; -extern word32 g_red_mask; -extern word32 g_green_mask; -extern word32 g_blue_mask; -extern int g_red_left_shift; -extern int g_green_left_shift; -extern int g_blue_left_shift; -extern int g_red_right_shift; -extern int g_green_right_shift; -extern int g_blue_right_shift; -extern Kimage g_mainwin_kimage; - -int keycode_to_a2code[128] = -{ - -1, // KEY_RESERVED - 0x35, // KEY_ESC - 0x12, // KEY_1 - 0x13, // KEY_2 - 0x14, // KEY_3 - 0x15, // KEY_4 - 0x17, // KEY_5 - 0x16, // KEY_6 - 0x1A, // KEY_7 - 0x1C, // KEY_8 - 0x19, // KEY_9 - 0x1D, // KEY_0 - 0x1B, // KEY_MINUS - 0x18, // KEY_EQUAL - 0x3B, // KEY_BACKSPACE0 - 0x30, // KEY_TAB - 0x0C, // KEY_Q - 0x0D, // KEY_W - 0x0E, // KEY_E - 0x0F, // KEY_R - 0x11, // KEY_T - 0x10, // KEY_Y - 0x20, // KEY_U - 0x22, // KEY_I - 0x1F, // KEY_O - 0x23, // KEY_P - 0x21, // KEY_LEFTBRACE - 0x1E, // KEY_RIGHTBRACE - 0x24, // KEY_ENTER - 0x36, // KEY_LEFTCTRL - 0x00, // KEY_A - 0x01, // KEY_S - 0x02, // KEY_D - 0x03, // KEY_F - 0x05, // KEY_G - 0x04, // KEY_H - 0x26, // KEY_J - 0x28, // KEY_K - 0x25, // KEY_L - 0x29, // KEY_SEMICOLON - 0x27, // KEY_APOSTROPHE - 0x32, // KEY_GRAVE - 0x38, // KEY_LEFTSHIFT - 0x2A, // KEY_BACKSLASH - 0x06, // KEY_Z - 0x07, // KEY_X - 0x08, // KEY_C - 0x09, // KEY_V - 0x0B, // KEY_B - 0x2D, // KEY_N - 0x2E, // KEY_M - 0x2B, // KEY_COMMA - 0x2F, // KEY_DOT - 0x2C, // KEY_SLASH - 0x38, // KEY_RIGHTSHIFT - 0x43, // KEY_KPASTERISK - 0x37, // KEY_LEFTALT - 0x31, // KEY_SPACE - 0x39, // KEY_CAPSLOCK - 0x7A, // KEY_F1 - 0x78, // KEY_F2 - 0x63, // KEY_F3 - 0x76, // KEY_F4 - 0x60, // KEY_F5 - 0x61, // KEY_F6 - 0x62, // KEY_F7 - 0x64, // KEY_F8 - 0x65, // KEY_F9 - 0x6D, // KEY_F10 - 0x47, // KEY_NUMLOCK - 0x37, // KEY_SCROLLLOCK - 0x59, // KEY_KP7 - 0x5B, // KEY_KP8 - 0x5C, // KEY_KP9 - 0x4E, // KEY_KPMINUS - 0x56, // KEY_KP4 - 0x57, // KEY_KP5 - 0x58, // KEY_KP6 - 0x45, // KEY_KPPLUS - 0x53, // KEY_KP1 - 0x54, // KEY_KP2 - 0x55, // KEY_KP3 - 0x52, // KEY_KP0 - 0x41, // KEY_KPDOT - -1, - -1, // KEY_ZENKAKUHANKAKU - -1, // KEY_102ND - 0x67, // KEY_F11 - 0x6F, // KEY_F12 - -1, // KEY_RO - -1, // KEY_KATAKANA - -1, // KEY_HIRAGANA - -1, // KEY_HENKAN - -1, // KEY_KATAKANAHIRAGANA - -1, // KEY_MUHENKAN - -1, // KEY_KPJPCOMMA - 0x4C, // KEY_KPENTER - 0x36, // KEY_RIGHTCTRL - 0x4B, // KEY_KPSLASH - 0x7F, // KEY_SYSRQ - 0x37, // KEY_RIGHTALT - 0x6E, // KEY_LINEFEED - 0x73, // KEY_HOME - 0x3E, // KEY_UP - 0x74, // KEY_PAGEUP - 0x3B, // KEY_LEFT - 0x3C, // KEY_RIGHT - 0x77, // KEY_END - 0x3D, // KEY_DOWN - 0x79, // KEY_PAGEDOWN - 0x72, // KEY_INSERT - 0x33, // KEY_DELETE - -1, // KEY_MACRO - -1, // KEY_MUTE - -1, // KEY_VOLUMEDOWN - -1, // KEY_VOLUMEUP - 0x7F, // KEY_POWER /* SC System Power Down */ - 0x51, // KEY_KPEQUAL - 0x4E, // KEY_KPPLUSMINUS - -1, // KEY_PAUSE - -1, // KEY_SCALE /* AL Compiz Scale (Expose) */ - 0x2B, // KEY_KPCOMMA - -1, // KEY_HANGEUL - -1, // KEY_HANJA - -1, // KEY_YEN - 0x3A, // KEY_LEFTMETA - 0x3A, // KEY_RIGHTMETA - -1 // KEY_COMPOSE -}; -struct termios org_tio; -struct fb_var_screeninfo orig_vinfo; -struct fb_var_screeninfo vinfo; -struct fb_fix_screeninfo finfo; -int pix_size, g_screen_mdepth, g_use_shmem = 1; -#define MOUSE_LBTN_DOWN 0x01 -#define MOUSE_MBTN_DOWN 0x02 -#define MOUSE_RBTN_DOWN 0x04 -#define MOUSE_LBTN_UP 0x00 -#define MOUSE_MBTN_UP 0x00 -#define MOUSE_RBTN_UP 0x00 -#define MOUSE_BTN_ACTIVE 0x07 -#define UPDATE_INPUT_MOUSE 0x10 -#define MAX_EVDEV 8 -char *fb_ptr, g_inputstate = 0; -int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0; -/* - * Clean up - */ -void xdriver_end(void) -{ - char c; - static char xexit = 0; - if (!xexit) - { - // cleanup - munmap(fb_ptr, finfo.smem_len); - ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo); - close(fbfd); - if (termfd > 0) - { - // Flush input - while (read(termfd, &c, 1) == 1); - ioctl(termfd, KDSETMODE, KD_TEXT); - tcsetattr(termfd, TCSANOW, &org_tio); - close(termfd); - } - fclose(stdout); - fclose(stderr); - while (evdevs--) - close(evfd[evdevs]); - xexit = 1; - } -} -/* - * Init framebuffer and input - */ -void dev_video_init(void) -{ - int i; - char evdevname[20]; - struct termios termio; - - // Set graphics mode on console - if ((termfd = open("/dev/tty", O_RDWR)) < 0) - { - fprintf(stderr, "Error opening tty device.\n"); - exit(-1); - } - // Save input settings. - tcgetattr(termfd, &termio); /* save current port settings */ - memcpy(&org_tio, &termio, sizeof(struct termios)); - ioctl(termfd, KDSETMODE, KD_GRAPHICS); - // Open the file for reading and writing - if ((fbfd = open("/dev/fb0", O_RDWR)) < 0) - { - fprintf(stderr, "Error opening framebuffer device.\n"); - ioctl(termfd, KDSETMODE, KD_TEXT); - exit(-1); - } - // Get variable screen information - if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) - { - fprintf(stderr, "Error reading variable screen information.\n"); - ioctl(termfd, KDSETMODE, KD_TEXT); - exit(-1); - } - // Store for reset(copy vinfo to vinfo_orig) - memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo)); - // Change variable info - //vinfo.bits_per_pixel = 8; - // Change resolution - vinfo.xres = 640; - vinfo.yres = 400; - if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) - { - fprintf(stderr, "Error setting variable screen information (640x400x8).\n"); - ioctl(termfd, KDSETMODE, KD_TEXT); - exit(-1); - } - // Get fixed screen information - if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) - { - fprintf(stderr, "Error reading fixed screen information.\n"); - ioctl(termfd, KDSETMODE, KD_TEXT); - exit(-1); - } - // map fb to user mem - fb_ptr = (char*)mmap(0, - finfo.smem_len, - PROT_READ|PROT_WRITE, - MAP_SHARED, - fbfd, - 0); - if ((int)fb_ptr == -1) - { - printf("Failed to mmap framebuffer.\n"); - ioctl(termfd, KDSETMODE, KD_TEXT); - exit (-1); - } - g_screen_depth = vinfo.bits_per_pixel; - g_screen_mdepth = g_screen_depth; - if (g_screen_depth > 8) - g_screen_mdepth = 16; - if (g_screen_depth > 16) - g_screen_mdepth = 32; - pix_size = g_screen_mdepth / 8; - if (vinfo.bits_per_pixel > 8) - { - g_red_mask = (1 << vinfo.red.length) - 1; - g_green_mask = (1 << vinfo.green.length) - 1; - g_blue_mask = (1 << vinfo.blue.length) - 1; - g_red_left_shift = vinfo.red.offset; - g_green_left_shift = vinfo.green.offset; - g_blue_left_shift = vinfo.blue.offset; - g_red_right_shift = 8 - vinfo.red.length; - g_green_right_shift = 8 - vinfo.green.length; - g_blue_right_shift = 8 - vinfo.blue.length; - } - video_get_kimages(); - if (g_screen_depth > 8) - video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth); - for (i = 0; i < 256; i++) - { - video_update_color_raw(i, g_lores_colors[i & 0xf]); - g_a2palette_8to1624[i] = g_palette_8to1624[i]; - } - fclose(stdin); - freopen("gsport.log", "w+", stdout); - freopen("gsport.err", "w+", stderr); - termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD; - termio.c_iflag = IGNPAR; - termio.c_oflag = 0; - termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */ - termio.c_cc[VTIME] = 0; /* inter-character timer unused */ - termio.c_cc[VMIN] = 0; /* non-blocking read */ - tcsetattr(termfd, TCSANOW, &termio); - // Open input event devices - for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++) - { - sprintf(evdevname, "/dev/input/event%c", evdevs + '0'); - if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0) - break; - } - g_video_act_margin_left = 0; - g_video_act_margin_right = 1; - g_video_act_margin_top = 0; - g_video_act_margin_bottom = 0; -} -/* - * Colormap - */ -__u16 cmapred[256], cmapgreen[256], cmapblue[256]; -int cmapstart, cmaplen, cmapdirty = 0; -void x_update_color(int col_num, int red, int green, int blue, word32 rgb) -{ - cmapred[col_num] = red | (red << 8); - cmapgreen[col_num] = green | (green << 8); - cmapblue[col_num] = blue | (blue << 8); - if (cmapdirty == 0) - { - cmapstart = col_num; - cmaplen = 1; - cmapdirty = 1; - } - else - { - if (col_num < cmapstart) - { - cmaplen += cmapstart - col_num; - cmapstart = col_num; - } - else if (col_num > cmapstart + cmaplen) - cmaplen = col_num - cmapstart + 1; - } -} -void x_update_physical_colormap(void) -{ - struct fb_cmap fbcol; - if (cmapdirty) - { - cmapdirty = 0; - fbcol.start = cmapstart; - fbcol.len = cmaplen; - fbcol.red = cmapred; - fbcol.green = cmapgreen; - fbcol.blue = cmapblue; - fbcol.transp = NULL; - ioctl(fbfd, FBIOPUTCMAP, &fbcol); - } -} -void show_xcolor_array(void) -{ -} -/* - * Screen update - */ -void x_get_kimage(Kimage *kimage_ptr) -{ - kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8); -} -void x_release_kimage(Kimage* kimage_ptr) -{ - if (kimage_ptr->data_ptr) - if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400) - free(kimage_ptr->data_ptr); - kimage_ptr->data_ptr = NULL; -} -void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) -{ - byte *src_ptr, *dst_ptr; - - // Copy sub-image to framebuffer - dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size; - src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size; - width *= pix_size; - while (height--) - { - memcpy(dst_ptr, src_ptr, width); - dst_ptr += finfo.line_length; - src_ptr += kimage_ptr->width_act * pix_size; - } -} -void x_push_done(void) -{ -} -/* - * NOP routines - */ -void x_dialog_create_gsport_conf(const char *str) -{ - // Just write the config file already... - config_write_config_gsport_file(); -} -int x_show_alert(int is_fatal, const char *str) -{ - // Not implemented yet - adb_all_keys_up(); - clear_fatal_logs(); - return 0; -} -void x_toggle_status_lines(void) -{ -} -void x_redraw_status_lines(void) -{ -} -void x_hide_pointer(int do_hide) -{ -} -void x_auto_repeat_on(int must) -{ -} -void x_full_screen(int do_full) -{ -} -int x_calc_ratio(float x, float y) -{ - return 1; -} -void clipboard_paste(void) -{ -} -int clipboard_get_char(void) -{ - return 0; -} -/* - * Input handling - */ -void check_input_events(void) -{ - struct input_event ev; - int i; - - for (i = 0; i < evdevs; i++) - // Check input events - while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event)) - { - if (ev.type == EV_REL) - { - if (ev.code == REL_X) - { - g_mouse_raw_x += ev.value; - if (g_mouse_raw_x < 0) - g_mouse_raw_x = 0; - if (g_mouse_raw_x > 639) - g_mouse_raw_x = 639; - } - else // REL_Y - { - g_mouse_raw_y += ev.value; - if (g_mouse_raw_y < 0) - g_mouse_raw_y = 0; - if (g_mouse_raw_y > 399) - g_mouse_raw_y = 399; - } - g_inputstate |= UPDATE_INPUT_MOUSE; - } - else if (ev.type == EV_KEY) - { - if (ev.code < 128) - { -#if 0 - if ((ev.code == KEY_F10) && SHIFT_DOWN) - { - //quitEmulator(); - iwm_shut(); - xdriver_end(); - my_exit(1); - } -#endif - if (keycode_to_a2code[ev.code] >= 0) - adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value); - } - else if (ev.code == BTN_LEFT) - { - g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN - : UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP; - } - } - else if (ev.type == EV_SYN) - { - if (g_inputstate & UPDATE_INPUT_MOUSE) - update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE); - g_inputstate &= ~UPDATE_INPUT_MOUSE; - } - } -} -static void sig_bye(int signo) -{ - xdriver_end(); - exit (-1); -} -/* - * Application entrypoint - */ -int main(int argc,char *argv[]) -{ - if (signal(SIGINT, sig_bye) == SIG_ERR) - exit(-1); - if (signal(SIGHUP, sig_bye) == SIG_ERR) - exit(-1); - gsportmain(argc, argv); - xdriver_end(); - return 0; -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2013 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * fbdriver - Linux fullscreen framebuffer graphics driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defc.h" + +void quitEmulator(); +extern int g_screen_depth; +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; +extern word32 g_a2_screen_buffer_changed; +extern word32 g_c025_val; +#define SHIFT_DOWN ( (g_c025_val & 0x01) ) +#define CTRL_DOWN ( (g_c025_val & 0x02) ) +#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) +#define OPTION_DOWN ( (g_c025_val & 0x40) ) +#define CMD_DOWN ( (g_c025_val & 0x80) ) +extern int g_video_act_margin_left; +extern int g_video_act_margin_right; +extern int g_video_act_margin_top; +extern int g_video_act_margin_bottom; +extern int g_lores_colors[]; +extern int g_cur_a2_stat; +extern int g_a2vid_palette; +extern int g_installed_full_superhires_colormap; +extern int g_mouse_raw_x; +extern int g_mouse_raw_y; +extern word32 g_red_mask; +extern word32 g_green_mask; +extern word32 g_blue_mask; +extern int g_red_left_shift; +extern int g_green_left_shift; +extern int g_blue_left_shift; +extern int g_red_right_shift; +extern int g_green_right_shift; +extern int g_blue_right_shift; +extern Kimage g_mainwin_kimage; + +int keycode_to_a2code[128] = +{ + -1, // KEY_RESERVED + 0x35, // KEY_ESC + 0x12, // KEY_1 + 0x13, // KEY_2 + 0x14, // KEY_3 + 0x15, // KEY_4 + 0x17, // KEY_5 + 0x16, // KEY_6 + 0x1A, // KEY_7 + 0x1C, // KEY_8 + 0x19, // KEY_9 + 0x1D, // KEY_0 + 0x1B, // KEY_MINUS + 0x18, // KEY_EQUAL + 0x3B, // KEY_BACKSPACE0 + 0x30, // KEY_TAB + 0x0C, // KEY_Q + 0x0D, // KEY_W + 0x0E, // KEY_E + 0x0F, // KEY_R + 0x11, // KEY_T + 0x10, // KEY_Y + 0x20, // KEY_U + 0x22, // KEY_I + 0x1F, // KEY_O + 0x23, // KEY_P + 0x21, // KEY_LEFTBRACE + 0x1E, // KEY_RIGHTBRACE + 0x24, // KEY_ENTER + 0x36, // KEY_LEFTCTRL + 0x00, // KEY_A + 0x01, // KEY_S + 0x02, // KEY_D + 0x03, // KEY_F + 0x05, // KEY_G + 0x04, // KEY_H + 0x26, // KEY_J + 0x28, // KEY_K + 0x25, // KEY_L + 0x29, // KEY_SEMICOLON + 0x27, // KEY_APOSTROPHE + 0x32, // KEY_GRAVE + 0x38, // KEY_LEFTSHIFT + 0x2A, // KEY_BACKSLASH + 0x06, // KEY_Z + 0x07, // KEY_X + 0x08, // KEY_C + 0x09, // KEY_V + 0x0B, // KEY_B + 0x2D, // KEY_N + 0x2E, // KEY_M + 0x2B, // KEY_COMMA + 0x2F, // KEY_DOT + 0x2C, // KEY_SLASH + 0x38, // KEY_RIGHTSHIFT + 0x43, // KEY_KPASTERISK + 0x37, // KEY_LEFTALT + 0x31, // KEY_SPACE + 0x39, // KEY_CAPSLOCK + 0x7A, // KEY_F1 + 0x78, // KEY_F2 + 0x63, // KEY_F3 + 0x76, // KEY_F4 + 0x60, // KEY_F5 + 0x61, // KEY_F6 + 0x62, // KEY_F7 + 0x64, // KEY_F8 + 0x65, // KEY_F9 + 0x6D, // KEY_F10 + 0x47, // KEY_NUMLOCK + 0x37, // KEY_SCROLLLOCK + 0x59, // KEY_KP7 + 0x5B, // KEY_KP8 + 0x5C, // KEY_KP9 + 0x4E, // KEY_KPMINUS + 0x56, // KEY_KP4 + 0x57, // KEY_KP5 + 0x58, // KEY_KP6 + 0x45, // KEY_KPPLUS + 0x53, // KEY_KP1 + 0x54, // KEY_KP2 + 0x55, // KEY_KP3 + 0x52, // KEY_KP0 + 0x41, // KEY_KPDOT + -1, + -1, // KEY_ZENKAKUHANKAKU + -1, // KEY_102ND + 0x67, // KEY_F11 + 0x6F, // KEY_F12 + -1, // KEY_RO + -1, // KEY_KATAKANA + -1, // KEY_HIRAGANA + -1, // KEY_HENKAN + -1, // KEY_KATAKANAHIRAGANA + -1, // KEY_MUHENKAN + -1, // KEY_KPJPCOMMA + 0x4C, // KEY_KPENTER + 0x36, // KEY_RIGHTCTRL + 0x4B, // KEY_KPSLASH + 0x7F, // KEY_SYSRQ + 0x37, // KEY_RIGHTALT + 0x6E, // KEY_LINEFEED + 0x73, // KEY_HOME + 0x3E, // KEY_UP + 0x74, // KEY_PAGEUP + 0x3B, // KEY_LEFT + 0x3C, // KEY_RIGHT + 0x77, // KEY_END + 0x3D, // KEY_DOWN + 0x79, // KEY_PAGEDOWN + 0x72, // KEY_INSERT + 0x33, // KEY_DELETE + -1, // KEY_MACRO + -1, // KEY_MUTE + -1, // KEY_VOLUMEDOWN + -1, // KEY_VOLUMEUP + 0x7F, // KEY_POWER /* SC System Power Down */ + 0x51, // KEY_KPEQUAL + 0x4E, // KEY_KPPLUSMINUS + -1, // KEY_PAUSE + -1, // KEY_SCALE /* AL Compiz Scale (Expose) */ + 0x2B, // KEY_KPCOMMA + -1, // KEY_HANGEUL + -1, // KEY_HANJA + -1, // KEY_YEN + 0x3A, // KEY_LEFTMETA + 0x3A, // KEY_RIGHTMETA + -1 // KEY_COMPOSE +}; +struct termios org_tio; +struct fb_var_screeninfo orig_vinfo; +struct fb_var_screeninfo vinfo; +struct fb_fix_screeninfo finfo; +int pix_size, g_screen_mdepth, g_use_shmem = 1; +#define MOUSE_LBTN_DOWN 0x01 +#define MOUSE_MBTN_DOWN 0x02 +#define MOUSE_RBTN_DOWN 0x04 +#define MOUSE_LBTN_UP 0x00 +#define MOUSE_MBTN_UP 0x00 +#define MOUSE_RBTN_UP 0x00 +#define MOUSE_BTN_ACTIVE 0x07 +#define UPDATE_INPUT_MOUSE 0x10 +#define MAX_EVDEV 8 +char *fb_ptr, g_inputstate = 0; +int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0; +/* + * Clean up + */ +void xdriver_end(void) +{ + char c; + static char xexit = 0; + if (!xexit) + { + // cleanup + munmap(fb_ptr, finfo.smem_len); + ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo); + close(fbfd); + if (termfd > 0) + { + // Flush input + while (read(termfd, &c, 1) == 1); + ioctl(termfd, KDSETMODE, KD_TEXT); + tcsetattr(termfd, TCSANOW, &org_tio); + close(termfd); + } + fclose(stdout); + fclose(stderr); + while (evdevs--) + close(evfd[evdevs]); + xexit = 1; + } +} +/* + * Init framebuffer and input + */ +void dev_video_init(void) +{ + int i; + char evdevname[20]; + struct termios termio; + + // Set graphics mode on console + if ((termfd = open("/dev/tty", O_RDWR)) < 0) + { + fprintf(stderr, "Error opening tty device.\n"); + exit(-1); + } + // Save input settings. + tcgetattr(termfd, &termio); /* save current port settings */ + memcpy(&org_tio, &termio, sizeof(struct termios)); + ioctl(termfd, KDSETMODE, KD_GRAPHICS); + // Open the file for reading and writing + if ((fbfd = open("/dev/fb0", O_RDWR)) < 0) + { + fprintf(stderr, "Error opening framebuffer device.\n"); + ioctl(termfd, KDSETMODE, KD_TEXT); + exit(-1); + } + // Get variable screen information + if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) + { + fprintf(stderr, "Error reading variable screen information.\n"); + ioctl(termfd, KDSETMODE, KD_TEXT); + exit(-1); + } + // Store for reset(copy vinfo to vinfo_orig) + memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo)); + // Change variable info + //vinfo.bits_per_pixel = 8; + // Change resolution + vinfo.xres = 640; + vinfo.yres = 400; + if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) + { + fprintf(stderr, "Error setting variable screen information (640x400x8).\n"); + ioctl(termfd, KDSETMODE, KD_TEXT); + exit(-1); + } + // Get fixed screen information + if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) + { + fprintf(stderr, "Error reading fixed screen information.\n"); + ioctl(termfd, KDSETMODE, KD_TEXT); + exit(-1); + } + // map fb to user mem + fb_ptr = (char*)mmap(0, + finfo.smem_len, + PROT_READ|PROT_WRITE, + MAP_SHARED, + fbfd, + 0); + if ((int)fb_ptr == -1) + { + printf("Failed to mmap framebuffer.\n"); + ioctl(termfd, KDSETMODE, KD_TEXT); + exit (-1); + } + g_screen_depth = vinfo.bits_per_pixel; + g_screen_mdepth = g_screen_depth; + if (g_screen_depth > 8) + g_screen_mdepth = 16; + if (g_screen_depth > 16) + g_screen_mdepth = 32; + pix_size = g_screen_mdepth / 8; + if (vinfo.bits_per_pixel > 8) + { + g_red_mask = (1 << vinfo.red.length) - 1; + g_green_mask = (1 << vinfo.green.length) - 1; + g_blue_mask = (1 << vinfo.blue.length) - 1; + g_red_left_shift = vinfo.red.offset; + g_green_left_shift = vinfo.green.offset; + g_blue_left_shift = vinfo.blue.offset; + g_red_right_shift = 8 - vinfo.red.length; + g_green_right_shift = 8 - vinfo.green.length; + g_blue_right_shift = 8 - vinfo.blue.length; + } + video_get_kimages(); + if (g_screen_depth > 8) + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth); + for (i = 0; i < 256; i++) + { + video_update_color_raw(i, g_lores_colors[i & 0xf]); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + fclose(stdin); + freopen("gsport.log", "w+", stdout); + freopen("gsport.err", "w+", stderr); + termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD; + termio.c_iflag = IGNPAR; + termio.c_oflag = 0; + termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */ + termio.c_cc[VTIME] = 0; /* inter-character timer unused */ + termio.c_cc[VMIN] = 0; /* non-blocking read */ + tcsetattr(termfd, TCSANOW, &termio); + // Open input event devices + for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++) + { + sprintf(evdevname, "/dev/input/event%c", evdevs + '0'); + if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0) + break; + } + g_video_act_margin_left = 0; + g_video_act_margin_right = 1; + g_video_act_margin_top = 0; + g_video_act_margin_bottom = 0; +} +/* + * Colormap + */ +__u16 cmapred[256], cmapgreen[256], cmapblue[256]; +int cmapstart, cmaplen, cmapdirty = 0; +void x_update_color(int col_num, int red, int green, int blue, word32 rgb) +{ + cmapred[col_num] = red | (red << 8); + cmapgreen[col_num] = green | (green << 8); + cmapblue[col_num] = blue | (blue << 8); + if (cmapdirty == 0) + { + cmapstart = col_num; + cmaplen = 1; + cmapdirty = 1; + } + else + { + if (col_num < cmapstart) + { + cmaplen += cmapstart - col_num; + cmapstart = col_num; + } + else if (col_num > cmapstart + cmaplen) + cmaplen = col_num - cmapstart + 1; + } +} +void x_update_physical_colormap(void) +{ + struct fb_cmap fbcol; + if (cmapdirty) + { + cmapdirty = 0; + fbcol.start = cmapstart; + fbcol.len = cmaplen; + fbcol.red = cmapred; + fbcol.green = cmapgreen; + fbcol.blue = cmapblue; + fbcol.transp = NULL; + ioctl(fbfd, FBIOPUTCMAP, &fbcol); + } +} +void show_xcolor_array(void) +{ +} +/* + * Screen update + */ +void x_get_kimage(Kimage *kimage_ptr) +{ + kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8); +} +void x_release_kimage(Kimage* kimage_ptr) +{ + if (kimage_ptr->data_ptr) + if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400) + free(kimage_ptr->data_ptr); + kimage_ptr->data_ptr = NULL; +} +void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) +{ + byte *src_ptr, *dst_ptr; + + // Copy sub-image to framebuffer + dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size; + src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size; + width *= pix_size; + while (height--) + { + memcpy(dst_ptr, src_ptr, width); + dst_ptr += finfo.line_length; + src_ptr += kimage_ptr->width_act * pix_size; + } +} +void x_push_done(void) +{ +} +/* + * NOP routines + */ +void x_dialog_create_gsport_conf(const char *str) +{ + // Just write the config file already... + config_write_config_gsport_file(); +} +int x_show_alert(int is_fatal, const char *str) +{ + // Not implemented yet + adb_all_keys_up(); + clear_fatal_logs(); + return 0; +} +void x_toggle_status_lines(void) +{ +} +void x_redraw_status_lines(void) +{ +} +void x_hide_pointer(int do_hide) +{ +} +void x_auto_repeat_on(int must) +{ +} +void x_full_screen(int do_full) +{ +} +int x_calc_ratio(float x, float y) +{ + return 1; +} +void clipboard_paste(void) +{ +} +int clipboard_get_char(void) +{ + return 0; +} +/* + * Input handling + */ +void check_input_events(void) +{ + struct input_event ev; + int i; + + for (i = 0; i < evdevs; i++) + // Check input events + while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event)) + { + if (ev.type == EV_REL) + { + if (ev.code == REL_X) + { + g_mouse_raw_x += ev.value; + if (g_mouse_raw_x < 0) + g_mouse_raw_x = 0; + if (g_mouse_raw_x > 639) + g_mouse_raw_x = 639; + } + else // REL_Y + { + g_mouse_raw_y += ev.value; + if (g_mouse_raw_y < 0) + g_mouse_raw_y = 0; + if (g_mouse_raw_y > 399) + g_mouse_raw_y = 399; + } + g_inputstate |= UPDATE_INPUT_MOUSE; + } + else if (ev.type == EV_KEY) + { + if (ev.code < 128) + { +#if 0 + if ((ev.code == KEY_F10) && SHIFT_DOWN) + { + //quitEmulator(); + iwm_shut(); + xdriver_end(); + my_exit(1); + } +#endif + if (keycode_to_a2code[ev.code] >= 0) + adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value); + } + else if (ev.code == BTN_LEFT) + { + g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN + : UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP; + } + } + else if (ev.type == EV_SYN) + { + if (g_inputstate & UPDATE_INPUT_MOUSE) + update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE); + g_inputstate &= ~UPDATE_INPUT_MOUSE; + } + } +} +static void sig_bye(int signo) +{ + xdriver_end(); + exit (-1); +} +/* + * Application entrypoint + */ +int main(int argc,char *argv[]) +{ + if (signal(SIGINT, sig_bye) == SIG_ERR) + exit(-1); + if (signal(SIGHUP, sig_bye) == SIG_ERR) + exit(-1); + gsportmain(argc, argv); + xdriver_end(); + return 0; +} diff --git a/src/gsport.sln b/src/gsport.sln index 2b6c137..9a17a1d 100644 --- a/src/gsport.sln +++ b/src/gsport.sln @@ -1,36 +1,36 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2012 for Windows Desktop -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsport", "gsport.vcxproj", "{0B4E527A-DB50-4B5F-9B08-303ABAF7356A}" - ProjectSection(ProjectDependencies) = postProject - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} = {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} - {E810477A-E004-4308-A58A-21393213EF89} = {E810477A-E004-4308-A58A-21393213EF89} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tfe", "tfe\tfe.vcxproj", "{E810477A-E004-4308-A58A-21393213EF89}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "atbridge", "atbridge\atbridge.vcxproj", "{2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Debug|Win32.ActiveCfg = Debug|Win32 - {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Debug|Win32.Build.0 = Debug|Win32 - {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Release|Win32.ActiveCfg = Release|Win32 - {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Release|Win32.Build.0 = Release|Win32 - {E810477A-E004-4308-A58A-21393213EF89}.Debug|Win32.ActiveCfg = Debug|Win32 - {E810477A-E004-4308-A58A-21393213EF89}.Debug|Win32.Build.0 = Debug|Win32 - {E810477A-E004-4308-A58A-21393213EF89}.Release|Win32.ActiveCfg = Release|Win32 - {E810477A-E004-4308-A58A-21393213EF89}.Release|Win32.Build.0 = Release|Win32 - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Debug|Win32.ActiveCfg = Debug|Win32 - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Debug|Win32.Build.0 = Debug|Win32 - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Release|Win32.ActiveCfg = Release|Win32 - {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsport", "gsport.vcxproj", "{0B4E527A-DB50-4B5F-9B08-303ABAF7356A}" + ProjectSection(ProjectDependencies) = postProject + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} = {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B} + {E810477A-E004-4308-A58A-21393213EF89} = {E810477A-E004-4308-A58A-21393213EF89} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tfe", "tfe\tfe.vcxproj", "{E810477A-E004-4308-A58A-21393213EF89}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "atbridge", "atbridge\atbridge.vcxproj", "{2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Debug|Win32.Build.0 = Debug|Win32 + {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Release|Win32.ActiveCfg = Release|Win32 + {0B4E527A-DB50-4B5F-9B08-303ABAF7356A}.Release|Win32.Build.0 = Release|Win32 + {E810477A-E004-4308-A58A-21393213EF89}.Debug|Win32.ActiveCfg = Debug|Win32 + {E810477A-E004-4308-A58A-21393213EF89}.Debug|Win32.Build.0 = Debug|Win32 + {E810477A-E004-4308-A58A-21393213EF89}.Release|Win32.ActiveCfg = Release|Win32 + {E810477A-E004-4308-A58A-21393213EF89}.Release|Win32.Build.0 = Release|Win32 + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Debug|Win32.ActiveCfg = Debug|Win32 + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Debug|Win32.Build.0 = Debug|Win32 + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Release|Win32.ActiveCfg = Release|Win32 + {2C88133A-7CB8-4C03-AF4D-4ECFC6F8500B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/gsport.vcxproj b/src/gsport.vcxproj index 270c7d8..18a19b7 100644 --- a/src/gsport.vcxproj +++ b/src/gsport.vcxproj @@ -1,203 +1,203 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {0B4E527A-DB50-4B5F-9B08-303ABAF7356A} - Win32Proj - gsport - - - - Application - true - MultiByte - v120 - - - Application - false - true - MultiByte - v120 - - - - - - - - - - - - - true - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN_SOUND;GSPORT_LITTLE_ENDIAN;HAVE_TFE;HAVE_ATBRIDGE;TOGGLE_STATUS;%(PreprocessorDefinitions) - CompileAsC - Speed - true - ProgramDatabase - EnableFastChecks - Prompt - true - true - false - - - Console - true - IPHLPAPI.lib;Winmm.lib;Ws2_32.lib;Shlwapi.lib;$(SolutionDir)$(Configuration)\tfe.lib;;$(SolutionDir)$(Configuration)\atbridge.lib;%(AdditionalDependencies) - MachineX86 - - - - - Level3 - NotUsing - Full - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN_SOUND;GSPORT_LITTLE_ENDIAN;HAVE_ATBRIDGE;HAVE_TFE;TOGGLE_STATUS;%(PreprocessorDefinitions) - Speed - false - CompileAsC - Prompt - StreamingSIMDExtensions2 - AnySuitable - true - true - - - Console - true - true - true - IPHLPAPI.lib;Winmm.lib;Ws2_32.lib;Shlwapi.lib;$(SolutionDir)$(Configuration)\tfe.lib;;$(SolutionDir)$(Configuration)\atbridge.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - perl make_inst c 8 instable.h > 8inst_c.h -perl make_inst c 16 instable.h > 16inst_c.h -perl make_inst s 8 instable.h > 8inst_s.h -perl make_inst s 16 instable.h > 16inst_s.h - 8inst_c.h 16inst_c.h 8inst_s.h 16inst_s.h - false - perl make_inst c 8 instable.h > 8inst_c.h -perl make_inst c 16 instable.h > 16inst_c.h -perl make_inst s 8 instable.h > 8inst_s.h -perl make_inst s 16 instable.h > 16inst_s.h - 8inst_c.h 16inst_c.h 8inst_s.h 16inst_s.h - false - - - - - - - - - - - - - - - - - - - - - - - perl make_size c size_tab.h > size_c.h -perl make_size s size_tab.h > size_s.h -perl make_size 8 size_tab.h > 8size_s.h -perl make_size 16 size_tab.h > 16size_s.h -perl make_size c size_tab.h > size_c.h - size_c.h size_s.h 8size_s.h 16size_s.h - false - perl make_size c size_tab.h > size_c.h -perl make_size s size_tab.h > size_s.h -perl make_size 8 size_tab.h > 8size_s.h -perl make_size 16 size_tab.h > 16size_s.h -perl make_size c size_tab.h > size_c.h - size_c.h size_s.h 8size_s.h 16size_s.h - false - - - - - - - - - - - - - - - - - - - - - CompileAsCpp - CompileAsCpp - - - - CompileAsCpp - CompileAsCpp - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + Debug + Win32 + + + Release + Win32 + + + + {0B4E527A-DB50-4B5F-9B08-303ABAF7356A} + Win32Proj + gsport + + + + Application + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + + + + + + + + + + + true + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN_SOUND;GSPORT_LITTLE_ENDIAN;HAVE_TFE;HAVE_ATBRIDGE;TOGGLE_STATUS;%(PreprocessorDefinitions) + CompileAsC + Speed + true + ProgramDatabase + EnableFastChecks + Prompt + true + true + false + + + Console + true + IPHLPAPI.lib;Winmm.lib;Ws2_32.lib;Shlwapi.lib;$(SolutionDir)$(Configuration)\tfe.lib;;$(SolutionDir)$(Configuration)\atbridge.lib;%(AdditionalDependencies) + MachineX86 + + + + + Level3 + NotUsing + Full + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN_SOUND;GSPORT_LITTLE_ENDIAN;HAVE_ATBRIDGE;HAVE_TFE;TOGGLE_STATUS;%(PreprocessorDefinitions) + Speed + false + CompileAsC + Prompt + StreamingSIMDExtensions2 + AnySuitable + true + true + + + Console + true + true + true + IPHLPAPI.lib;Winmm.lib;Ws2_32.lib;Shlwapi.lib;$(SolutionDir)$(Configuration)\tfe.lib;;$(SolutionDir)$(Configuration)\atbridge.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + perl make_inst c 8 instable.h > 8inst_c.h +perl make_inst c 16 instable.h > 16inst_c.h +perl make_inst s 8 instable.h > 8inst_s.h +perl make_inst s 16 instable.h > 16inst_s.h + 8inst_c.h 16inst_c.h 8inst_s.h 16inst_s.h + false + perl make_inst c 8 instable.h > 8inst_c.h +perl make_inst c 16 instable.h > 16inst_c.h +perl make_inst s 8 instable.h > 8inst_s.h +perl make_inst s 16 instable.h > 16inst_s.h + 8inst_c.h 16inst_c.h 8inst_s.h 16inst_s.h + false + + + + + + + + + + + + + + + + + + + + + + + perl make_size c size_tab.h > size_c.h +perl make_size s size_tab.h > size_s.h +perl make_size 8 size_tab.h > 8size_s.h +perl make_size 16 size_tab.h > 16size_s.h +perl make_size c size_tab.h > size_c.h + size_c.h size_s.h 8size_s.h 16size_s.h + false + perl make_size c size_tab.h > size_c.h +perl make_size s size_tab.h > size_s.h +perl make_size 8 size_tab.h > 8size_s.h +perl make_size 16 size_tab.h > 16size_s.h +perl make_size c size_tab.h > size_c.h + size_c.h size_s.h 8size_s.h 16size_s.h + false + + + + + + + + + + + + + + + + + + + + + CompileAsCpp + CompileAsCpp + + + + CompileAsCpp + CompileAsCpp + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gsport.vcxproj.filters b/src/gsport.vcxproj.filters index bb358ff..59b4026 100644 --- a/src/gsport.vcxproj.filters +++ b/src/gsport.vcxproj.filters @@ -1,217 +1,217 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + diff --git a/src/gsport32.rc b/src/gsport32.rc index efad538..228aff4 100644 --- a/src/gsport32.rc +++ b/src/gsport32.rc @@ -1,209 +1,209 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource." - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDC_GSPORT32 MENU -BEGIN - POPUP "&Emulator" - BEGIN - MENUITEM "&Set Disk Configuration\tALT-F1", ID_FILE_DISK - MENUITEM "Send CTRL Reset\tCTRL-BREAK", ID_FILE_SENDRESET - MENUITEM "Reboot\tCTRL-ALT-BREAK", ID_FILE_SENDREBOOT - MENUITEM SEPARATOR - MENUITEM "Flush Printer", ID_FILE_FLUSHPRINTER - MENUITEM "Toggle &Joystick", ID_FILE_JOYSTICK - MENUITEM "Toggle Debug Statistics", ID_FILE_DEBUGSTAT - MENUITEM SEPARATOR - MENUITEM "E&xit\tALT-F4", ID_FILE_EXIT - END - POPUP "&Help" - BEGIN - MENUITEM "Key Commands", ID_HELP_KEY - MENUITEM SEPARATOR - MENUITEM "&About", ID_HELP_ABOUT - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDC_GSPORT32 BITMAP "wintoolbar.bmp" - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDR_ACCEL ACCELERATORS -BEGIN - VK_F1, ID_FILE_DISK, VIRTKEY, ALT, NOINVERT - VK_F4, ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDC_GSPORT32 ICON "gsport32.ico" -GSPORT32_ICON ICON "gsport32.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUT_DIALOG DIALOGEX 0, 0, 207, 82 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "About" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "OK",IDOK,78,61,50,14 - LTEXT "GSport: GS Emulator.\nBased on KEGS by Kent Dickey\nWindows Port by Chea Chee Keong\n\nThis software is free for non-commercial use.",IDC_STATIC,38,7,162,45,NOT WS_GROUP - ICON "GSPORT32_ICON",IDC_STATIC,7,7,20,20 -END - -IDD_DLG_DISKCONF DIALOGEX 0, 0, 268, 182 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Disk Configuration" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,150,161,50,14 - PUSHBUTTON "Cancel",IDCANCEL,203,161,50,14 - LTEXT "S5D1",IDC_STATIC,19,46,19,8 - EDITTEXT IDC_EDIT_S5D1,43,42,156,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S5D1,203,42,50,14 - LTEXT "S5D2",IDC_STATIC,19,62,19,8 - EDITTEXT IDC_EDIT_S5D2,43,60,155,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S5D2,203,60,50,14 - LTEXT "S6D1",IDC_STATIC,19,80,19,8 - EDITTEXT IDC_EDIT_S6D1,43,77,156,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S6D1,203,77,50,14 - LTEXT "S6D2",IDC_STATIC,19,98,19,8 - EDITTEXT IDC_EDIT_S6D2,43,95,156,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S6D2,203,96,50,14 - LTEXT "S7D1",IDC_STATIC,19,118,19,8 - EDITTEXT IDC_EDIT_S7D1,43,115,155,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S7D1,203,115,50,14 - LTEXT "S7D2",IDC_STATIC,19,137,19,8 - EDITTEXT IDC_EDIT_S7D2,43,135,155,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S7D2,203,135,50,14 - GROUPBOX "Disk settings",IDC_STATIC,7,7,254,148 - LTEXT "Configure your disk images for each drive. Disk image formats supported\nare *.2MG,*.PO and *.DSK. ",IDC_STATIC,19,20,234,16 -END - -IDD_SPEEDDIALOG DIALOG 0, 0, 240, 129 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Speed Control" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "1 MHz",IDC_SLOW,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,41,51,13 - CONTROL "2.5 MHz",IDC_NORMAL,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,55,43,13 - CONTROL "As fast as possible",IDC_FASTEST,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,69,74,13 - CONTROL "Custom (MHz)",IDC_CUSTOM,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,83,69,13 - EDITTEXT IDC_EDITCUSTOM,117,83,79,13,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,133,107,50,15 - PUSHBUTTON "Cancel",IDCANCEL,183,107,50,15 - GROUPBOX "Speed Control",IDC_STATIC,7,7,226,96,WS_GROUP - LTEXT "Adjust the speed of your emulator by selecting the appropriate speed control",IDC_STATIC,46,19,181,19,NOT WS_GROUP - ICON IDC_GSPORT32,IDC_STATIC,14,19,21,20 -END - -IDD_GSPORT32_KEY DIALOGEX 0, 0, 186, 172 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Help About Key Commands" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "OK",IDOK,65,151,50,14 - LTEXT "GSport Key Commands",IDC_STATIC,7,7,82,10 - LTEXT "Alt/F1\t\tOpen-Apple\nF2\t\tClose-Apple\nF7\t\tToggle Fast Disk Emulation\nF8\t\tToggle Mouse Pointer\n\t\tDisplay\n",IDC_STATIC,21,25,151,42 - LTEXT "F11\t\tToggle Fullscreen Display\nF12\t\tReset\nCtrl-Alt-Break\tReboot Emulator\nCtrl-Alt-Esc\tControl-Panel\nCtrl-Break\tReset Emulator",IDC_STATIC,21,66,141,50 - CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | WS_DISABLED | WS_BORDER,7,17,172,1 - LTEXT "For more information, please consult the readme.gsport file",IDC_STATIC,21,124,144,19 -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - ID_FILE_DISK "Disk Configuration" -END - -STRINGTABLE -BEGIN - ID_SPEED_1MHZ "Set Speed to 1 Mhz" - ID_SPEED_2MHZ "Set Speed to 2.5 Mhz" - ID_SPEED_FMHZ "Set Speed to as fast as possible" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource." + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_GSPORT32 MENU +BEGIN + POPUP "&Emulator" + BEGIN + MENUITEM "&Set Disk Configuration\tALT-F1", ID_FILE_DISK + MENUITEM "Send CTRL Reset\tCTRL-BREAK", ID_FILE_SENDRESET + MENUITEM "Reboot\tCTRL-ALT-BREAK", ID_FILE_SENDREBOOT + MENUITEM SEPARATOR + MENUITEM "Flush Printer", ID_FILE_FLUSHPRINTER + MENUITEM "Toggle &Joystick", ID_FILE_JOYSTICK + MENUITEM "Toggle Debug Statistics", ID_FILE_DEBUGSTAT + MENUITEM SEPARATOR + MENUITEM "E&xit\tALT-F4", ID_FILE_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "Key Commands", ID_HELP_KEY + MENUITEM SEPARATOR + MENUITEM "&About", ID_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDC_GSPORT32 BITMAP "wintoolbar.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCEL ACCELERATORS +BEGIN + VK_F1, ID_FILE_DISK, VIRTKEY, ALT, NOINVERT + VK_F4, ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDC_GSPORT32 ICON "gsport32.ico" +GSPORT32_ICON ICON "gsport32.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT_DIALOG DIALOGEX 0, 0, 207, 82 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,78,61,50,14 + LTEXT "GSport: GS Emulator.\nBased on KEGS by Kent Dickey\nWindows Port by Chea Chee Keong\n\nThis software is free for non-commercial use.",IDC_STATIC,38,7,162,45,NOT WS_GROUP + ICON "GSPORT32_ICON",IDC_STATIC,7,7,20,20 +END + +IDD_DLG_DISKCONF DIALOGEX 0, 0, 268, 182 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disk Configuration" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,150,161,50,14 + PUSHBUTTON "Cancel",IDCANCEL,203,161,50,14 + LTEXT "S5D1",IDC_STATIC,19,46,19,8 + EDITTEXT IDC_EDIT_S5D1,43,42,156,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S5D1,203,42,50,14 + LTEXT "S5D2",IDC_STATIC,19,62,19,8 + EDITTEXT IDC_EDIT_S5D2,43,60,155,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S5D2,203,60,50,14 + LTEXT "S6D1",IDC_STATIC,19,80,19,8 + EDITTEXT IDC_EDIT_S6D1,43,77,156,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S6D1,203,77,50,14 + LTEXT "S6D2",IDC_STATIC,19,98,19,8 + EDITTEXT IDC_EDIT_S6D2,43,95,156,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S6D2,203,96,50,14 + LTEXT "S7D1",IDC_STATIC,19,118,19,8 + EDITTEXT IDC_EDIT_S7D1,43,115,155,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S7D1,203,115,50,14 + LTEXT "S7D2",IDC_STATIC,19,137,19,8 + EDITTEXT IDC_EDIT_S7D2,43,135,155,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S7D2,203,135,50,14 + GROUPBOX "Disk settings",IDC_STATIC,7,7,254,148 + LTEXT "Configure your disk images for each drive. Disk image formats supported\nare *.2MG,*.PO and *.DSK. ",IDC_STATIC,19,20,234,16 +END + +IDD_SPEEDDIALOG DIALOG 0, 0, 240, 129 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Speed Control" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "1 MHz",IDC_SLOW,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,41,51,13 + CONTROL "2.5 MHz",IDC_NORMAL,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,55,43,13 + CONTROL "As fast as possible",IDC_FASTEST,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,69,74,13 + CONTROL "Custom (MHz)",IDC_CUSTOM,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,45,83,69,13 + EDITTEXT IDC_EDITCUSTOM,117,83,79,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,133,107,50,15 + PUSHBUTTON "Cancel",IDCANCEL,183,107,50,15 + GROUPBOX "Speed Control",IDC_STATIC,7,7,226,96,WS_GROUP + LTEXT "Adjust the speed of your emulator by selecting the appropriate speed control",IDC_STATIC,46,19,181,19,NOT WS_GROUP + ICON IDC_GSPORT32,IDC_STATIC,14,19,21,20 +END + +IDD_GSPORT32_KEY DIALOGEX 0, 0, 186, 172 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Help About Key Commands" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,151,50,14 + LTEXT "GSport Key Commands",IDC_STATIC,7,7,82,10 + LTEXT "Alt/F1\t\tOpen-Apple\nF2\t\tClose-Apple\nF7\t\tToggle Fast Disk Emulation\nF8\t\tToggle Mouse Pointer\n\t\tDisplay\n",IDC_STATIC,21,25,151,42 + LTEXT "F11\t\tToggle Fullscreen Display\nF12\t\tReset\nCtrl-Alt-Break\tReboot Emulator\nCtrl-Alt-Esc\tControl-Panel\nCtrl-Break\tReset Emulator",IDC_STATIC,21,66,141,50 + CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | WS_DISABLED | WS_BORDER,7,17,172,1 + LTEXT "For more information, please consult the readme.gsport file",IDC_STATIC,21,124,144,19 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + ID_FILE_DISK "Disk Configuration" +END + +STRINGTABLE +BEGIN + ID_SPEED_1MHZ "Set Speed to 1 Mhz" + ID_SPEED_2MHZ "Set Speed to 2.5 Mhz" + ID_SPEED_FMHZ "Set Speed to as fast as possible" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/gsportfont.h b/src/gsportfont.h index ab628fd..39473b8 100644 --- a/src/gsportfont.h +++ b/src/gsportfont.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp index 1678f9e..f6505e2 100644 --- a/src/imagewriter.cpp +++ b/src/imagewriter.cpp @@ -1,2257 +1,2257 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2011 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * Copyright (C) 2002-2004 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - Modified for the GSport emulator by Christopher G. Mason 03/2014 - Extensively rewritten to provide full emulation of the Apple ImageWriter II - and LQ printers. - - Information used to write this emulator was provided by - Apple's "ImageWriter II Technical Reference Manual" - ISBN# 0-201-17766-8 - and - Apple's "ImageWriter LQ Reference Manual" - ISBN# 0-201-17751-X - */ - -#include "imagewriter.h" -#include -#include "support.h" - -//#include "png.h" -//#pragma comment( lib, "libpng.lib" ) -//#pragma comment (lib, "zdll.lib" ) - -static Imagewriter* defaultImagewriter = NULL; - -static FILE *textPrinterFile = NULL; -#ifdef WIN32 -const char* const textPrinterFileName = ".\\printer.txt"; -#else -const char* const textPrinterFileName = "./printer.txt"; -#endif - -#define PARAM16(I) (params[I+1]*256+params[I]) -#define PIXX ((Bitu)floor(curX*dpi+0.5)) -#define PIXY ((Bitu)floor(curY*dpi+0.5)) -//These ugly defines are so we can convert multibyte parameters from strings into some nice ints. -#define paramc(I) (params[I]-'0') -#define PARAM2(I) (paramc(I)*10+paramc(I+1)) -#define PARAM3(I) (paramc(I)*100+paramc(I+1)*10+paramc(I+2)) -#define PARAM4(I) (paramc(I)*1000+paramc(I+1)*100+paramc(I+2)*10+paramc(I+3)) - -static Bitu printer_timout; -static bool timeout_dirty; -static const char* document_path; -extern "C" char* g_imagewriter_fixed_font; -extern "C" char* g_imagewriter_prop_font; -extern "C" int iw_scc_write; -#include "iw_charmaps.h" - -#ifdef HAVE_SDL -void Imagewriter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal) -{ - float red=redmax/30.9; - float green=greenmax/30.9; - float blue=bluemax/30.9; - - Bit8u colormask=colorID<<=5; - - for(int i = 0; i < 32;i++) { - pal->colors[i+colormask].r=255-(red*(float)i); - pal->colors[i+colormask].g=255-(green*(float)i); - pal->colors[i+colormask].b=255-(blue*(float)i); - } -} -#endif // HAVE_SDL - -Imagewriter::Imagewriter(Bit16u dpi, Bit16u paperSize, Bit16u bannerSize, char* output, bool multipageOutput) -{ -#ifdef HAVE_SDL - if (FT_Init_FreeType(&FTlib)) - { - page = NULL; - } - else - { - SDL_Init(SDL_INIT_EVERYTHING); - this->output = output; - this->multipageOutput = multipageOutput; - this->port = port; - - if (bannerSize) - { - defaultPageWidth = ((Real64)paperSizes[0][0]/(Real64)72); - defaultPageHeight = (((Real64)paperSizes[0][1]*bannerSize)/(Real64)72); - dpi = 144; - } - else - { - defaultPageWidth = ((Real64)paperSizes[paperSize][0]/(Real64)72); - defaultPageHeight = ((Real64)paperSizes[paperSize][1]/(Real64)72); - } - this->dpi = dpi; - // Create page - page = SDL_CreateRGBSurface( - SDL_SWSURFACE, - (Bitu)(defaultPageWidth*dpi), - (Bitu)(defaultPageHeight*dpi), - 8, - 0, - 0, - 0, - 0); - - // Set a grey palette - SDL_Palette* palette = page->format->palette; - - for (Bitu i=0; i<32; i++) - { - palette->colors[i].r =255; - palette->colors[i].g =255; - palette->colors[i].b =255; - } - - // 0 = all white needed for logic 000 - FillPalette( 0, 0, 0, 1, palette); - // 1 = magenta* 001 - FillPalette( 0, 255, 0, 1, palette); - // 2 = cyan* 010 - FillPalette(255, 0, 0, 2, palette); - // 3 = "violet" 011 - FillPalette(255, 255, 0, 3, palette); - // 4 = yellow* 100 - FillPalette( 0, 0, 255, 4, palette); - // 5 = red 101 - FillPalette( 0, 255, 255, 5, palette); - // 6 = green 110 - FillPalette(255, 0, 255, 6, palette); - // 7 = black 111 - FillPalette(255, 255, 255, 7, palette); - - // 0 = all white needed for logic 000 - /*FillPalette( 0, 0, 0, 1, palette); - // 1 = yellow* 100 IW - FillPalette( 0, 0, 255, 1, palette); - // 2 = magenta* 001 IW - FillPalette( 0, 255, 0, 2, palette); - // 3 = cyan* 010 IW - FillPalette(255, 0, 0, 3, palette); - // 4 = red 101 IW - FillPalette( 0, 255, 255, 4, palette); - // 5 = green 110 IW - FillPalette(255, 0, 255, 5, palette); - // 6 = "violet" 011 IW - FillPalette(255, 255, 0, 6, palette); - // 7 = black 111 - FillPalette(255, 255, 255, 7, palette);*/ - - // yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max - // Printing colors on top of each other ORs them and gets the - // correct resulting color. - // i.e. magenta on blank page yyy=001 - // then yellow on magenta 001 | 100 = 101 = red - - color=COLOR_BLACK; - - curFont = NULL; - charRead = false; - autoFeed = false; - outputHandle = NULL; - - resetPrinter(); - //Only initialize native printer here if multipage output is off. That way the user doesn't get prompted every page. - if (strcasecmp(output, "printer") == 0 && !multipageOutput) - { -#if defined (WIN32) - // Show Print dialog to obtain a printer device context - - ShowCursor(1); - PRINTDLG pd; - pd.lStructSize = sizeof(PRINTDLG); - pd.hDevMode = (HANDLE) NULL; - pd.hDevNames = (HANDLE) NULL; - pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; - pd.hwndOwner = NULL; - pd.hDC = (HDC) NULL; - pd.nFromPage = 0xFFFF; - pd.nToPage = 0xFFFF; - pd.nMinPage = 1; - pd.nMaxPage = 0xFFFF; - pd.nCopies = 1; - pd.hInstance = NULL; - pd.lCustData = 0L; - pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; - pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; - pd.lpPrintTemplateName = (LPCSTR) NULL; - pd.lpSetupTemplateName = (LPCSTR) NULL; - pd.hPrintTemplate = (HANDLE) NULL; - pd.hSetupTemplate = (HANDLE) NULL; - if(!PrintDlg(&pd)) - { - //If user presses cancel, warn them with a dialog and switch output to bitmap files - this->output = "bmp"; - MessageBox(NULL,"You did not select a printer.\nAll printer output will be saved as bitmap files.\nTo select a printer, press F4 and select 'Reset Virtual ImageWriter'",NULL,MB_ICONEXCLAMATION); - } - printerDC = pd.hDC; - ShowCursor(0); -#endif // WIN32 - } - } -#endif // HAVE_SDL -#ifndef HAVE_SDL - this->output = output; - this->multipageOutput = multipageOutput; -#endif // !HAVE_SDL -}; - -void Imagewriter::resetPrinterHard() -{ -#ifdef HAVE_SDL - charRead = false; - resetPrinter(); -#endif // HAVE_SDL -} - -void Imagewriter::resetPrinter() -{ -#ifdef HAVE_SDL - printRes = 0; - color=COLOR_BLACK; - curX = curY = 0.0; - ESCSeen = false; - FSSeen = false; - ESCCmd = 0; - numParam = neededParam = 0; - topMargin = 0.0; - leftMargin = 0.25; //Most all Apple II software including GS/OS assume a 1/4 inch margin on an Imagewriter - rightMargin = pageWidth = defaultPageWidth; - bottomMargin = pageHeight = defaultPageHeight; - lineSpacing = (Real64)1/6; - cpi = 12.0; - printRes = 2; - style &= (0xffff - STYLE_PROP); - definedUnit = 96; - curCharTable = 1; - style = 0; - extraIntraSpace = 0.0; - printUpperContr = true; - bitGraph.remBytes = 0; - densk = 0; - densl = 1; - densy = 2; - densz = 3; - charTables[0] = 0; // Italics - charTables[1] = charTables[2] = charTables[3] = 437; - multipoint = false; - multiPointSize = 0.0; - multicpi = 0.0; - hmi = -1.0; - switcha = 0; - switchb = ' '; - numPrintAsChar = 0; - LQtypeFace = fixed; - verticalDot = 0; - selectCodepage(charTables[curCharTable]); - - updateFont(); - updateSwitch(); - -#endif // HAVE_SDL - newPage(false,true); -#ifdef HAVE_SDL - - // Default tabs => Each eight characters - /*for (Bitu i=0;i<32;i++) - horiztabs[i] = i*8*(1/(Real64)cpi);*/ - numHorizTabs = 0; - - numVertTabs = 0; -#endif // HAVE_SDL -} - - -Imagewriter::~Imagewriter(void) -{ -#ifdef HAVE_SDL - finishMultipage(); - if (page != NULL) - { - SDL_FreeSurface(page); - page = NULL; - FT_Done_FreeType(FTlib); - } -#if defined (WIN32) - DeleteDC(printerDC); -#endif -#endif // HAVE_SDL -}; - -#ifdef HAVE_SDL -void Imagewriter::selectCodepage(Bit16u cp) -{ - Bit16u *mapToUse = NULL; - - switch(cp) - { - case 0: // Italics, use cp437 - case 437: - mapToUse = (Bit16u*)&cp437Map; - break; - default: - //LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp); - mapToUse = (Bit16u*)&cp437Map; - } - - for (int i=0; i<256; i++) - curMap[i] = mapToUse[i]; -} -#endif // HAVE_SDL - -#ifdef HAVE_SDL -void Imagewriter::updateFont() -{ - // char buffer[1000]; - if (curFont != NULL) - FT_Done_Face(curFont); - - char* fontName; - - switch (LQtypeFace) - { - case fixed: - fontName = g_imagewriter_fixed_font; - break; - case prop: - fontName = g_imagewriter_prop_font; - break; - default: - fontName = g_imagewriter_fixed_font; - } - - if (FT_New_Face(FTlib, fontName, 0, &curFont)) - { - - printf("Unable to load font %s\n"); - //LOG_MSG("Unable to load font %s", fontName); - curFont = NULL; - } - - Real64 horizPoints = 10; - Real64 vertPoints = 10; - if (!multipoint) - { - actcpi = cpi; - - if (!(style & STYLE_CONDENSED)) { - horizPoints *= 10.0/cpi; - //vertPoints *= 10.0/cpi; - } - - if (!(style & STYLE_PROP)) { - if ((cpi == 10.0) && (style & STYLE_CONDENSED)) { - actcpi = 17.14; - horizPoints *= 10.0/17.14; - } - if ((cpi == 12.0) && (style & STYLE_CONDENSED)) { - actcpi = 20.0; - horizPoints *= 10.0/20.0; - vertPoints *= 10.0/12.0; - } - } else if (style & STYLE_CONDENSED) horizPoints /= 2.0; - - - if ((style & STYLE_DOUBLEWIDTH)) { - actcpi /= 2.0; - horizPoints *= 2.0; - } - } else { // multipoint true - actcpi = multicpi; - horizPoints = vertPoints = multiPointSize; - } - - if (style & STYLE_SUPERSCRIPT || style & STYLE_SUBSCRIPT || style & STYLE_HALFHEIGHT) { - //horizPoints *= 2.0/3.0; - vertPoints *= 2.0/3.0; - //actcpi /= 2.0/3.0; - } - - FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi); - - if (style & STYLE_ITALICS || charTables[curCharTable] == 0) - { - FT_Matrix matrix; - matrix.xx = 0x10000L; - matrix.xy = (FT_Fixed)(0.20 * 0x10000L); - matrix.yx = 0; - matrix.yy = 0x10000L; - FT_Set_Transform(curFont, &matrix, 0); - } -} - - -void Imagewriter::updateSwitch() -{ - //Set international character mappping (Switches A-1 to A3) - int charmap = switcha &= 7; - curMap[0x23] = intCharSets[charmap][0]; - curMap[0x40] = intCharSets[charmap][1]; - curMap[0x5b] = intCharSets[charmap][2]; - curMap[0x5c] = intCharSets[charmap][3]; - curMap[0x5d] = intCharSets[charmap][4]; - curMap[0x60] = intCharSets[charmap][5]; - curMap[0x7b] = intCharSets[charmap][6]; - curMap[0x7c] = intCharSets[charmap][7]; - curMap[0x7d] = intCharSets[charmap][8]; - curMap[0x7e] = intCharSets[charmap][9]; - //MSB control (Switch B-6) - if (!(switchb&32)) - { - msb = 255; - } - else msb = 0; -} -void Imagewriter::slashzero(Bit16u penX, Bit16u penY) -{ - FT_Face slashFont = curFont; - FT_UInt slashindex = FT_Get_Char_Index(slashFont, curMap[0x2f]); - FT_Load_Glyph(slashFont, slashindex, FT_LOAD_DEFAULT); - FT_Render_Glyph(slashFont->glyph, FT_RENDER_MODE_NORMAL); - blitGlyph(slashFont->glyph->bitmap, penX, penY, false); - blitGlyph(slashFont->glyph->bitmap, penX+1, penY, true); - if (style & STYLE_BOLD) { - blitGlyph(slashFont->glyph->bitmap, penX+1, penY, true); - blitGlyph(slashFont->glyph->bitmap, penX+2, penY, true); - blitGlyph(slashFont->glyph->bitmap, penX+3, penY, true); - } -} -#endif // HAVE_SDL - -#ifdef HAVE_SDL -bool Imagewriter::processCommandChar(Bit8u ch) -{ - if (ESCSeen || FSSeen) - { - ESCCmd = ch; - if(FSSeen) ESCCmd |= 0x800; - ESCSeen = FSSeen = false; - numParam = 0; - - switch (ESCCmd) { - case 0x21: // Select bold font (ESC !) IW - case 0x22: // Cancel bold font (ESC ") IW - case 0x24: // Cancel MSB control and Mousetext (ESC $) IW - case 0x2b: // custom char width is 8 dots (ESC -) IW - case 0x2e: // custom char width is 8 dots (ESC +) IW - case 0x30: // Clear all tabs (ESC 0) IW - case 0x31: // Insert 1 intercharacter spaces (ESC 1) IW - case 0x32: // Insert 2 intercharacter spaces (ESC 2) IW - case 0x33: // Insert 3 intercharacter spaces (ESC 3) IW - case 0x34: // Insert 4 intercharacter spaces (ESC 4) IW - case 0x35: // Insert 5 intercharacter spaces (ESC 5) IW - case 0x36: // Insert 6 intercharacter spaces (ESC 6) IW - case 0x3c: // bidirectional mode (one line) (ESC <) IW - case 0x3e: // Unidirectional mode (one line) (ESC >) IW - case 0x3f: // Send ID string (ESC ?) IW - case 0x41: // Select 1/6-inch line spacing (ESC A) IW - case 0x42: // Select 1/8-inch line spacing (ESC B) IW - case 0x45: // 12 cpi, 96 dpi graphics (ESC E) IW - case 0x4d: // Same as ESC a2 (ESC M) IW - case 0x4e: // 10 cpi, 80 dpi graphics (ESC N) IW - case 0x4f: // Disable paper-out detector (ESC O) IW - case 0x50: // Proportional, 160 dpi graphics (ESC P) IW - case 0x51: // 17 cpi, 136 dpi graphics (ESC Q) IW - case 0x57: // Cancel halfheight printing (ESC W) IW - case 0x58: // Turn underline on (ESC X) IW - case 0x59: // Turn underline off (ESC Y) IW - case 0x63: // Initialize printer (ESC c) IW - case 0x65: // 13.4 cpi, 107 dpi graphics (ESC e) IW - case 0x66: // Select forward feed mode (ESC f) IW - case 0x6b: // Select optional font (ESC k) IW LQ - case 0x6d: // Same as ESC a0 (ESC m) IW - case 0x6e: // 9 cpi, 72 dpi graphics (ESC n) IW - case 0x6f: // Enable paper-out detector (ESC o) IW - case 0x70: // Proportional, 144 dpi graphics (ESC p) IW - case 0x72: // Select reverse feed mode (ESC r) IW - case 0x71: // 15 cpi, 120 dpi graphics (ESC q) IW - case 0x77: // Select halfheight printing (ESC w) IW - case 0x78: // Select superscript printing (ESC x) IW - case 0x79: // Select subscript printing (ESC y) IW - case 0x7a: // Cancel superscript/subscript printing (ESC z) IW - neededParam = 0; - break; - case 0x3d: // Internal font ID (ESC = n) IW LQ - case 0x40: // Select output bin (ESC @ n) IW LQ - case 0x4b: // Select printing color (ESC K n) IW - case 0x61: // Select font (ESC a n) IW - case 0x6c: // Insert CR before LF and FF (ESC l n) IW - case 0x73: // Set intercharacter space (ESC s n) IW - case 0x74: // Shift printing downward n/216 inch (ESC t n) IW LQ - case 0x833: // Feed n lines of blank space (US n) IW - neededParam = 1; - break; - case 0x44: // Set soft switches to closed (on)= 1 (ESC D nn) IW - case 0x54: // Distance between lines to be nn/144 inch (ESC T nn) IW - case 0x5a: // Set soft switches to open (off) = 0 (ESC Z nn) IW - neededParam = 2; - break; - case 0x4c: // Set left margin at column nnn (ESC L nnn) IW - case 0x67: // Print graphics for next nnn * 8 databytes (ESC g nnn) IW - case 0x75: // Add one tab stop at nnn (ESC u nnn) IW - neededParam = 3; - break; - case 0x28: // Set horizontal tabs (ESC ( nnn,) IW - numHorizTabs = 0; - case 0x29: // Delete horizontal tabs (ESC ) nnn,) IW - case 0x43: // Print hi-res graphics for next nnnn*3 databytes (ESC C nnnn) IW LQ - case 0x47: // Print graphics for next nnnn databytes (ESC G nnnn) IW - case 0x46: // Place printhead nnnn dots from left margin (ESC F nnnn) IW - case 0x48: // Set pagelength to nnnn/144 (ESC H nnnn) IW - case 0x53: // Print graphics for next nnnn databytes (ESC S nnnn) IW - case 0x52: // Repeat character c nnn times (ESC R nnn c) IW - case 0x68: // Place printhead nnnn hi-res dots from left margin (ESC h nnnn) IW LQ - neededParam = 4; - break; - case 0x56: //Repeat Print nnnn repetitions of dot column c (ESC V nnnn c) IW - neededParam = 5; - msb = 255; - break; - case 0x55: //Repeat Print nnnn repetitions of hi-res dot column abc (ESC U nnnn abc) IW LQ - neededParam = 7; - msb = 255; - break; - case 0x27: // Select user-defined set (ESC ') - case 0x49: // Define user-defined characters (ESC I) - //LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!"); - return true; - default: - /*LOG_MSG("PRINTER: Unknown command %c (%02Xh) %c , unable to skip parameters.", - (ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd);*/ - - neededParam = 0; - ESCCmd = 0; - return true; - } - - if (neededParam > 0) - return true; - } - - if (numParam < neededParam) - { - params[numParam++] = ch; - - if (numParam < neededParam) - return true; - } - if (ESCCmd != 0) - { - switch (ESCCmd) - { - case 0x19: // Control paper loading/ejecting (ESC EM) - // We are not really loading paper, so most commands can be ignored - if (params[0] == 'R') - newPage(true,false); // TODO resetx? - break; - case 0x73: // Set intercharacter space (ESC s) IW - if (style & STYLE_PROP) - { - extraIntraSpace = (Real64)paramc(0); - updateFont(); - } - break; - case 0x46: // Set absolute horizontal print position (ESC F nnnn) IW - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - Real64 unitSize = definedUnit; - if (unitSize < 0) - unitSize = (Real64)72.0; - - Real64 newX = leftMargin + ((Real64)PARAM4(0)/unitSize); - if (newX <= rightMargin) - curX = newX; - } - break; - case 0x68: // Set absolute horizontal hi-res print position (ESC h nnnn) IW LQ - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - Real64 unitSize = definedUnit*2; - if (unitSize < 0) - unitSize = (Real64)72.0; - - Real64 newX = leftMargin + ((Real64)PARAM4(0)/unitSize); - if (newX <= rightMargin) - curX = newX; - } - break; - case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36:// Insert 1-6 intercharacter spaces (ESC 1 to 6) IW - { - if (style & STYLE_PROP) //This function only works in proportional mode - { - Real64 unitSize = definedUnit; - if (unitSize < 0) - unitSize = (Real64)72.0; - - Real64 newX = ((Real64)(ESCCmd-'0')/unitSize); - if (newX <= rightMargin) - curX = newX; - } - break; - } - case 0x47: case 0x53: // Print graphics (ESC G nnnn) IW - { - int x = 0; - printRes &= ~8; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - setupBitImage(printRes, PARAM4(0)); - break; - } - case 0x43: // Print hi-res graphics (ESC G nnnn) IW LQ - { - int x = 0; - printRes |= 8; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - setupBitImage(printRes, PARAM4(0)); - break; - } - case 0x67: // Print graphics (ESC g nnn) IW - { - int x = 0; - printRes &= ~8; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - setupBitImage(printRes, (PARAM3(0)*8)); - break; - } - case 0x56: //Repeat Print nnnn repetitions of dot column byte c (ESC V nnnn c)IW - { - int x = 0; - printRes &= ~8; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - x = 0; - while ( x < PARAM4(0)) - { - setupBitImage(printRes, 1); - printBitGraph(params[4]); - x++; - } - msb = 0; - break; - } - case 0x55: //Repeat Print nnnn repetitions of hi-res dot column byte abc (ESC U nnnn abc) IW LQ - { - int x = 0; - printRes |= 8; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - x = 0; - while ( x < PARAM4(0)) - { - setupBitImage(printRes, 1); - printBitGraph(params[4]); - printBitGraph(params[5]); - printBitGraph(params[6]); - x++; - } - msb = 0; - break; - } - case 0x74: // Shift printing downward n/216 inch (ESC t n) IW LQ - { - verticalDot = paramc(0); - break; - } - case 0x6e: // 9 cpi, 72/144 dpi graphics (ESC n) IW - cpi = 9.0; - style &= (0xffff - STYLE_PROP); - printRes = 0; - definedUnit = 72; - extraIntraSpace = 0.0; - LQtypeFace = fixed; - updateFont(); - break; - case 0x4e: // 10 cpi, 80/160 dpi graphics (ESC N) IW - cpi = 10.0; - printRes = 1; - style &= (0xffff - STYLE_PROP); - definedUnit = 80; - extraIntraSpace = 0.0; - LQtypeFace = fixed; - updateFont(); - break; - case 0x45: // 12 cpi, 96/192 dpi graphics (ESC E) IW - cpi = 12.0; - printRes = 2; - style &= (0xffff - STYLE_PROP); - definedUnit = 96; - extraIntraSpace = 0.0; - LQtypeFace = fixed; - updateFont(); - break; - case 0x65: // 13.4 cpi, 107/216 dpi graphics (ESC e) IW - cpi = 13.4; - printRes = 3; - style &= (0xffff - STYLE_PROP); - definedUnit = 107; - extraIntraSpace = 0.0; - LQtypeFace = fixed; - updateFont(); - break; - case 0x71: // 15 cpi, 120/240 dpi graphics (ESC q) IW - cpi = 15; - printRes = 4; - style &= (0xffff - STYLE_PROP); - definedUnit = 120; - extraIntraSpace = 0.0; - LQtypeFace = fixed; - updateFont(); - break; - case 0x51: // 17 cpi, 136/272 dpi graphics (ESC Q) IW - cpi = 17; - printRes = 5; - style &= (0xffff - STYLE_PROP); - definedUnit = 136; - extraIntraSpace = 0.0; - LQtypeFace = fixed; - updateFont(); - break; - case 0x70: // Proportional, 144/288 dpi graphics (ESC p) IW - style |= STYLE_PROP; - cpi = 10; - //printQuality = QUALITY_LQ; - printRes = 6; - definedUnit = 144; - LQtypeFace = prop; - updateFont(); - break; - case 0x50: // Proportional, 160/320 dpi graphics (ESC P) IW - style |= STYLE_PROP; - cpi = 12; - //printQuality = QUALITY_LQ; - printRes = 7; - definedUnit = 160; - LQtypeFace = prop; - updateFont(); - break; - case 0x54: // Set n/144-inch line spacing (ESC T nn) IW - lineSpacing = (Real64)PARAM2(0)/144; - break; - case 0x59: // Turn underline off (ESC Y) IW - style &= ~STYLE_UNDERLINE; - updateFont(); - break; - case 0x58: // Turn underline on (ESC X) IW - style |= STYLE_UNDERLINE; - score = SCORE_SINGLE; - updateFont(); - break; - case 0x42: // Select 1/8-inch line spacing (ESC B) IW - lineSpacing = (Real64)1/8; - break; - case 0x41: // Select 1/6-inch line spacing (ESC A) IW - lineSpacing = (Real64)1/6; - break; - case 0x3c: case 0x3e: // Unidirectional mode (one line) (ESC <) - // We don't have a print head, so just ignore this - break; - case 0x63: // Initialize printer (ESC c) IW - resetPrinter(); - break; - case 0x48: // Set page length in lines (ESC H nnnn) IW - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - pageHeight = (Real64)PARAM4(0)/144; - bottomMargin = pageHeight; - topMargin = 0.0; - break; - } - case 0x21: // Select bold font (ESC !) IW - style |= STYLE_BOLD; - updateFont(); - break; - case 0x22: // Cancel bold font (ESC ") IW - style &= ~STYLE_BOLD; - updateFont(); - break; - case 0x78: // Select superscript printing (ESC x) IW - style |= STYLE_SUPERSCRIPT; - updateFont(); - break; - case 0x79: // Select subscript printing (ESC y) IW - style |= STYLE_SUBSCRIPT; - updateFont(); - break; - case 0x7a: // Cancel superscript/subscript printing (ESC z) IW - style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; - updateFont(); - break; - case 0x77: // Select halfheight printing (ESC w) IW - style |= STYLE_HALFHEIGHT; - updateFont(); - break; - case 0x57: // Cancel halfheight printing (ESC W) IW - style &= ~STYLE_HALFHEIGHT; - updateFont(); - break; - case 0x72: // Reverse paper feed (ESC r) IW - { - printf("Reverse Feed\n"); - if(lineSpacing > 0) lineSpacing *= -1; - break; - } - case 0x66: // Forward paper feed (ESC f) IW - { - if(lineSpacing < 0) lineSpacing *= -1; - break; - } - case 0x61: // Select typeface (ESC a n) IW worry about this later - break; - case 0x6d: case 0x4d: //Same as ESC a n commands - break; - case 0x4c: // Set left margin (ESC L nnn) IW - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - leftMargin = (Real64)(PARAM3(0)-1.0) / (Real64)cpi; - if (curX < leftMargin) - curX = leftMargin; - break; - } - case 0x4b: // Select printing color (ESC K) IW - - switch (paramc(0)) - { - case 0: break; - case 1: params[0] = 4; break; - case 2: params[0] = 1; break; - case 3: params[0] = 2; break; - case 4: params[0] = 5; break; - case 5: params[0] = 6; break; - case 6: params[0] = 3; break; - } - if(paramc(0)==0) color = COLOR_BLACK; - else color = params[0]<<5; - break; - case 0x3d: // Internal font ID (ESC = n) IW LQ - //Ignore for now - break; - case 0x3f: //Send ID string to computer (ESC ?) IW - //insert SCC send code here - printf("Sending ID String\n"); - iw_scc_write = true; - break; - case 0x52: // Repeat character c for nnn times (ESC R nnn c) IW - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - x = 0; - ESCCmd = 0; - while (x < PARAM3(0)) - { - printChar(params[3]); - x++; - } - break; - } - case 0x30: //Clear all tabs - numHorizTabs = 0; - break; - case 0x28: // Set horizontal tabs (ESC ( nnn,) IW - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - if (params[3] == '.' || (numHorizTabs>0 && horiztabs[numHorizTabs-1] > (Real64)PARAM3(0)*(1/(Real64)cpi))) - { - horiztabs[numHorizTabs++] = (Real64)PARAM3(0)*(1/(Real64)cpi); - //printf("Adding tab %d, and end\n",PARAM3(0)); - //printf("Number of Tabs:%d\n",numHorizTabs); - } - else if (params[3] == ',' && numHorizTabs < 32) - { - horiztabs[numHorizTabs++] = (Real64)PARAM3(0)*(1/(Real64)cpi); - numParam = 0; - neededParam = 4; - //printf("Adding tab %d, plus more\n", PARAM3(0)); - //printf("Number of Tabs:%d\n",numHorizTabs); - return true; - } - x = 0; - break; - } - case 0x29: // Delete horizontal tabs (ESC ) nnn,) IW - { - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - x = 0; - while (x < numHorizTabs) - { - if (horiztabs[x] == (Real64)PARAM3(0)*(1/(Real64)cpi)) - { printf("Tab Found %d\n",PARAM3(0)); - horiztabs[x] = 0; - } - x++; - } - - if (params[3] == '.') - { - printf("Deleting tab %d, and end\n",PARAM3(0)); - } - else if (params[3] == ',') - { - numParam = 0; - neededParam = 4; - //printf("Deleting tab %d, plus more\n", PARAM3(0)); - return true; - } - x = 0; - break; - } - case 0x5a: // Set switches to open (off) (ESC Z nn) IW - //printf ("switcha is: %x switchb is: %x\n",switcha,switchb); - //printf ("(Setting to 0) param 0 is: %x param 1 is: %x\n",params[0],params[1]); - switcha &= ~params[0]; - switchb &= ~params[1]; - //printf ("switcha is now: %x switchb is now: %x\n",switcha,switchb); - updateSwitch(); - break; - case 0x44: // Set switches to closed (on) (ESC D nn) IW - //printf ("switcha is: %x switchb is: %x\n",switcha,switchb); - //printf ("(Setting to 1) param 0 is: %x param 1 is: %x\n",params[0],params[1]); - switcha |= params[0]; - switchb |= params[1]; - //printf ("switcha is now: %x switchb is now: %x\n",switcha,switchb); - updateSwitch(); - break; - case 0x75: // Add one tab stop at nnn (ESC u nnn) IW - { - bool haveStop = false; - int lastEmpty; - //If the list is full, we assume there are no empty spaces to fill until the list is scanned - if (numHorizTabs == 32) lastEmpty = 33; - else lastEmpty = numHorizTabs; - int x = 0; - //convert any leading spaces in parameters to zeros - while (x < 4) - { - if (params[x] == ' ') params[x] = '0'; - x++; - } - x = 0; - //see if we have the tab stop already on the list and check for any deleted entries to reuse - while (x < numHorizTabs) - { - if (horiztabs[x] == (Real64)PARAM3(0)*(1/(Real64)cpi)) - { - //printf("We have this tab already! at list entry: %d\n", x); - haveStop = true; - } - if (horiztabs[x] == 0) lastEmpty = x; - //printf("at list entry: %d\n", x); - x++; - } - if (!haveStop && lastEmpty < 33) - { - //printf("Adding tab %d\n", PARAM3(0)); - horiztabs[lastEmpty] = (Real64)PARAM3(0)*(1/(Real64)cpi); - if (lastEmpty == numHorizTabs) numHorizTabs++; //only increase if we don't reuse an empty tab entry - //printf("Number of Tabs:%d\n",numHorizTabs); - } - } - break; - case 0x833: // Feed n lines of blank space (US n) IW - { - int x = 0; - while (x < paramc(0)) - { - curY += lineSpacing; - if (curY > bottomMargin) - newPage(true,false); - x++; - } - } - break; - default: - if (ESCCmd < 0x100); - //LOG(LOG_MISC,LOG_WARN) - //LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd); - else; - //LOG(LOG_MISC,LOG_WARN) - //LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200); - } - - ESCCmd = 0; - return true; - } - - switch (ch) - { - case 0x00: // NUL is ignored by the printer - return true; - case 0x07: // Beeper (BEL) - // BEEEP! - return true; - case 0x08: // Backspace (BS) - { - Real64 newX = curX - (1/(Real64)actcpi); - if (hmi > 0) - newX = curX - hmi; - if (newX >= leftMargin) - curX = newX; - } - return true; - case 0x09: // Tab horizontally (HT) - { - // Find tab right to current pos - Real64 moveTo = -1; - for (Bit8u i=0; i curX) - moveTo = horiztabs[i]; - // Nothing found => Ignore - if (moveTo > 0 && moveTo < rightMargin) - curX = moveTo; - } - return true; - case 0x0b: // Tab vertically (VT) - if (numVertTabs == 0) // All tabs cancelled => Act like CR - curX = leftMargin; - else if (numVertTabs == 255) // No tabs set since reset => Act like LF - { - curX = leftMargin; - curY += lineSpacing; - if (curY > bottomMargin) - newPage(true,false); - } - else - { - // Find tab below current pos - Real64 moveTo = -1; - for (Bit8u i=0; i curY) - moveTo = verttabs[i]; - - // Nothing found => Act like FF - if (moveTo > bottomMargin || moveTo < 0) - newPage(true,false); - else - curY = moveTo; - } - return true; - case 0x0c: // Form feed (FF) - newPage(true,true); - return true; - case 0x0d: // Carriage Return (CR) - curX = leftMargin; - if ((switcha&=128)) curY += lineSpacing; // If switch A-8 is set, send a LF after CR - if (!autoFeed) - return true; - case 0x0a: // Line feed - //curX = leftMargin; - curY += lineSpacing; - if (curY > bottomMargin) - newPage(true,false); - return true; - case 0x0e: //Select double width printing (SO) IW - style |= STYLE_DOUBLEWIDTH; - updateFont(); - return true; - case 0x0f: // Dis-select double width printing (SI) IW - style &= ~STYLE_DOUBLEWIDTH; - updateFont(); - return true; - case 0x11: // Select printer (DC1) - // Ignore - return true; - case 0x12: // Cancel condensed printing (DC2) - hmi = -1; - style &= ~STYLE_CONDENSED; - updateFont(); - return true; - case 0x13: // Deselect printer (DC3) - // Ignore - return true; - case 0x14: // Cancel double-width printing (one line) (DC4) - return true; - case 0x18: // Cancel line (CAN) - return true; - case 0x1b: // ESC - ESCSeen = true; - return true; - case 0x1f: // unit seperator (US) Feed 1 to 15 line commands - FSSeen = true; - return true; - default: - return false; - } - - return false; -} -#endif // HAVE_SDL - -//static void PRINTER_EventHandler(Bitu param); - -void Imagewriter::newPage(bool save, bool resetx) -{ - //PIC_RemoveEvents(PRINTER_EventHandler); - if(printer_timout) timeout_dirty=false; - -#ifdef HAVE_SDL - if (save) - outputPage(); - - if(resetx) curX=leftMargin; - curY = topMargin; - - SDL_Rect rect; - rect.x = 0; - rect.y = 0; - rect.w = page->w; - rect.h = page->h; - SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255)); - - /*for(int i = 0; i < 256; i++) - { - *((Bit8u*)page->pixels+i)=i; - }*/ -#endif // HAVE_SDL - if (strcasecmp(output, "text") == 0) { /* Text file */ - if (textPrinterFile) { - fclose(textPrinterFile); - textPrinterFile = NULL; - } - } -} - -void Imagewriter::printChar(Bit8u ch) -{ -#ifdef HAVE_SDL - - charRead = true; - if (page == NULL) return; -// Apply MSB if desired, but only if we aren't printing graphics! - if (msb != 255) { - if (!bitGraph.remBytes) ch &= 0x7F; - } -#endif // HAVE_SDL - if (strcasecmp(output, "text") == 0) { - if (!textPrinterFile) { - textPrinterFile = fopen(textPrinterFileName,"ab"); - } - fprintf(textPrinterFile,"%c",ch); - fflush(textPrinterFile); - return; - } -#ifdef HAVE_SDL - - // Are we currently printing a bit graphic? - if (bitGraph.remBytes > 0) { - printBitGraph(ch); - return; - } - // Print everything? - if (numPrintAsChar > 0) numPrintAsChar--; - else if (processCommandChar(ch)) return; - - // Do not print if no font is available - if (!curFont) return; - if(ch==0x1) ch=0x20; - - // Find the glyph for the char to render - FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]); - - // Load the glyph - FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT); - - - // Render a high-quality bitmap - FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL); - - Bit16u penX = PIXX + curFont->glyph->bitmap_left; - Bit16u penY = PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender/64; - - //if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2; - //if (style & STYLE_HALFHEIGHT) penY += curFont->glyph->bitmap.rows / 4; - if (style & STYLE_SUBSCRIPT) penY += 20; - if (style & STYLE_SUPERSCRIPT) penY -= 10; - if (style & STYLE_HALFHEIGHT) penY += 15; - - // Copy bitmap into page - SDL_LockSurface(page); - - blitGlyph(curFont->glyph->bitmap, penX, penY, false); - blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); - - // Bold => Print the glyph a second time one pixel to the right - // or be a bit more bold... - if (style & STYLE_BOLD) { - blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); - blitGlyph(curFont->glyph->bitmap, penX+2, penY, true); - blitGlyph(curFont->glyph->bitmap, penX+3, penY, true); - } - SDL_UnlockSurface(page); - - // For line printing - Bit16u lineStart = PIXX; - // Print a slashed zero if the softswitch B-1 is set - if(switchb&1 && ch=='0') slashzero(penX,penY); - // advance the cursor to the right - Real64 x_advance; - if (style & STYLE_PROP) - x_advance = (Real64)((Real64)(curFont->glyph->advance.x)/(Real64)(dpi*64)); - else { - x_advance = 1/(Real64)actcpi; - } - x_advance += extraIntraSpace; - curX += x_advance; - - // Draw lines if desired - if ((score != SCORE_NONE) && (style & - (STYLE_UNDERLINE))) - { - // Find out where to put the line - Bit16u lineY = PIXY; - double height = (curFont->size->metrics.height>>6); // TODO height is fixed point madness... - - if (style & STYLE_UNDERLINE) lineY = PIXY + (Bit16u)(height*0.9); - - drawLine(lineStart, PIXX, lineY, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); - - // draw second line if needed - if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN)) - drawLine(lineStart, PIXX, lineY + 5, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); - } - // If the next character would go beyond the right margin, line-wrap. - if((curX + x_advance) > rightMargin) { - curX = leftMargin; - curY += lineSpacing; - if (curY > bottomMargin) newPage(true,false); - } -#endif // HAVE_SDL -} - -#ifdef HAVE_SDL -void Imagewriter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) { - for (Bitu y=0; y 0 && (destx+x < page->w) && (desty+y < page->h) ) { - Bit8u* target = (Bit8u*)page->pixels + (x+destx) + (y+desty)*page->pitch; - source>>=3; - - if (add) { - if (((*target)&0x1f )+ source > 31) *target |= (color|0x1f); - else { - *target += source; - *target |= color; - } - } - else *target = source|color; - } - } - } -} - -void Imagewriter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken) -{ - SDL_LockSurface(page); - - Bitu breakmod = dpi / 15; - Bitu gapstart = (breakmod * 4)/5; - - // Draw anti-aliased line - for (Bitu x=fromx; x<=tox; x++) - { - // Skip parts if broken line or going over the border - if ((!broken || (x%breakmod <= gapstart)) && (x < page->w)) - { - if (y > 0 && (y-1) < page->h) - *((Bit8u*)page->pixels + x + (y-1)*page->pitch) = 240; - if (y < page->h) - *((Bit8u*)page->pixels + x + y*page->pitch) = !broken?255:240; - if (y+1 < page->h) - *((Bit8u*)page->pixels + x + (y+1)*page->pitch) = 240; - } - } - SDL_UnlockSurface(page); -} - -void Imagewriter::setAutofeed(bool feed) { - autoFeed = feed; -} - -bool Imagewriter::getAutofeed() { - return autoFeed; -} - -bool Imagewriter::isBusy() { - // We're never busy - return false; -} - -bool Imagewriter::ack() { - // Acknowledge last char read - if(charRead) { - charRead=false; - return true; - } - return false; -} - -void Imagewriter::setupBitImage(Bit8u dens, Bit16u numCols) { - switch (dens) - { - case 0: - bitGraph.horizDens = 72; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 1: - bitGraph.horizDens = 80; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 2: - bitGraph.horizDens = 96; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 3: - bitGraph.horizDens = 107; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 4: - bitGraph.horizDens = 120; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 5: - bitGraph.horizDens = 136; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 6: - bitGraph.horizDens = 144; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 7: - bitGraph.horizDens = 160; - bitGraph.vertDens = 72; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - //Imagewriter LQ resolutions - case 8: - bitGraph.horizDens = 144; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 9: - bitGraph.horizDens = 160; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 10: - bitGraph.horizDens = 192; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 11: - bitGraph.horizDens = 216; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 12: - bitGraph.horizDens = 240; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 13: - bitGraph.horizDens = 272; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 14: - bitGraph.horizDens = 288; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 15: - bitGraph.horizDens = 320; - bitGraph.vertDens = 216; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - default: - //break; - printf("PRINTER: Unsupported bit image density"); - } - - bitGraph.remBytes = numCols * bitGraph.bytesColumn; - bitGraph.readBytesColumn = 0; -} - -void Imagewriter::printBitGraph(Bit8u ch) -{ - bitGraph.column[bitGraph.readBytesColumn++] = ch; - bitGraph.remBytes--; - - // Only print after reading a full column - if (bitGraph.readBytesColumn < bitGraph.bytesColumn) - return; - - Real64 oldY = curY; - SDL_LockSurface(page); - - // When page dpi is greater than graphics dpi, the drawn pixels get "bigger" - Bitu pixsizeX=1; - Bitu pixsizeY=1; - if(bitGraph.adjacent) { - pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; - if(dpi%bitGraph.horizDens && bitGraph.horizDens < dpi) - { - if(PIXX%(bitGraph.horizDens*8) || (PIXX == 0)) //Primative scaling function - { - pixsizeX++; - } - } - pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; - if(bitGraph.vertDens == 216) - { - if(PIXY%(bitGraph.vertDens*8) || (PIXY == 0)) //Primative scaling function - { - pixsizeY++; - } - } - } - if ((printRes > 7) && (verticalDot != 0)) //for ESC t - { - curY += (Real64)verticalDot/(Real64)bitGraph.vertDens; - } - // TODO figure this out for 360dpi mode in windows - -// Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; -// Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; - - for (Bitu i=0; iw) && ((PIXY + yy) < page->h)) - *((Bit8u*)page->pixels + (PIXX+xx) + (PIXY+yy)*page->pitch) |= (color|0x1F); - } - } // else white pixel - curY += (Real64)1/(Real64)bitGraph.vertDens; // TODO line wrap? - } - } - SDL_UnlockSurface(page); - - curY = oldY; - bitGraph.readBytesColumn = 0; - - // Advance to the left - curX += (Real64)1/(Real64)bitGraph.horizDens; -} -#endif // HAVE_SDL - -void Imagewriter::formFeed() -{ -#ifdef HAVE_SDL - // Don't output blank pages - newPage(!isBlank(),true); - finishMultipage(); -#endif // HAVE_SDL -} - -#ifdef HAVE_SDL -static void findNextName(char* front, char* ext, char* fname) -{ - document_path = ""; - Bitu i = 1; - Bitu slen = strlen(document_path); - if(slen>(200-15)) { - fname[0]=0; - return; - } - FILE *test = NULL; - do - { - strcpy(fname, document_path); - printf(fname); -#ifdef WIN32 - const char* const pathstring = ".\\%s%d%s"; -#else - const char* const pathstring = "./%s%d%s"; -#endif - sprintf(fname+strlen(fname), pathstring, front,i++,ext); - test = fopen(fname, "rb"); - if (test != NULL) - fclose(test); - } - while (test != NULL ); -} - -void Imagewriter::outputPage() -{/* - SDL_Surface *screen; - screen = SDL_SetVideoMode(1024, 768, 16, SDL_DOUBLEBUF | SDL_RESIZABLE); -if (screen == NULL) { - printf("Unable to set video mode: %s\n", SDL_GetError()); -} -SDL_Surface *image; -SDL_LockSurface(page); -image = SDL_DisplayFormat(page); -SDL_UnlockSurface(page); -SDL_Rect src, dest; - -src.x = 0; -src.y = 0; -src.w = image->w; -src.h = image->h; - -dest.x = 100; -dest.y = 100; -dest.w = image->w; -dest.h = image->h; - -SDL_BlitSurface(image, &src, screen, &dest); -SDL_Flip(screen); - -SDL_Delay(2000); -SDL_FreeSurface(image);*/ - char fname[200]; - if (strcasecmp(output, "printer") == 0) - { -#if defined (WIN32) - if (multipageOutput && outputHandle == NULL) - { - ShowCursor(1); - PRINTDLG pd; - pd.lStructSize = sizeof(PRINTDLG); - pd.hDevMode = (HANDLE) NULL; - pd.hDevNames = (HANDLE) NULL; - pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; - pd.hwndOwner = NULL; - pd.hDC = (HDC) NULL; - pd.nFromPage = 0xFFFF; - pd.nToPage = 0xFFFF; - pd.nMinPage = 1; - pd.nMaxPage = 0xFFFF; - pd.nCopies = 1; - pd.hInstance = NULL; - pd.lCustData = 0L; - pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; - pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; - pd.lpPrintTemplateName = (LPCSTR) NULL; - pd.lpSetupTemplateName = (LPCSTR) NULL; - pd.hPrintTemplate = (HANDLE) NULL; - pd.hSetupTemplate = (HANDLE) NULL; - if(!PrintDlg(&pd)) - { - //If user clicks cancel, show warning dialog and force all output to bitmaps as failsafe. - MessageBox(NULL,"You did not select a printer.\nAll output from this print job will be saved as bitmap files.",NULL,MB_ICONEXCLAMATION); - findNextName("page", ".bmp", &fname[0]); - SDL_SaveBMP(page, fname); //Save first page as bitmap. - outputHandle = printerDC; - printerDC = NULL; - ShowCursor(0); - return; - } - else - { - //Create device context. - printerDC = pd.hDC; - ShowCursor(0); - } - } - if (!printerDC) //Fall thru for subsequent pages if printer dialog was cancelled. - { - findNextName("page", ".bmp", &fname[0]); - SDL_SaveBMP(page, fname); //Save remaining pages. - return; - } - Bit32u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH); - Bit32u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT); - Bit16u printeroffsetW = GetDeviceCaps(printerDC, PHYSICALOFFSETX); //printer x offset in actual pixels - Bit16u printeroffsetH = GetDeviceCaps(printerDC, PHYSICALOFFSETY); //printer y offset in actual pixels - Bit16u deviceDPIW = GetDeviceCaps(printerDC, LOGPIXELSX); - Bit16u deviceDPIH = GetDeviceCaps(printerDC, LOGPIXELSY); - Real64 physoffsetW = (Real64)printeroffsetW/deviceDPIW; //printer x offset in inches - Real64 physoffsetH = (Real64)printeroffsetH/deviceDPIH; //printer y offset in inches - Bit16u dpiW = page->w/defaultPageWidth; //Get currently set DPI of the emulated printer in an indirect way - Bit16u dpiH = page->h/defaultPageHeight; - Real64 soffsetW = physoffsetW*dpiW; //virtual page x offset in actual pixels - Real64 soffsetH = physoffsetH*dpiH; //virtual page y offset in actual pixels - HDC memHDC = CreateCompatibleDC(printerDC); - BITMAPINFO *BitmapInfo; - HBITMAP bitmap; - - // Start new printer job? - if (outputHandle == NULL) - { - DOCINFO docinfo; - docinfo.cbSize = sizeof(docinfo); - docinfo.lpszDocName = "GSport Virtual ImageWriter"; - docinfo.lpszOutput = NULL; - docinfo.lpszDatatype = NULL; - docinfo.fwType = 0; - - StartDoc(printerDC, &docinfo); - multiPageCounter = 1; - } - SDL_LockSurface(page); - StartPage(printerDC); - DWORD TotalSize; - HGDIOBJ Prev; - void* Pixels; - BitmapInfo = (BITMAPINFO*) - malloc (sizeof (BITMAPINFO)+255*sizeof (RGBQUAD)); - memset (BitmapInfo,0,sizeof (bitmap)); - BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - BitmapInfo->bmiHeader.biWidth = page->w; - BitmapInfo->bmiHeader.biHeight = -page->h; - BitmapInfo->bmiHeader.biPlanes = 1; - BitmapInfo->bmiHeader.biBitCount = page->format->BitsPerPixel; - BitmapInfo->bmiHeader.biCompression = BI_RGB; - BitmapInfo->bmiHeader.biSizeImage = page->h * page->pitch; - BitmapInfo->bmiHeader.biXPelsPerMeter = 0; - BitmapInfo->bmiHeader.biYPelsPerMeter = 0; - BitmapInfo->bmiHeader.biClrUsed = page->format->palette->ncolors; - BitmapInfo->bmiHeader.biClrImportant = 0; - if (page->format->palette) { - for (int I=0; Iformat->palette->ncolors; I++) { - BitmapInfo->bmiColors[I].rgbRed = - (page->format->palette->colors+I)->r; - BitmapInfo->bmiColors[I].rgbGreen = - (page->format->palette->colors+I)->g; - BitmapInfo->bmiColors[I].rgbBlue = - (page->format->palette->colors+I)->b; - } - } - memHDC = CreateCompatibleDC(printerDC); - if (memHDC) { - bitmap = CreateDIBSection(memHDC, BitmapInfo, DIB_RGB_COLORS, - (&Pixels), NULL, 0); - if (bitmap) { - memcpy (Pixels, page->pixels, - BitmapInfo->bmiHeader.biSizeImage); - Prev = SelectObject (memHDC, bitmap); - StretchBlt(printerDC, 0, 0, physW, physH, memHDC, soffsetW, soffsetH, page->w, page->h, SRCCOPY); - SelectObject (memHDC,Prev); - DeleteObject (bitmap); - } - } - free (BitmapInfo); - SDL_UnlockSurface(page); - EndPage(printerDC); - - if (multipageOutput) - { - multiPageCounter++; - outputHandle = printerDC; - } - else - { - EndDoc(printerDC); - outputHandle = NULL; - } - DeleteObject(bitmap); - DeleteDC(memHDC); -#else - //LOG_MSG("PRINTER: Direct printing not supported under this OS"); -#endif - } -#ifdef C_LIBPNG - else if (strcasecmp(output, "png") == 0) - { - // Find a page that does not exists - findNextName("page", ".png", &fname[0]); - - png_structp png_ptr; - png_infop info_ptr; - png_bytep * row_pointers; - png_color palette[256]; - Bitu i; - - /* Open the actual file */ - FILE * fp=fopen(fname,"wb"); - if (!fp) - { - //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); - return; - } - - /* First try to alloacte the png structures */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); - if (!png_ptr) return; - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr,(png_infopp)NULL); - return; - } - - /* Finalize the initing of png library */ - png_init_io(png_ptr, fp); - png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192); - - - png_set_IHDR(png_ptr, info_ptr, page->w, page->h, - 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - for (i=0;i<256;i++) - { - palette[i].red = page->format->palette->colors[i].r; - palette[i].green = page->format->palette->colors[i].g; - palette[i].blue = page->format->palette->colors[i].b; - } - png_set_PLTE(png_ptr, info_ptr, palette,256); - png_set_packing(png_ptr); - SDL_LockSurface(page); - - // Allocate an array of scanline pointers - row_pointers = (png_bytep*)malloc(page->h*sizeof(png_bytep)); - for (i=0; ih; i++) - row_pointers[i] = ((Bit8u*)page->pixels+(i*page->pitch)); - - // tell the png library what to encode. - png_set_rows(png_ptr, info_ptr, row_pointers); - - // Write image to file - png_write_png(png_ptr, info_ptr, 0, NULL); - - - - - SDL_UnlockSurface(page); - - /*close file*/ - fclose(fp); - - /*Destroy PNG structs*/ - png_destroy_write_struct(&png_ptr, &info_ptr); - - /*clean up dynamically allocated RAM.*/ - free(row_pointers); - } -#endif - else if (strcasecmp(output, "colorps") == 0) - { - FILE* psfile = NULL; - - // Continue postscript file? - if (outputHandle != NULL) - psfile = (FILE*)outputHandle; - - // Create new file? - if (psfile == NULL) - { - if (!multipageOutput) - findNextName("page", ".ps", &fname[0]); - else - findNextName("doc", ".ps", &fname[0]); - - psfile = fopen(fname, "wb"); - if (!psfile) - { - //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); - return; - } - - // Print header - fprintf(psfile, "%%!PS-Adobe-3.0\n"); - fprintf(psfile, "%%%%Pages: (atend)\n"); - fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); - fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n"); - fprintf(psfile, "%%%%DocumentData: Clean7Bit\n"); - fprintf(psfile, "%%%%LanguageLevel: 2\n"); - fprintf(psfile, "%%%%EndComments\n"); - multiPageCounter = 1; - } - - fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); - fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); - fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); - fprintf(psfile, "currentfile\n"); - fprintf(psfile, "/ASCII85Decode filter\n"); - fprintf(psfile, "/RunLengthDecode filter\n"); - fprintf(psfile, "false 3\n"); - fprintf(psfile, "colorimage\n"); - - SDL_LockSurface(page); - Bit8u * templine; - templine = (Bit8u*) malloc(page->w*3); - Bit32u x = 0; - Bit32u numy = page->h; - Bit32u numx = page->w; - Bit32u numpix = page->w*3; - Bit32u pix = 0; - Bit32u currDot = 0; - Bit32u y = 0; - Bit32u plane = 0; - Bit8u r, g, b; - ASCII85BufferPos = ASCII85CurCol = 0; - for (y=0; y < numy;y++) - { - currDot = 0; - for (x = 0; x < numx; x++) - { - SDL_GetRGB(getxyPixel(x,y), page->format, &r, &g, &b); - templine[currDot] = ~r; currDot++; - templine[currDot] = ~g; currDot++; - templine[currDot] = ~b; currDot++; - } - // Compress data using RLE - pix = 0; - while (pix < numpix) - { - if ((pix < numpix-2) && (templine[pix] == templine[pix+1]) && (templine[pix] == templine[pix+2])) - { - // Found three or more pixels with the same color - Bit8u sameCount = 3; - Bit8u col = templine[pix]; - while (sameCount < 128 && sameCount+pix < numpix && col == templine[pix+sameCount]) - sameCount++; - - fprintASCII85(psfile, 257-sameCount); - fprintASCII85(psfile, 255-col); - - // Skip ahead - pix += sameCount; - } - else - { - // Find end of heterogenous area - Bit8u diffCount = 1; - while (diffCount < 128 && diffCount+pix < numpix && - ( - (diffCount+pix < numpix-2) - || (templine[pix+diffCount] != templine[pix+diffCount+1]) - || (templine[pix+diffCount] != templine[pix+diffCount+2]) - )) - diffCount++; - - fprintASCII85(psfile, diffCount-1); - for (Bit8u i=0; iw, page->h, page->w, page->h, page->h); - fprintf(psfile, "currentfile\n"); - fprintf(psfile, "/ASCII85Decode filter\n"); - fprintf(psfile, "/RunLengthDecode filter\n"); - fprintf(psfile, "image\n"); - - SDL_LockSurface(page); - - Bit32u pix = 0; - Bit32u numpix = page->h*page->w; - ASCII85BufferPos = ASCII85CurCol = 0; - - while (pix < numpix) - { - // Compress data using RLE - - if ((pix < numpix-2) && (getPixel(pix) == getPixel(pix+1)) && (getPixel(pix) == getPixel(pix+2))) - { - // Found three or more pixels with the same color - Bit8u sameCount = 3; - Bit8u col = getPixel(pix); - while (sameCount < 128 && sameCount+pix < numpix && col == getPixel(pix+sameCount)) - sameCount++; - - fprintASCII85(psfile, 257-sameCount); - fprintASCII85(psfile, 255-col); - - // Skip ahead - pix += sameCount; - } - else - { - // Find end of heterogenous area - Bit8u diffCount = 1; - while (diffCount < 128 && diffCount+pix < numpix && - ( - (diffCount+pix < numpix-2) - || (getPixel(pix+diffCount) != getPixel(pix+diffCount+1)) - || (getPixel(pix+diffCount) != getPixel(pix+diffCount+2)) - )) - diffCount++; - - fprintASCII85(psfile, diffCount-1); - for (Bit8u i=0; i= 79) - { - ASCII85CurCol = 0; - fprintf(f, "\n"); - } - } - else - { - char buffer[5]; - for (Bit8s i=4; i>=0; i--) - { - buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85); - buffer[i] += 33; - num /= (Bit32u)85; - } - - // Make sure a line never starts with a % (which may be mistaken as start of a comment) - if (ASCII85CurCol == 0 && buffer[0] == '%') - fprintf(f, " "); - - for (int i=0; i<((b != 257)?5:ASCII85BufferPos+1); i++) - { - fprintf(f, "%c", buffer[i]); - if (++ASCII85CurCol >= 79) - { - ASCII85CurCol = 0; - fprintf(f, "\n"); - } - } - } - - ASCII85BufferPos = 0; - } - - } - else // Close string - { - // Partial tupel if there are still bytes in the buffer - if (ASCII85BufferPos > 0) - { - for (Bit8u i = ASCII85BufferPos; i < 4; i++) - ASCII85Buffer[i] = 0; - - fprintASCII85(f, 257); - } - - fprintf(f, "~"); - fprintf(f, ">\n"); - } -} - -void Imagewriter::finishMultipage() -{ - if (outputHandle != NULL) - { - if (strcasecmp(output, "ps") == 0) - { - FILE* psfile = (FILE*)outputHandle; - fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); - fprintf(psfile, "%%%%EOF\n"); - fclose(psfile); - } - if (strcasecmp(output, "colorps") == 0) - { - FILE* psfile = (FILE*)outputHandle; - fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); - fprintf(psfile, "%%%%EOF\n"); - fclose(psfile); - } - else if (strcasecmp(output, "printer") == 0) - { -#if defined (WIN32) - EndDoc(printerDC); -#endif - } - outputHandle = NULL; - } -} - -bool Imagewriter::isBlank() { - bool blank = true; - SDL_LockSurface(page); - - for (Bit16u y=0; yh; y++) - for (Bit16u x=0; xw; x++) - if (*((Bit8u*)page->pixels + x + (y*page->pitch)) != 0) - blank = false; - - SDL_UnlockSurface(page); - return blank; -} - -Bit8u Imagewriter::getxyPixel(Bit32u x,Bit32u y) { - Bit8u *p; - - /* get the X/Y values within the bounds of this surface */ - if ((unsigned) x > (unsigned) page->w - 1u) - x = (x < 0) ? 0 : page->w - 1; - if ((unsigned) y > (unsigned) page->h - 1u) - y = (y < 0) ? 0 : page->h - 1; - - /* Set a pointer to the exact location in memory of the pixel - in question: */ - - p = (Bit8u *) (((Bit8u *) page->pixels) + /* Start at top of RAM */ - (y * page->pitch) + /* Go down Y lines */ - x); /* Go in X pixels */ - - - /* Return the correctly-sized piece of data containing the - * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit - * RGB value) */ - - return (*p); -} -Bit8u Imagewriter::getPixel(Bit32u num) { - Bit32u pixel = *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); - return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); -} -#endif // HAVE_SDL - -//Interfaces to C code - - -extern "C" void imagewriter_init(int pdpi, int ppaper, int banner, char* poutput, bool mpage) -{ - if (defaultImagewriter != NULL) return; //if Imagewriter on this port is initialized, reuse it - defaultImagewriter = new Imagewriter(pdpi, ppaper, banner, poutput, mpage); -} -extern "C" void imagewriter_loop(Bit8u pchar) -{ - if (defaultImagewriter == NULL) return; - defaultImagewriter->printChar(pchar); -} - -extern "C" void imagewriter_close() -{ - delete defaultImagewriter; - defaultImagewriter = NULL; -} -extern "C" void imagewriter_feed() -{ - if(defaultImagewriter == NULL) return; - defaultImagewriter->formFeed(); -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2010 - 2011 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Copyright (C) 2002-2004 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Modified for the GSport emulator by Christopher G. Mason 03/2014 + Extensively rewritten to provide full emulation of the Apple ImageWriter II + and LQ printers. + + Information used to write this emulator was provided by + Apple's "ImageWriter II Technical Reference Manual" + ISBN# 0-201-17766-8 + and + Apple's "ImageWriter LQ Reference Manual" + ISBN# 0-201-17751-X + */ + +#include "imagewriter.h" +#include +#include "support.h" + +//#include "png.h" +//#pragma comment( lib, "libpng.lib" ) +//#pragma comment (lib, "zdll.lib" ) + +static Imagewriter* defaultImagewriter = NULL; + +static FILE *textPrinterFile = NULL; +#ifdef WIN32 +const char* const textPrinterFileName = ".\\printer.txt"; +#else +const char* const textPrinterFileName = "./printer.txt"; +#endif + +#define PARAM16(I) (params[I+1]*256+params[I]) +#define PIXX ((Bitu)floor(curX*dpi+0.5)) +#define PIXY ((Bitu)floor(curY*dpi+0.5)) +//These ugly defines are so we can convert multibyte parameters from strings into some nice ints. +#define paramc(I) (params[I]-'0') +#define PARAM2(I) (paramc(I)*10+paramc(I+1)) +#define PARAM3(I) (paramc(I)*100+paramc(I+1)*10+paramc(I+2)) +#define PARAM4(I) (paramc(I)*1000+paramc(I+1)*100+paramc(I+2)*10+paramc(I+3)) + +static Bitu printer_timout; +static bool timeout_dirty; +static const char* document_path; +extern "C" char* g_imagewriter_fixed_font; +extern "C" char* g_imagewriter_prop_font; +extern "C" int iw_scc_write; +#include "iw_charmaps.h" + +#ifdef HAVE_SDL +void Imagewriter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal) +{ + float red=redmax/30.9; + float green=greenmax/30.9; + float blue=bluemax/30.9; + + Bit8u colormask=colorID<<=5; + + for(int i = 0; i < 32;i++) { + pal->colors[i+colormask].r=255-(red*(float)i); + pal->colors[i+colormask].g=255-(green*(float)i); + pal->colors[i+colormask].b=255-(blue*(float)i); + } +} +#endif // HAVE_SDL + +Imagewriter::Imagewriter(Bit16u dpi, Bit16u paperSize, Bit16u bannerSize, char* output, bool multipageOutput) +{ +#ifdef HAVE_SDL + if (FT_Init_FreeType(&FTlib)) + { + page = NULL; + } + else + { + SDL_Init(SDL_INIT_EVERYTHING); + this->output = output; + this->multipageOutput = multipageOutput; + this->port = port; + + if (bannerSize) + { + defaultPageWidth = ((Real64)paperSizes[0][0]/(Real64)72); + defaultPageHeight = (((Real64)paperSizes[0][1]*bannerSize)/(Real64)72); + dpi = 144; + } + else + { + defaultPageWidth = ((Real64)paperSizes[paperSize][0]/(Real64)72); + defaultPageHeight = ((Real64)paperSizes[paperSize][1]/(Real64)72); + } + this->dpi = dpi; + // Create page + page = SDL_CreateRGBSurface( + SDL_SWSURFACE, + (Bitu)(defaultPageWidth*dpi), + (Bitu)(defaultPageHeight*dpi), + 8, + 0, + 0, + 0, + 0); + + // Set a grey palette + SDL_Palette* palette = page->format->palette; + + for (Bitu i=0; i<32; i++) + { + palette->colors[i].r =255; + palette->colors[i].g =255; + palette->colors[i].b =255; + } + + // 0 = all white needed for logic 000 + FillPalette( 0, 0, 0, 1, palette); + // 1 = magenta* 001 + FillPalette( 0, 255, 0, 1, palette); + // 2 = cyan* 010 + FillPalette(255, 0, 0, 2, palette); + // 3 = "violet" 011 + FillPalette(255, 255, 0, 3, palette); + // 4 = yellow* 100 + FillPalette( 0, 0, 255, 4, palette); + // 5 = red 101 + FillPalette( 0, 255, 255, 5, palette); + // 6 = green 110 + FillPalette(255, 0, 255, 6, palette); + // 7 = black 111 + FillPalette(255, 255, 255, 7, palette); + + // 0 = all white needed for logic 000 + /*FillPalette( 0, 0, 0, 1, palette); + // 1 = yellow* 100 IW + FillPalette( 0, 0, 255, 1, palette); + // 2 = magenta* 001 IW + FillPalette( 0, 255, 0, 2, palette); + // 3 = cyan* 010 IW + FillPalette(255, 0, 0, 3, palette); + // 4 = red 101 IW + FillPalette( 0, 255, 255, 4, palette); + // 5 = green 110 IW + FillPalette(255, 0, 255, 5, palette); + // 6 = "violet" 011 IW + FillPalette(255, 255, 0, 6, palette); + // 7 = black 111 + FillPalette(255, 255, 255, 7, palette);*/ + + // yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max + // Printing colors on top of each other ORs them and gets the + // correct resulting color. + // i.e. magenta on blank page yyy=001 + // then yellow on magenta 001 | 100 = 101 = red + + color=COLOR_BLACK; + + curFont = NULL; + charRead = false; + autoFeed = false; + outputHandle = NULL; + + resetPrinter(); + //Only initialize native printer here if multipage output is off. That way the user doesn't get prompted every page. + if (strcasecmp(output, "printer") == 0 && !multipageOutput) + { +#if defined (WIN32) + // Show Print dialog to obtain a printer device context + + ShowCursor(1); + PRINTDLG pd; + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = (HANDLE) NULL; + pd.hDevNames = (HANDLE) NULL; + pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; + pd.hwndOwner = NULL; + pd.hDC = (HDC) NULL; + pd.nFromPage = 0xFFFF; + pd.nToPage = 0xFFFF; + pd.nMinPage = 1; + pd.nMaxPage = 0xFFFF; + pd.nCopies = 1; + pd.hInstance = NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPCSTR) NULL; + pd.lpSetupTemplateName = (LPCSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + if(!PrintDlg(&pd)) + { + //If user presses cancel, warn them with a dialog and switch output to bitmap files + this->output = "bmp"; + MessageBox(NULL,"You did not select a printer.\nAll printer output will be saved as bitmap files.\nTo select a printer, press F4 and select 'Reset Virtual ImageWriter'",NULL,MB_ICONEXCLAMATION); + } + printerDC = pd.hDC; + ShowCursor(0); +#endif // WIN32 + } + } +#endif // HAVE_SDL +#ifndef HAVE_SDL + this->output = output; + this->multipageOutput = multipageOutput; +#endif // !HAVE_SDL +}; + +void Imagewriter::resetPrinterHard() +{ +#ifdef HAVE_SDL + charRead = false; + resetPrinter(); +#endif // HAVE_SDL +} + +void Imagewriter::resetPrinter() +{ +#ifdef HAVE_SDL + printRes = 0; + color=COLOR_BLACK; + curX = curY = 0.0; + ESCSeen = false; + FSSeen = false; + ESCCmd = 0; + numParam = neededParam = 0; + topMargin = 0.0; + leftMargin = 0.25; //Most all Apple II software including GS/OS assume a 1/4 inch margin on an Imagewriter + rightMargin = pageWidth = defaultPageWidth; + bottomMargin = pageHeight = defaultPageHeight; + lineSpacing = (Real64)1/6; + cpi = 12.0; + printRes = 2; + style &= (0xffff - STYLE_PROP); + definedUnit = 96; + curCharTable = 1; + style = 0; + extraIntraSpace = 0.0; + printUpperContr = true; + bitGraph.remBytes = 0; + densk = 0; + densl = 1; + densy = 2; + densz = 3; + charTables[0] = 0; // Italics + charTables[1] = charTables[2] = charTables[3] = 437; + multipoint = false; + multiPointSize = 0.0; + multicpi = 0.0; + hmi = -1.0; + switcha = 0; + switchb = ' '; + numPrintAsChar = 0; + LQtypeFace = fixed; + verticalDot = 0; + selectCodepage(charTables[curCharTable]); + + updateFont(); + updateSwitch(); + +#endif // HAVE_SDL + newPage(false,true); +#ifdef HAVE_SDL + + // Default tabs => Each eight characters + /*for (Bitu i=0;i<32;i++) + horiztabs[i] = i*8*(1/(Real64)cpi);*/ + numHorizTabs = 0; + + numVertTabs = 0; +#endif // HAVE_SDL +} + + +Imagewriter::~Imagewriter(void) +{ +#ifdef HAVE_SDL + finishMultipage(); + if (page != NULL) + { + SDL_FreeSurface(page); + page = NULL; + FT_Done_FreeType(FTlib); + } +#if defined (WIN32) + DeleteDC(printerDC); +#endif +#endif // HAVE_SDL +}; + +#ifdef HAVE_SDL +void Imagewriter::selectCodepage(Bit16u cp) +{ + Bit16u *mapToUse = NULL; + + switch(cp) + { + case 0: // Italics, use cp437 + case 437: + mapToUse = (Bit16u*)&cp437Map; + break; + default: + //LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp); + mapToUse = (Bit16u*)&cp437Map; + } + + for (int i=0; i<256; i++) + curMap[i] = mapToUse[i]; +} +#endif // HAVE_SDL + +#ifdef HAVE_SDL +void Imagewriter::updateFont() +{ + // char buffer[1000]; + if (curFont != NULL) + FT_Done_Face(curFont); + + char* fontName; + + switch (LQtypeFace) + { + case fixed: + fontName = g_imagewriter_fixed_font; + break; + case prop: + fontName = g_imagewriter_prop_font; + break; + default: + fontName = g_imagewriter_fixed_font; + } + + if (FT_New_Face(FTlib, fontName, 0, &curFont)) + { + + printf("Unable to load font %s\n"); + //LOG_MSG("Unable to load font %s", fontName); + curFont = NULL; + } + + Real64 horizPoints = 10; + Real64 vertPoints = 10; + if (!multipoint) + { + actcpi = cpi; + + if (!(style & STYLE_CONDENSED)) { + horizPoints *= 10.0/cpi; + //vertPoints *= 10.0/cpi; + } + + if (!(style & STYLE_PROP)) { + if ((cpi == 10.0) && (style & STYLE_CONDENSED)) { + actcpi = 17.14; + horizPoints *= 10.0/17.14; + } + if ((cpi == 12.0) && (style & STYLE_CONDENSED)) { + actcpi = 20.0; + horizPoints *= 10.0/20.0; + vertPoints *= 10.0/12.0; + } + } else if (style & STYLE_CONDENSED) horizPoints /= 2.0; + + + if ((style & STYLE_DOUBLEWIDTH)) { + actcpi /= 2.0; + horizPoints *= 2.0; + } + } else { // multipoint true + actcpi = multicpi; + horizPoints = vertPoints = multiPointSize; + } + + if (style & STYLE_SUPERSCRIPT || style & STYLE_SUBSCRIPT || style & STYLE_HALFHEIGHT) { + //horizPoints *= 2.0/3.0; + vertPoints *= 2.0/3.0; + //actcpi /= 2.0/3.0; + } + + FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi); + + if (style & STYLE_ITALICS || charTables[curCharTable] == 0) + { + FT_Matrix matrix; + matrix.xx = 0x10000L; + matrix.xy = (FT_Fixed)(0.20 * 0x10000L); + matrix.yx = 0; + matrix.yy = 0x10000L; + FT_Set_Transform(curFont, &matrix, 0); + } +} + + +void Imagewriter::updateSwitch() +{ + //Set international character mappping (Switches A-1 to A3) + int charmap = switcha &= 7; + curMap[0x23] = intCharSets[charmap][0]; + curMap[0x40] = intCharSets[charmap][1]; + curMap[0x5b] = intCharSets[charmap][2]; + curMap[0x5c] = intCharSets[charmap][3]; + curMap[0x5d] = intCharSets[charmap][4]; + curMap[0x60] = intCharSets[charmap][5]; + curMap[0x7b] = intCharSets[charmap][6]; + curMap[0x7c] = intCharSets[charmap][7]; + curMap[0x7d] = intCharSets[charmap][8]; + curMap[0x7e] = intCharSets[charmap][9]; + //MSB control (Switch B-6) + if (!(switchb&32)) + { + msb = 255; + } + else msb = 0; +} +void Imagewriter::slashzero(Bit16u penX, Bit16u penY) +{ + FT_Face slashFont = curFont; + FT_UInt slashindex = FT_Get_Char_Index(slashFont, curMap[0x2f]); + FT_Load_Glyph(slashFont, slashindex, FT_LOAD_DEFAULT); + FT_Render_Glyph(slashFont->glyph, FT_RENDER_MODE_NORMAL); + blitGlyph(slashFont->glyph->bitmap, penX, penY, false); + blitGlyph(slashFont->glyph->bitmap, penX+1, penY, true); + if (style & STYLE_BOLD) { + blitGlyph(slashFont->glyph->bitmap, penX+1, penY, true); + blitGlyph(slashFont->glyph->bitmap, penX+2, penY, true); + blitGlyph(slashFont->glyph->bitmap, penX+3, penY, true); + } +} +#endif // HAVE_SDL + +#ifdef HAVE_SDL +bool Imagewriter::processCommandChar(Bit8u ch) +{ + if (ESCSeen || FSSeen) + { + ESCCmd = ch; + if(FSSeen) ESCCmd |= 0x800; + ESCSeen = FSSeen = false; + numParam = 0; + + switch (ESCCmd) { + case 0x21: // Select bold font (ESC !) IW + case 0x22: // Cancel bold font (ESC ") IW + case 0x24: // Cancel MSB control and Mousetext (ESC $) IW + case 0x2b: // custom char width is 8 dots (ESC -) IW + case 0x2e: // custom char width is 8 dots (ESC +) IW + case 0x30: // Clear all tabs (ESC 0) IW + case 0x31: // Insert 1 intercharacter spaces (ESC 1) IW + case 0x32: // Insert 2 intercharacter spaces (ESC 2) IW + case 0x33: // Insert 3 intercharacter spaces (ESC 3) IW + case 0x34: // Insert 4 intercharacter spaces (ESC 4) IW + case 0x35: // Insert 5 intercharacter spaces (ESC 5) IW + case 0x36: // Insert 6 intercharacter spaces (ESC 6) IW + case 0x3c: // bidirectional mode (one line) (ESC <) IW + case 0x3e: // Unidirectional mode (one line) (ESC >) IW + case 0x3f: // Send ID string (ESC ?) IW + case 0x41: // Select 1/6-inch line spacing (ESC A) IW + case 0x42: // Select 1/8-inch line spacing (ESC B) IW + case 0x45: // 12 cpi, 96 dpi graphics (ESC E) IW + case 0x4d: // Same as ESC a2 (ESC M) IW + case 0x4e: // 10 cpi, 80 dpi graphics (ESC N) IW + case 0x4f: // Disable paper-out detector (ESC O) IW + case 0x50: // Proportional, 160 dpi graphics (ESC P) IW + case 0x51: // 17 cpi, 136 dpi graphics (ESC Q) IW + case 0x57: // Cancel halfheight printing (ESC W) IW + case 0x58: // Turn underline on (ESC X) IW + case 0x59: // Turn underline off (ESC Y) IW + case 0x63: // Initialize printer (ESC c) IW + case 0x65: // 13.4 cpi, 107 dpi graphics (ESC e) IW + case 0x66: // Select forward feed mode (ESC f) IW + case 0x6b: // Select optional font (ESC k) IW LQ + case 0x6d: // Same as ESC a0 (ESC m) IW + case 0x6e: // 9 cpi, 72 dpi graphics (ESC n) IW + case 0x6f: // Enable paper-out detector (ESC o) IW + case 0x70: // Proportional, 144 dpi graphics (ESC p) IW + case 0x72: // Select reverse feed mode (ESC r) IW + case 0x71: // 15 cpi, 120 dpi graphics (ESC q) IW + case 0x77: // Select halfheight printing (ESC w) IW + case 0x78: // Select superscript printing (ESC x) IW + case 0x79: // Select subscript printing (ESC y) IW + case 0x7a: // Cancel superscript/subscript printing (ESC z) IW + neededParam = 0; + break; + case 0x3d: // Internal font ID (ESC = n) IW LQ + case 0x40: // Select output bin (ESC @ n) IW LQ + case 0x4b: // Select printing color (ESC K n) IW + case 0x61: // Select font (ESC a n) IW + case 0x6c: // Insert CR before LF and FF (ESC l n) IW + case 0x73: // Set intercharacter space (ESC s n) IW + case 0x74: // Shift printing downward n/216 inch (ESC t n) IW LQ + case 0x833: // Feed n lines of blank space (US n) IW + neededParam = 1; + break; + case 0x44: // Set soft switches to closed (on)= 1 (ESC D nn) IW + case 0x54: // Distance between lines to be nn/144 inch (ESC T nn) IW + case 0x5a: // Set soft switches to open (off) = 0 (ESC Z nn) IW + neededParam = 2; + break; + case 0x4c: // Set left margin at column nnn (ESC L nnn) IW + case 0x67: // Print graphics for next nnn * 8 databytes (ESC g nnn) IW + case 0x75: // Add one tab stop at nnn (ESC u nnn) IW + neededParam = 3; + break; + case 0x28: // Set horizontal tabs (ESC ( nnn,) IW + numHorizTabs = 0; + case 0x29: // Delete horizontal tabs (ESC ) nnn,) IW + case 0x43: // Print hi-res graphics for next nnnn*3 databytes (ESC C nnnn) IW LQ + case 0x47: // Print graphics for next nnnn databytes (ESC G nnnn) IW + case 0x46: // Place printhead nnnn dots from left margin (ESC F nnnn) IW + case 0x48: // Set pagelength to nnnn/144 (ESC H nnnn) IW + case 0x53: // Print graphics for next nnnn databytes (ESC S nnnn) IW + case 0x52: // Repeat character c nnn times (ESC R nnn c) IW + case 0x68: // Place printhead nnnn hi-res dots from left margin (ESC h nnnn) IW LQ + neededParam = 4; + break; + case 0x56: //Repeat Print nnnn repetitions of dot column c (ESC V nnnn c) IW + neededParam = 5; + msb = 255; + break; + case 0x55: //Repeat Print nnnn repetitions of hi-res dot column abc (ESC U nnnn abc) IW LQ + neededParam = 7; + msb = 255; + break; + case 0x27: // Select user-defined set (ESC ') + case 0x49: // Define user-defined characters (ESC I) + //LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!"); + return true; + default: + /*LOG_MSG("PRINTER: Unknown command %c (%02Xh) %c , unable to skip parameters.", + (ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd);*/ + + neededParam = 0; + ESCCmd = 0; + return true; + } + + if (neededParam > 0) + return true; + } + + if (numParam < neededParam) + { + params[numParam++] = ch; + + if (numParam < neededParam) + return true; + } + if (ESCCmd != 0) + { + switch (ESCCmd) + { + case 0x19: // Control paper loading/ejecting (ESC EM) + // We are not really loading paper, so most commands can be ignored + if (params[0] == 'R') + newPage(true,false); // TODO resetx? + break; + case 0x73: // Set intercharacter space (ESC s) IW + if (style & STYLE_PROP) + { + extraIntraSpace = (Real64)paramc(0); + updateFont(); + } + break; + case 0x46: // Set absolute horizontal print position (ESC F nnnn) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)72.0; + + Real64 newX = leftMargin + ((Real64)PARAM4(0)/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + case 0x68: // Set absolute horizontal hi-res print position (ESC h nnnn) IW LQ + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + Real64 unitSize = definedUnit*2; + if (unitSize < 0) + unitSize = (Real64)72.0; + + Real64 newX = leftMargin + ((Real64)PARAM4(0)/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36:// Insert 1-6 intercharacter spaces (ESC 1 to 6) IW + { + if (style & STYLE_PROP) //This function only works in proportional mode + { + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)72.0; + + Real64 newX = ((Real64)(ESCCmd-'0')/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + } + case 0x47: case 0x53: // Print graphics (ESC G nnnn) IW + { + int x = 0; + printRes &= ~8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + setupBitImage(printRes, PARAM4(0)); + break; + } + case 0x43: // Print hi-res graphics (ESC G nnnn) IW LQ + { + int x = 0; + printRes |= 8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + setupBitImage(printRes, PARAM4(0)); + break; + } + case 0x67: // Print graphics (ESC g nnn) IW + { + int x = 0; + printRes &= ~8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + setupBitImage(printRes, (PARAM3(0)*8)); + break; + } + case 0x56: //Repeat Print nnnn repetitions of dot column byte c (ESC V nnnn c)IW + { + int x = 0; + printRes &= ~8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + while ( x < PARAM4(0)) + { + setupBitImage(printRes, 1); + printBitGraph(params[4]); + x++; + } + msb = 0; + break; + } + case 0x55: //Repeat Print nnnn repetitions of hi-res dot column byte abc (ESC U nnnn abc) IW LQ + { + int x = 0; + printRes |= 8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + while ( x < PARAM4(0)) + { + setupBitImage(printRes, 1); + printBitGraph(params[4]); + printBitGraph(params[5]); + printBitGraph(params[6]); + x++; + } + msb = 0; + break; + } + case 0x74: // Shift printing downward n/216 inch (ESC t n) IW LQ + { + verticalDot = paramc(0); + break; + } + case 0x6e: // 9 cpi, 72/144 dpi graphics (ESC n) IW + cpi = 9.0; + style &= (0xffff - STYLE_PROP); + printRes = 0; + definedUnit = 72; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x4e: // 10 cpi, 80/160 dpi graphics (ESC N) IW + cpi = 10.0; + printRes = 1; + style &= (0xffff - STYLE_PROP); + definedUnit = 80; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x45: // 12 cpi, 96/192 dpi graphics (ESC E) IW + cpi = 12.0; + printRes = 2; + style &= (0xffff - STYLE_PROP); + definedUnit = 96; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x65: // 13.4 cpi, 107/216 dpi graphics (ESC e) IW + cpi = 13.4; + printRes = 3; + style &= (0xffff - STYLE_PROP); + definedUnit = 107; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x71: // 15 cpi, 120/240 dpi graphics (ESC q) IW + cpi = 15; + printRes = 4; + style &= (0xffff - STYLE_PROP); + definedUnit = 120; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x51: // 17 cpi, 136/272 dpi graphics (ESC Q) IW + cpi = 17; + printRes = 5; + style &= (0xffff - STYLE_PROP); + definedUnit = 136; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x70: // Proportional, 144/288 dpi graphics (ESC p) IW + style |= STYLE_PROP; + cpi = 10; + //printQuality = QUALITY_LQ; + printRes = 6; + definedUnit = 144; + LQtypeFace = prop; + updateFont(); + break; + case 0x50: // Proportional, 160/320 dpi graphics (ESC P) IW + style |= STYLE_PROP; + cpi = 12; + //printQuality = QUALITY_LQ; + printRes = 7; + definedUnit = 160; + LQtypeFace = prop; + updateFont(); + break; + case 0x54: // Set n/144-inch line spacing (ESC T nn) IW + lineSpacing = (Real64)PARAM2(0)/144; + break; + case 0x59: // Turn underline off (ESC Y) IW + style &= ~STYLE_UNDERLINE; + updateFont(); + break; + case 0x58: // Turn underline on (ESC X) IW + style |= STYLE_UNDERLINE; + score = SCORE_SINGLE; + updateFont(); + break; + case 0x42: // Select 1/8-inch line spacing (ESC B) IW + lineSpacing = (Real64)1/8; + break; + case 0x41: // Select 1/6-inch line spacing (ESC A) IW + lineSpacing = (Real64)1/6; + break; + case 0x3c: case 0x3e: // Unidirectional mode (one line) (ESC <) + // We don't have a print head, so just ignore this + break; + case 0x63: // Initialize printer (ESC c) IW + resetPrinter(); + break; + case 0x48: // Set page length in lines (ESC H nnnn) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + pageHeight = (Real64)PARAM4(0)/144; + bottomMargin = pageHeight; + topMargin = 0.0; + break; + } + case 0x21: // Select bold font (ESC !) IW + style |= STYLE_BOLD; + updateFont(); + break; + case 0x22: // Cancel bold font (ESC ") IW + style &= ~STYLE_BOLD; + updateFont(); + break; + case 0x78: // Select superscript printing (ESC x) IW + style |= STYLE_SUPERSCRIPT; + updateFont(); + break; + case 0x79: // Select subscript printing (ESC y) IW + style |= STYLE_SUBSCRIPT; + updateFont(); + break; + case 0x7a: // Cancel superscript/subscript printing (ESC z) IW + style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + updateFont(); + break; + case 0x77: // Select halfheight printing (ESC w) IW + style |= STYLE_HALFHEIGHT; + updateFont(); + break; + case 0x57: // Cancel halfheight printing (ESC W) IW + style &= ~STYLE_HALFHEIGHT; + updateFont(); + break; + case 0x72: // Reverse paper feed (ESC r) IW + { + printf("Reverse Feed\n"); + if(lineSpacing > 0) lineSpacing *= -1; + break; + } + case 0x66: // Forward paper feed (ESC f) IW + { + if(lineSpacing < 0) lineSpacing *= -1; + break; + } + case 0x61: // Select typeface (ESC a n) IW worry about this later + break; + case 0x6d: case 0x4d: //Same as ESC a n commands + break; + case 0x4c: // Set left margin (ESC L nnn) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + leftMargin = (Real64)(PARAM3(0)-1.0) / (Real64)cpi; + if (curX < leftMargin) + curX = leftMargin; + break; + } + case 0x4b: // Select printing color (ESC K) IW + + switch (paramc(0)) + { + case 0: break; + case 1: params[0] = 4; break; + case 2: params[0] = 1; break; + case 3: params[0] = 2; break; + case 4: params[0] = 5; break; + case 5: params[0] = 6; break; + case 6: params[0] = 3; break; + } + if(paramc(0)==0) color = COLOR_BLACK; + else color = params[0]<<5; + break; + case 0x3d: // Internal font ID (ESC = n) IW LQ + //Ignore for now + break; + case 0x3f: //Send ID string to computer (ESC ?) IW + //insert SCC send code here + printf("Sending ID String\n"); + iw_scc_write = true; + break; + case 0x52: // Repeat character c for nnn times (ESC R nnn c) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + ESCCmd = 0; + while (x < PARAM3(0)) + { + printChar(params[3]); + x++; + } + break; + } + case 0x30: //Clear all tabs + numHorizTabs = 0; + break; + case 0x28: // Set horizontal tabs (ESC ( nnn,) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + if (params[3] == '.' || (numHorizTabs>0 && horiztabs[numHorizTabs-1] > (Real64)PARAM3(0)*(1/(Real64)cpi))) + { + horiztabs[numHorizTabs++] = (Real64)PARAM3(0)*(1/(Real64)cpi); + //printf("Adding tab %d, and end\n",PARAM3(0)); + //printf("Number of Tabs:%d\n",numHorizTabs); + } + else if (params[3] == ',' && numHorizTabs < 32) + { + horiztabs[numHorizTabs++] = (Real64)PARAM3(0)*(1/(Real64)cpi); + numParam = 0; + neededParam = 4; + //printf("Adding tab %d, plus more\n", PARAM3(0)); + //printf("Number of Tabs:%d\n",numHorizTabs); + return true; + } + x = 0; + break; + } + case 0x29: // Delete horizontal tabs (ESC ) nnn,) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + while (x < numHorizTabs) + { + if (horiztabs[x] == (Real64)PARAM3(0)*(1/(Real64)cpi)) + { printf("Tab Found %d\n",PARAM3(0)); + horiztabs[x] = 0; + } + x++; + } + + if (params[3] == '.') + { + printf("Deleting tab %d, and end\n",PARAM3(0)); + } + else if (params[3] == ',') + { + numParam = 0; + neededParam = 4; + //printf("Deleting tab %d, plus more\n", PARAM3(0)); + return true; + } + x = 0; + break; + } + case 0x5a: // Set switches to open (off) (ESC Z nn) IW + //printf ("switcha is: %x switchb is: %x\n",switcha,switchb); + //printf ("(Setting to 0) param 0 is: %x param 1 is: %x\n",params[0],params[1]); + switcha &= ~params[0]; + switchb &= ~params[1]; + //printf ("switcha is now: %x switchb is now: %x\n",switcha,switchb); + updateSwitch(); + break; + case 0x44: // Set switches to closed (on) (ESC D nn) IW + //printf ("switcha is: %x switchb is: %x\n",switcha,switchb); + //printf ("(Setting to 1) param 0 is: %x param 1 is: %x\n",params[0],params[1]); + switcha |= params[0]; + switchb |= params[1]; + //printf ("switcha is now: %x switchb is now: %x\n",switcha,switchb); + updateSwitch(); + break; + case 0x75: // Add one tab stop at nnn (ESC u nnn) IW + { + bool haveStop = false; + int lastEmpty; + //If the list is full, we assume there are no empty spaces to fill until the list is scanned + if (numHorizTabs == 32) lastEmpty = 33; + else lastEmpty = numHorizTabs; + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + //see if we have the tab stop already on the list and check for any deleted entries to reuse + while (x < numHorizTabs) + { + if (horiztabs[x] == (Real64)PARAM3(0)*(1/(Real64)cpi)) + { + //printf("We have this tab already! at list entry: %d\n", x); + haveStop = true; + } + if (horiztabs[x] == 0) lastEmpty = x; + //printf("at list entry: %d\n", x); + x++; + } + if (!haveStop && lastEmpty < 33) + { + //printf("Adding tab %d\n", PARAM3(0)); + horiztabs[lastEmpty] = (Real64)PARAM3(0)*(1/(Real64)cpi); + if (lastEmpty == numHorizTabs) numHorizTabs++; //only increase if we don't reuse an empty tab entry + //printf("Number of Tabs:%d\n",numHorizTabs); + } + } + break; + case 0x833: // Feed n lines of blank space (US n) IW + { + int x = 0; + while (x < paramc(0)) + { + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + x++; + } + } + break; + default: + if (ESCCmd < 0x100); + //LOG(LOG_MISC,LOG_WARN) + //LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd); + else; + //LOG(LOG_MISC,LOG_WARN) + //LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200); + } + + ESCCmd = 0; + return true; + } + + switch (ch) + { + case 0x00: // NUL is ignored by the printer + return true; + case 0x07: // Beeper (BEL) + // BEEEP! + return true; + case 0x08: // Backspace (BS) + { + Real64 newX = curX - (1/(Real64)actcpi); + if (hmi > 0) + newX = curX - hmi; + if (newX >= leftMargin) + curX = newX; + } + return true; + case 0x09: // Tab horizontally (HT) + { + // Find tab right to current pos + Real64 moveTo = -1; + for (Bit8u i=0; i curX) + moveTo = horiztabs[i]; + // Nothing found => Ignore + if (moveTo > 0 && moveTo < rightMargin) + curX = moveTo; + } + return true; + case 0x0b: // Tab vertically (VT) + if (numVertTabs == 0) // All tabs cancelled => Act like CR + curX = leftMargin; + else if (numVertTabs == 255) // No tabs set since reset => Act like LF + { + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + } + else + { + // Find tab below current pos + Real64 moveTo = -1; + for (Bit8u i=0; i curY) + moveTo = verttabs[i]; + + // Nothing found => Act like FF + if (moveTo > bottomMargin || moveTo < 0) + newPage(true,false); + else + curY = moveTo; + } + return true; + case 0x0c: // Form feed (FF) + newPage(true,true); + return true; + case 0x0d: // Carriage Return (CR) + curX = leftMargin; + if ((switcha&=128)) curY += lineSpacing; // If switch A-8 is set, send a LF after CR + if (!autoFeed) + return true; + case 0x0a: // Line feed + //curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + return true; + case 0x0e: //Select double width printing (SO) IW + style |= STYLE_DOUBLEWIDTH; + updateFont(); + return true; + case 0x0f: // Dis-select double width printing (SI) IW + style &= ~STYLE_DOUBLEWIDTH; + updateFont(); + return true; + case 0x11: // Select printer (DC1) + // Ignore + return true; + case 0x12: // Cancel condensed printing (DC2) + hmi = -1; + style &= ~STYLE_CONDENSED; + updateFont(); + return true; + case 0x13: // Deselect printer (DC3) + // Ignore + return true; + case 0x14: // Cancel double-width printing (one line) (DC4) + return true; + case 0x18: // Cancel line (CAN) + return true; + case 0x1b: // ESC + ESCSeen = true; + return true; + case 0x1f: // unit seperator (US) Feed 1 to 15 line commands + FSSeen = true; + return true; + default: + return false; + } + + return false; +} +#endif // HAVE_SDL + +//static void PRINTER_EventHandler(Bitu param); + +void Imagewriter::newPage(bool save, bool resetx) +{ + //PIC_RemoveEvents(PRINTER_EventHandler); + if(printer_timout) timeout_dirty=false; + +#ifdef HAVE_SDL + if (save) + outputPage(); + + if(resetx) curX=leftMargin; + curY = topMargin; + + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = page->w; + rect.h = page->h; + SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255)); + + /*for(int i = 0; i < 256; i++) + { + *((Bit8u*)page->pixels+i)=i; + }*/ +#endif // HAVE_SDL + if (strcasecmp(output, "text") == 0) { /* Text file */ + if (textPrinterFile) { + fclose(textPrinterFile); + textPrinterFile = NULL; + } + } +} + +void Imagewriter::printChar(Bit8u ch) +{ +#ifdef HAVE_SDL + + charRead = true; + if (page == NULL) return; +// Apply MSB if desired, but only if we aren't printing graphics! + if (msb != 255) { + if (!bitGraph.remBytes) ch &= 0x7F; + } +#endif // HAVE_SDL + if (strcasecmp(output, "text") == 0) { + if (!textPrinterFile) { + textPrinterFile = fopen(textPrinterFileName,"ab"); + } + fprintf(textPrinterFile,"%c",ch); + fflush(textPrinterFile); + return; + } +#ifdef HAVE_SDL + + // Are we currently printing a bit graphic? + if (bitGraph.remBytes > 0) { + printBitGraph(ch); + return; + } + // Print everything? + if (numPrintAsChar > 0) numPrintAsChar--; + else if (processCommandChar(ch)) return; + + // Do not print if no font is available + if (!curFont) return; + if(ch==0x1) ch=0x20; + + // Find the glyph for the char to render + FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]); + + // Load the glyph + FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT); + + + // Render a high-quality bitmap + FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL); + + Bit16u penX = PIXX + curFont->glyph->bitmap_left; + Bit16u penY = PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender/64; + + //if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2; + //if (style & STYLE_HALFHEIGHT) penY += curFont->glyph->bitmap.rows / 4; + if (style & STYLE_SUBSCRIPT) penY += 20; + if (style & STYLE_SUPERSCRIPT) penY -= 10; + if (style & STYLE_HALFHEIGHT) penY += 15; + + // Copy bitmap into page + SDL_LockSurface(page); + + blitGlyph(curFont->glyph->bitmap, penX, penY, false); + blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); + + // Bold => Print the glyph a second time one pixel to the right + // or be a bit more bold... + if (style & STYLE_BOLD) { + blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); + blitGlyph(curFont->glyph->bitmap, penX+2, penY, true); + blitGlyph(curFont->glyph->bitmap, penX+3, penY, true); + } + SDL_UnlockSurface(page); + + // For line printing + Bit16u lineStart = PIXX; + // Print a slashed zero if the softswitch B-1 is set + if(switchb&1 && ch=='0') slashzero(penX,penY); + // advance the cursor to the right + Real64 x_advance; + if (style & STYLE_PROP) + x_advance = (Real64)((Real64)(curFont->glyph->advance.x)/(Real64)(dpi*64)); + else { + x_advance = 1/(Real64)actcpi; + } + x_advance += extraIntraSpace; + curX += x_advance; + + // Draw lines if desired + if ((score != SCORE_NONE) && (style & + (STYLE_UNDERLINE))) + { + // Find out where to put the line + Bit16u lineY = PIXY; + double height = (curFont->size->metrics.height>>6); // TODO height is fixed point madness... + + if (style & STYLE_UNDERLINE) lineY = PIXY + (Bit16u)(height*0.9); + + drawLine(lineStart, PIXX, lineY, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); + + // draw second line if needed + if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN)) + drawLine(lineStart, PIXX, lineY + 5, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); + } + // If the next character would go beyond the right margin, line-wrap. + if((curX + x_advance) > rightMargin) { + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) newPage(true,false); + } +#endif // HAVE_SDL +} + +#ifdef HAVE_SDL +void Imagewriter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) { + for (Bitu y=0; y 0 && (destx+x < page->w) && (desty+y < page->h) ) { + Bit8u* target = (Bit8u*)page->pixels + (x+destx) + (y+desty)*page->pitch; + source>>=3; + + if (add) { + if (((*target)&0x1f )+ source > 31) *target |= (color|0x1f); + else { + *target += source; + *target |= color; + } + } + else *target = source|color; + } + } + } +} + +void Imagewriter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken) +{ + SDL_LockSurface(page); + + Bitu breakmod = dpi / 15; + Bitu gapstart = (breakmod * 4)/5; + + // Draw anti-aliased line + for (Bitu x=fromx; x<=tox; x++) + { + // Skip parts if broken line or going over the border + if ((!broken || (x%breakmod <= gapstart)) && (x < page->w)) + { + if (y > 0 && (y-1) < page->h) + *((Bit8u*)page->pixels + x + (y-1)*page->pitch) = 240; + if (y < page->h) + *((Bit8u*)page->pixels + x + y*page->pitch) = !broken?255:240; + if (y+1 < page->h) + *((Bit8u*)page->pixels + x + (y+1)*page->pitch) = 240; + } + } + SDL_UnlockSurface(page); +} + +void Imagewriter::setAutofeed(bool feed) { + autoFeed = feed; +} + +bool Imagewriter::getAutofeed() { + return autoFeed; +} + +bool Imagewriter::isBusy() { + // We're never busy + return false; +} + +bool Imagewriter::ack() { + // Acknowledge last char read + if(charRead) { + charRead=false; + return true; + } + return false; +} + +void Imagewriter::setupBitImage(Bit8u dens, Bit16u numCols) { + switch (dens) + { + case 0: + bitGraph.horizDens = 72; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 1: + bitGraph.horizDens = 80; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 2: + bitGraph.horizDens = 96; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 3: + bitGraph.horizDens = 107; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 4: + bitGraph.horizDens = 120; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 5: + bitGraph.horizDens = 136; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 6: + bitGraph.horizDens = 144; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 7: + bitGraph.horizDens = 160; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + //Imagewriter LQ resolutions + case 8: + bitGraph.horizDens = 144; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 9: + bitGraph.horizDens = 160; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 10: + bitGraph.horizDens = 192; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 11: + bitGraph.horizDens = 216; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 12: + bitGraph.horizDens = 240; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 13: + bitGraph.horizDens = 272; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 14: + bitGraph.horizDens = 288; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 15: + bitGraph.horizDens = 320; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + default: + //break; + printf("PRINTER: Unsupported bit image density"); + } + + bitGraph.remBytes = numCols * bitGraph.bytesColumn; + bitGraph.readBytesColumn = 0; +} + +void Imagewriter::printBitGraph(Bit8u ch) +{ + bitGraph.column[bitGraph.readBytesColumn++] = ch; + bitGraph.remBytes--; + + // Only print after reading a full column + if (bitGraph.readBytesColumn < bitGraph.bytesColumn) + return; + + Real64 oldY = curY; + SDL_LockSurface(page); + + // When page dpi is greater than graphics dpi, the drawn pixels get "bigger" + Bitu pixsizeX=1; + Bitu pixsizeY=1; + if(bitGraph.adjacent) { + pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; + if(dpi%bitGraph.horizDens && bitGraph.horizDens < dpi) + { + if(PIXX%(bitGraph.horizDens*8) || (PIXX == 0)) //Primative scaling function + { + pixsizeX++; + } + } + pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; + if(bitGraph.vertDens == 216) + { + if(PIXY%(bitGraph.vertDens*8) || (PIXY == 0)) //Primative scaling function + { + pixsizeY++; + } + } + } + if ((printRes > 7) && (verticalDot != 0)) //for ESC t + { + curY += (Real64)verticalDot/(Real64)bitGraph.vertDens; + } + // TODO figure this out for 360dpi mode in windows + +// Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; +// Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; + + for (Bitu i=0; iw) && ((PIXY + yy) < page->h)) + *((Bit8u*)page->pixels + (PIXX+xx) + (PIXY+yy)*page->pitch) |= (color|0x1F); + } + } // else white pixel + curY += (Real64)1/(Real64)bitGraph.vertDens; // TODO line wrap? + } + } + SDL_UnlockSurface(page); + + curY = oldY; + bitGraph.readBytesColumn = 0; + + // Advance to the left + curX += (Real64)1/(Real64)bitGraph.horizDens; +} +#endif // HAVE_SDL + +void Imagewriter::formFeed() +{ +#ifdef HAVE_SDL + // Don't output blank pages + newPage(!isBlank(),true); + finishMultipage(); +#endif // HAVE_SDL +} + +#ifdef HAVE_SDL +static void findNextName(char* front, char* ext, char* fname) +{ + document_path = ""; + Bitu i = 1; + Bitu slen = strlen(document_path); + if(slen>(200-15)) { + fname[0]=0; + return; + } + FILE *test = NULL; + do + { + strcpy(fname, document_path); + printf(fname); +#ifdef WIN32 + const char* const pathstring = ".\\%s%d%s"; +#else + const char* const pathstring = "./%s%d%s"; +#endif + sprintf(fname+strlen(fname), pathstring, front,i++,ext); + test = fopen(fname, "rb"); + if (test != NULL) + fclose(test); + } + while (test != NULL ); +} + +void Imagewriter::outputPage() +{/* + SDL_Surface *screen; + screen = SDL_SetVideoMode(1024, 768, 16, SDL_DOUBLEBUF | SDL_RESIZABLE); +if (screen == NULL) { + printf("Unable to set video mode: %s\n", SDL_GetError()); +} +SDL_Surface *image; +SDL_LockSurface(page); +image = SDL_DisplayFormat(page); +SDL_UnlockSurface(page); +SDL_Rect src, dest; + +src.x = 0; +src.y = 0; +src.w = image->w; +src.h = image->h; + +dest.x = 100; +dest.y = 100; +dest.w = image->w; +dest.h = image->h; + +SDL_BlitSurface(image, &src, screen, &dest); +SDL_Flip(screen); + +SDL_Delay(2000); +SDL_FreeSurface(image);*/ + char fname[200]; + if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + if (multipageOutput && outputHandle == NULL) + { + ShowCursor(1); + PRINTDLG pd; + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = (HANDLE) NULL; + pd.hDevNames = (HANDLE) NULL; + pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; + pd.hwndOwner = NULL; + pd.hDC = (HDC) NULL; + pd.nFromPage = 0xFFFF; + pd.nToPage = 0xFFFF; + pd.nMinPage = 1; + pd.nMaxPage = 0xFFFF; + pd.nCopies = 1; + pd.hInstance = NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPCSTR) NULL; + pd.lpSetupTemplateName = (LPCSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + if(!PrintDlg(&pd)) + { + //If user clicks cancel, show warning dialog and force all output to bitmaps as failsafe. + MessageBox(NULL,"You did not select a printer.\nAll output from this print job will be saved as bitmap files.",NULL,MB_ICONEXCLAMATION); + findNextName("page", ".bmp", &fname[0]); + SDL_SaveBMP(page, fname); //Save first page as bitmap. + outputHandle = printerDC; + printerDC = NULL; + ShowCursor(0); + return; + } + else + { + //Create device context. + printerDC = pd.hDC; + ShowCursor(0); + } + } + if (!printerDC) //Fall thru for subsequent pages if printer dialog was cancelled. + { + findNextName("page", ".bmp", &fname[0]); + SDL_SaveBMP(page, fname); //Save remaining pages. + return; + } + Bit32u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH); + Bit32u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT); + Bit16u printeroffsetW = GetDeviceCaps(printerDC, PHYSICALOFFSETX); //printer x offset in actual pixels + Bit16u printeroffsetH = GetDeviceCaps(printerDC, PHYSICALOFFSETY); //printer y offset in actual pixels + Bit16u deviceDPIW = GetDeviceCaps(printerDC, LOGPIXELSX); + Bit16u deviceDPIH = GetDeviceCaps(printerDC, LOGPIXELSY); + Real64 physoffsetW = (Real64)printeroffsetW/deviceDPIW; //printer x offset in inches + Real64 physoffsetH = (Real64)printeroffsetH/deviceDPIH; //printer y offset in inches + Bit16u dpiW = page->w/defaultPageWidth; //Get currently set DPI of the emulated printer in an indirect way + Bit16u dpiH = page->h/defaultPageHeight; + Real64 soffsetW = physoffsetW*dpiW; //virtual page x offset in actual pixels + Real64 soffsetH = physoffsetH*dpiH; //virtual page y offset in actual pixels + HDC memHDC = CreateCompatibleDC(printerDC); + BITMAPINFO *BitmapInfo; + HBITMAP bitmap; + + // Start new printer job? + if (outputHandle == NULL) + { + DOCINFO docinfo; + docinfo.cbSize = sizeof(docinfo); + docinfo.lpszDocName = "GSport Virtual ImageWriter"; + docinfo.lpszOutput = NULL; + docinfo.lpszDatatype = NULL; + docinfo.fwType = 0; + + StartDoc(printerDC, &docinfo); + multiPageCounter = 1; + } + SDL_LockSurface(page); + StartPage(printerDC); + DWORD TotalSize; + HGDIOBJ Prev; + void* Pixels; + BitmapInfo = (BITMAPINFO*) + malloc (sizeof (BITMAPINFO)+255*sizeof (RGBQUAD)); + memset (BitmapInfo,0,sizeof (bitmap)); + BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + BitmapInfo->bmiHeader.biWidth = page->w; + BitmapInfo->bmiHeader.biHeight = -page->h; + BitmapInfo->bmiHeader.biPlanes = 1; + BitmapInfo->bmiHeader.biBitCount = page->format->BitsPerPixel; + BitmapInfo->bmiHeader.biCompression = BI_RGB; + BitmapInfo->bmiHeader.biSizeImage = page->h * page->pitch; + BitmapInfo->bmiHeader.biXPelsPerMeter = 0; + BitmapInfo->bmiHeader.biYPelsPerMeter = 0; + BitmapInfo->bmiHeader.biClrUsed = page->format->palette->ncolors; + BitmapInfo->bmiHeader.biClrImportant = 0; + if (page->format->palette) { + for (int I=0; Iformat->palette->ncolors; I++) { + BitmapInfo->bmiColors[I].rgbRed = + (page->format->palette->colors+I)->r; + BitmapInfo->bmiColors[I].rgbGreen = + (page->format->palette->colors+I)->g; + BitmapInfo->bmiColors[I].rgbBlue = + (page->format->palette->colors+I)->b; + } + } + memHDC = CreateCompatibleDC(printerDC); + if (memHDC) { + bitmap = CreateDIBSection(memHDC, BitmapInfo, DIB_RGB_COLORS, + (&Pixels), NULL, 0); + if (bitmap) { + memcpy (Pixels, page->pixels, + BitmapInfo->bmiHeader.biSizeImage); + Prev = SelectObject (memHDC, bitmap); + StretchBlt(printerDC, 0, 0, physW, physH, memHDC, soffsetW, soffsetH, page->w, page->h, SRCCOPY); + SelectObject (memHDC,Prev); + DeleteObject (bitmap); + } + } + free (BitmapInfo); + SDL_UnlockSurface(page); + EndPage(printerDC); + + if (multipageOutput) + { + multiPageCounter++; + outputHandle = printerDC; + } + else + { + EndDoc(printerDC); + outputHandle = NULL; + } + DeleteObject(bitmap); + DeleteDC(memHDC); +#else + //LOG_MSG("PRINTER: Direct printing not supported under this OS"); +#endif + } +#ifdef C_LIBPNG + else if (strcasecmp(output, "png") == 0) + { + // Find a page that does not exists + findNextName("page", ".png", &fname[0]); + + png_structp png_ptr; + png_infop info_ptr; + png_bytep * row_pointers; + png_color palette[256]; + Bitu i; + + /* Open the actual file */ + FILE * fp=fopen(fname,"wb"); + if (!fp) + { + //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); + return; + } + + /* First try to alloacte the png structures */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); + if (!png_ptr) return; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + return; + } + + /* Finalize the initing of png library */ + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192); + + + png_set_IHDR(png_ptr, info_ptr, page->w, page->h, + 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + for (i=0;i<256;i++) + { + palette[i].red = page->format->palette->colors[i].r; + palette[i].green = page->format->palette->colors[i].g; + palette[i].blue = page->format->palette->colors[i].b; + } + png_set_PLTE(png_ptr, info_ptr, palette,256); + png_set_packing(png_ptr); + SDL_LockSurface(page); + + // Allocate an array of scanline pointers + row_pointers = (png_bytep*)malloc(page->h*sizeof(png_bytep)); + for (i=0; ih; i++) + row_pointers[i] = ((Bit8u*)page->pixels+(i*page->pitch)); + + // tell the png library what to encode. + png_set_rows(png_ptr, info_ptr, row_pointers); + + // Write image to file + png_write_png(png_ptr, info_ptr, 0, NULL); + + + + + SDL_UnlockSurface(page); + + /*close file*/ + fclose(fp); + + /*Destroy PNG structs*/ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /*clean up dynamically allocated RAM.*/ + free(row_pointers); + } +#endif + else if (strcasecmp(output, "colorps") == 0) + { + FILE* psfile = NULL; + + // Continue postscript file? + if (outputHandle != NULL) + psfile = (FILE*)outputHandle; + + // Create new file? + if (psfile == NULL) + { + if (!multipageOutput) + findNextName("page", ".ps", &fname[0]); + else + findNextName("doc", ".ps", &fname[0]); + + psfile = fopen(fname, "wb"); + if (!psfile) + { + //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); + return; + } + + // Print header + fprintf(psfile, "%%!PS-Adobe-3.0\n"); + fprintf(psfile, "%%%%Pages: (atend)\n"); + fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); + fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n"); + fprintf(psfile, "%%%%DocumentData: Clean7Bit\n"); + fprintf(psfile, "%%%%LanguageLevel: 2\n"); + fprintf(psfile, "%%%%EndComments\n"); + multiPageCounter = 1; + } + + fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); + fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); + fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); + fprintf(psfile, "currentfile\n"); + fprintf(psfile, "/ASCII85Decode filter\n"); + fprintf(psfile, "/RunLengthDecode filter\n"); + fprintf(psfile, "false 3\n"); + fprintf(psfile, "colorimage\n"); + + SDL_LockSurface(page); + Bit8u * templine; + templine = (Bit8u*) malloc(page->w*3); + Bit32u x = 0; + Bit32u numy = page->h; + Bit32u numx = page->w; + Bit32u numpix = page->w*3; + Bit32u pix = 0; + Bit32u currDot = 0; + Bit32u y = 0; + Bit32u plane = 0; + Bit8u r, g, b; + ASCII85BufferPos = ASCII85CurCol = 0; + for (y=0; y < numy;y++) + { + currDot = 0; + for (x = 0; x < numx; x++) + { + SDL_GetRGB(getxyPixel(x,y), page->format, &r, &g, &b); + templine[currDot] = ~r; currDot++; + templine[currDot] = ~g; currDot++; + templine[currDot] = ~b; currDot++; + } + // Compress data using RLE + pix = 0; + while (pix < numpix) + { + if ((pix < numpix-2) && (templine[pix] == templine[pix+1]) && (templine[pix] == templine[pix+2])) + { + // Found three or more pixels with the same color + Bit8u sameCount = 3; + Bit8u col = templine[pix]; + while (sameCount < 128 && sameCount+pix < numpix && col == templine[pix+sameCount]) + sameCount++; + + fprintASCII85(psfile, 257-sameCount); + fprintASCII85(psfile, 255-col); + + // Skip ahead + pix += sameCount; + } + else + { + // Find end of heterogenous area + Bit8u diffCount = 1; + while (diffCount < 128 && diffCount+pix < numpix && + ( + (diffCount+pix < numpix-2) + || (templine[pix+diffCount] != templine[pix+diffCount+1]) + || (templine[pix+diffCount] != templine[pix+diffCount+2]) + )) + diffCount++; + + fprintASCII85(psfile, diffCount-1); + for (Bit8u i=0; iw, page->h, page->w, page->h, page->h); + fprintf(psfile, "currentfile\n"); + fprintf(psfile, "/ASCII85Decode filter\n"); + fprintf(psfile, "/RunLengthDecode filter\n"); + fprintf(psfile, "image\n"); + + SDL_LockSurface(page); + + Bit32u pix = 0; + Bit32u numpix = page->h*page->w; + ASCII85BufferPos = ASCII85CurCol = 0; + + while (pix < numpix) + { + // Compress data using RLE + + if ((pix < numpix-2) && (getPixel(pix) == getPixel(pix+1)) && (getPixel(pix) == getPixel(pix+2))) + { + // Found three or more pixels with the same color + Bit8u sameCount = 3; + Bit8u col = getPixel(pix); + while (sameCount < 128 && sameCount+pix < numpix && col == getPixel(pix+sameCount)) + sameCount++; + + fprintASCII85(psfile, 257-sameCount); + fprintASCII85(psfile, 255-col); + + // Skip ahead + pix += sameCount; + } + else + { + // Find end of heterogenous area + Bit8u diffCount = 1; + while (diffCount < 128 && diffCount+pix < numpix && + ( + (diffCount+pix < numpix-2) + || (getPixel(pix+diffCount) != getPixel(pix+diffCount+1)) + || (getPixel(pix+diffCount) != getPixel(pix+diffCount+2)) + )) + diffCount++; + + fprintASCII85(psfile, diffCount-1); + for (Bit8u i=0; i= 79) + { + ASCII85CurCol = 0; + fprintf(f, "\n"); + } + } + else + { + char buffer[5]; + for (Bit8s i=4; i>=0; i--) + { + buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85); + buffer[i] += 33; + num /= (Bit32u)85; + } + + // Make sure a line never starts with a % (which may be mistaken as start of a comment) + if (ASCII85CurCol == 0 && buffer[0] == '%') + fprintf(f, " "); + + for (int i=0; i<((b != 257)?5:ASCII85BufferPos+1); i++) + { + fprintf(f, "%c", buffer[i]); + if (++ASCII85CurCol >= 79) + { + ASCII85CurCol = 0; + fprintf(f, "\n"); + } + } + } + + ASCII85BufferPos = 0; + } + + } + else // Close string + { + // Partial tupel if there are still bytes in the buffer + if (ASCII85BufferPos > 0) + { + for (Bit8u i = ASCII85BufferPos; i < 4; i++) + ASCII85Buffer[i] = 0; + + fprintASCII85(f, 257); + } + + fprintf(f, "~"); + fprintf(f, ">\n"); + } +} + +void Imagewriter::finishMultipage() +{ + if (outputHandle != NULL) + { + if (strcasecmp(output, "ps") == 0) + { + FILE* psfile = (FILE*)outputHandle; + fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); + fprintf(psfile, "%%%%EOF\n"); + fclose(psfile); + } + if (strcasecmp(output, "colorps") == 0) + { + FILE* psfile = (FILE*)outputHandle; + fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); + fprintf(psfile, "%%%%EOF\n"); + fclose(psfile); + } + else if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + EndDoc(printerDC); +#endif + } + outputHandle = NULL; + } +} + +bool Imagewriter::isBlank() { + bool blank = true; + SDL_LockSurface(page); + + for (Bit16u y=0; yh; y++) + for (Bit16u x=0; xw; x++) + if (*((Bit8u*)page->pixels + x + (y*page->pitch)) != 0) + blank = false; + + SDL_UnlockSurface(page); + return blank; +} + +Bit8u Imagewriter::getxyPixel(Bit32u x,Bit32u y) { + Bit8u *p; + + /* get the X/Y values within the bounds of this surface */ + if ((unsigned) x > (unsigned) page->w - 1u) + x = (x < 0) ? 0 : page->w - 1; + if ((unsigned) y > (unsigned) page->h - 1u) + y = (y < 0) ? 0 : page->h - 1; + + /* Set a pointer to the exact location in memory of the pixel + in question: */ + + p = (Bit8u *) (((Bit8u *) page->pixels) + /* Start at top of RAM */ + (y * page->pitch) + /* Go down Y lines */ + x); /* Go in X pixels */ + + + /* Return the correctly-sized piece of data containing the + * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit + * RGB value) */ + + return (*p); +} +Bit8u Imagewriter::getPixel(Bit32u num) { + Bit32u pixel = *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); + return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); +} +#endif // HAVE_SDL + +//Interfaces to C code + + +extern "C" void imagewriter_init(int pdpi, int ppaper, int banner, char* poutput, bool mpage) +{ + if (defaultImagewriter != NULL) return; //if Imagewriter on this port is initialized, reuse it + defaultImagewriter = new Imagewriter(pdpi, ppaper, banner, poutput, mpage); +} +extern "C" void imagewriter_loop(Bit8u pchar) +{ + if (defaultImagewriter == NULL) return; + defaultImagewriter->printChar(pchar); +} + +extern "C" void imagewriter_close() +{ + delete defaultImagewriter; + defaultImagewriter = NULL; +} +extern "C" void imagewriter_feed() +{ + if(defaultImagewriter == NULL) return; + defaultImagewriter->formFeed(); +} diff --git a/src/imagewriter.h b/src/imagewriter.h index ce59ae0..e41e066 100644 --- a/src/imagewriter.h +++ b/src/imagewriter.h @@ -1,316 +1,318 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2011 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * Copyright (C) 2002-2004 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - Modified for the GSport emulator by Christopher G. Mason 02/2014 - Extensively rewritten to provide full emulation of the Apple ImageWriter II - printer. - - Information used to write this emulator was provided by - Apple's "ImageWriter II Technical Reference Manual" - ISBN# 0-201-17766-8 - - Apple's "ImageWriter LQ Reference Manual" - ISBN# 0-201-17751-X - */ - -#if !defined __IMAGEWRITER_H -#define __IMAGEWRITER_H -#ifdef __cplusplus -#ifdef C_LIBPNG -#include -#endif - -#include - -#ifdef HAVE_SDL -#include "SDL.h" - -#include -#include FT_FREETYPE_H -#endif // HAVE_SDL - -#if defined (WIN32) -#include -#include -#endif - -#define STYLE_PROP 0x01 -#define STYLE_CONDENSED 0x02 -#define STYLE_BOLD 0x04 -#define STYLE_DOUBLESTRIKE 0x08 -#define STYLE_DOUBLEWIDTH 0x10 -#define STYLE_ITALICS 0x20 -#define STYLE_UNDERLINE 0x40 -#define STYLE_SUPERSCRIPT 0x80 -#define STYLE_SUBSCRIPT 0x100 -#define STYLE_HALFHEIGHT 0x200 - -#define SCORE_NONE 0x00 -#define SCORE_SINGLE 0x01 -#define SCORE_DOUBLE 0x02 -#define SCORE_SINGLEBROKEN 0x05 -#define SCORE_DOUBLEBROKEN 0x06 - -#define QUALITY_DRAFT 0x01 -#define QUALITY_LQ 0x02 - -#define COLOR_BLACK 7<<5 -typedef unsigned Bitu; -typedef signed Bits; -typedef unsigned char Bit8u; -typedef signed char Bit8s; -typedef unsigned short Bit16u; -typedef signed short Bit16s; -typedef unsigned long Bit32u; -typedef signed long Bit32s; -typedef double Real64; -#if defined(_MSC_VER) -typedef unsigned __int64 Bit64u; -typedef signed __int64 Bit64s; -#else -typedef unsigned long long int Bit64u; -typedef signed long long int Bit64s; -#endif -enum IWTypeface -{ - fixed = 0, - prop = 1 -}; - -typedef struct { - Bitu codepage; - const Bit16u* map; -} IWCHARMAP; - - -class Imagewriter { -public: - - Imagewriter (Bit16u dpi, Bit16u paperSize, Bit16u bannerSize, char* output, bool multipageOutput); - virtual ~Imagewriter(); - - // Process one character sent to virtual printer - void printChar(Bit8u ch); - - // Hard Reset (like switching printer off and on) - void resetPrinterHard(); - - // Set Autofeed value - void setAutofeed(bool feed); - - // Get Autofeed value - bool getAutofeed(); - - // True if printer is unable to process more data right now (do not use printChar) - bool isBusy(); - - // True if the last sent character was received - bool ack(); - - // Manual formfeed - void formFeed(); - -#ifdef HAVE_SDL - // Returns true if the current page is blank - bool isBlank(); -#endif // HAVE_SDL - -private: - - // Resets the printer to the factory settings - void resetPrinter(); - - // Clears page. If save is true, saves the current page to a bitmap - void newPage(bool save, bool resetx); - - // Closes a multipage document - void finishMultipage(); - - // Output current page - void outputPage(); - -#ifdef HAVE_SDL - // used to fill the color "sub-pallettes" - void FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, - SDL_Palette* pal); - - // Checks if given char belongs to a command and process it. If false, the character - // should be printed - bool processCommandChar(Bit8u ch); - - // Reload font. Must be called after changing dpi, style or cpi - void updateFont(); - - // Reconfigures printer parameters after changing soft-switches with ESC Z and ESC D - void updateSwitch(); - - // Overprints a slash over zero if softswitch B-1 is set - void slashzero(Bit16u penX, Bit16u penY); - - // Blits the given glyph on the page surface. If add is true, the values of bitmap are - // added to the values of the pixels in the page - void blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add); - - // Draws an anti-aliased line from (fromx, y) to (tox, y). If broken is true, gaps are included - void drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken); - - // Setup the bitGraph structure - void setupBitImage(Bit8u dens, Bit16u numCols); - - // Process a character that is part of bit image. Must be called iff bitGraph.remBytes > 0. - void printBitGraph(Bit8u ch); - - // Copies the codepage mapping from the constant array to CurMap - void selectCodepage(Bit16u cp); - - // Prints out a byte using ASCII85 encoding (only outputs something every four bytes). When b>255, closes the ASCII85 string - void fprintASCII85(FILE* f, Bit16u b); - - // Returns value of the num-th pixel (couting left-right, top-down) in a safe way - Bit8u getPixel(Bit32u num); - Bit8u getxyPixel(Bit32u x,Bit32u y); - - FT_Library FTlib; // FreeType2 library used to render the characters - - SDL_Surface* page; // Surface representing the current page - FT_Face curFont; // The font currently used to render characters - Bit8u color; - Bit8u switcha; //Imagewriter softswitch A - Bit8u switchb; //Imagewriter softswitch B - - Real64 curX, curY; // Position of the print head (in inch) - - Bit16u dpi; // dpi of the page - Bit16u ESCCmd; // ESC-command that is currently processed - bool ESCSeen; // True if last read character was an ESC (0x1B) - bool FSSeen; // True if last read character was an FS (0x1C) (IBM commands) - Bit8u numParam, neededParam; // Numbers of parameters already read/needed to process command - - Bit8u params[20]; // Buffer for the read params - Bit16u style; // Style of font (see STYLE_* constants) - Real64 cpi, actcpi; // CPI value set by program and the actual one (taking in account font types) - Bit8u score; // Score for lines (see SCORE_* constants) - Bit8u verticalDot; // Vertical dot shift for Imagewriter LQ modes - - Real64 topMargin, bottomMargin, rightMargin, leftMargin; // Margins of the page (in inch) - Real64 pageWidth, pageHeight; // Size of page (in inch) - Real64 defaultPageWidth, defaultPageHeight; // Default size of page (in inch) - Real64 lineSpacing; // Size of one line (in inch) - - Real64 horiztabs[32]; // Stores the set horizontal tabs (in inch) - Bit8u numHorizTabs; // Number of configured tabs - - Real64 verttabs[16]; // Stores the set vertical tabs (in inch) - Bit8u numVertTabs; // Number of configured tabs - - Bit8u curCharTable; // Currently used char table und charset - Bit8u printQuality; // Print quality (see QUALITY_* constants) - Bit8u printRes; // Graphics resolution - IWTypeface LQtypeFace; // Typeface used in LQ printing mode - - Real64 extraIntraSpace; // Extra space between two characters (set by program, in inch) - - bool charRead; // True if a character was read since the printer was last initialized - bool autoFeed; // True if a LF should automatically added after a CR - bool printUpperContr; // True if the upper command characters should be printed - - struct bitGraphicParams // Holds information about printing bit images - { - Bit16u horizDens, vertDens; // Density of image to print (in dpi) - bool adjacent; // Print adjacent pixels? (ignored) - Bit8u bytesColumn; // Bytes per column - Bit16u remBytes; // Bytes left to read before image is done - Bit8u column[6]; // Bytes of the current and last column - Bit8u readBytesColumn; // Bytes read so far for the current column - } bitGraph; - - Bit8u densk, densl, densy, densz; // Image density modes used in ESC K/L/Y/Z commands - - Bit16u curMap[256]; // Currently used ASCII => Unicode mapping - Bit16u charTables[4]; // Charactertables - - Real64 definedUnit; // Unit used by some ESC/P2 commands (negative => use default) - - bool multipoint; // If multipoint mode is enabled - Real64 multiPointSize; // Point size of font in multipoint mode - Real64 multicpi; // CPI used in multipoint mode - - Real64 hmi; // Horizontal motion index (in inch; overrides CPI settings) - - Bit16u numPrintAsChar; // Number of bytes to print as characters (even when normally control codes) - -#if defined (WIN32) - HDC printerDC; // Win32 printer device -#endif - int port; // SCC Port - -#endif // HAVE_SDL - Bit8u msb; // MSB mode - - char* output; // Output method selected by user - void* outputHandle; // If not null, additional pages will be appended to the given handle - bool multipageOutput; // If true, all pages are combined to one file/print job etc. until the "eject page" button is pressed - Bit16u multiPageCounter; // Current page (when printing multipages) - - Bit8u ASCII85Buffer[4]; // Buffer used in ASCII85 encoding - Bit8u ASCII85BufferPos; // Position in ASCII85 encode buffer - Bit8u ASCII85CurCol; // Columns printed so far in the current lines -}; - -#endif - -//Interfaces to C code -#ifdef __cplusplus -extern "C" -{ +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2010 - 2011 by GSport contributors + + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Copyright (C) 2002-2004 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Modified for the GSport emulator by Christopher G. Mason 02/2014 + Extensively rewritten to provide full emulation of the Apple ImageWriter II + printer. + + Information used to write this emulator was provided by + Apple's "ImageWriter II Technical Reference Manual" + ISBN# 0-201-17766-8 + + Apple's "ImageWriter LQ Reference Manual" + ISBN# 0-201-17751-X + */ + +#if !defined __IMAGEWRITER_H +#define __IMAGEWRITER_H +#ifdef __cplusplus +#ifdef C_LIBPNG +#include +#endif + +#include + +#ifdef HAVE_SDL +#include "SDL.h" + +#include +#include FT_FREETYPE_H +#endif // HAVE_SDL + +#if defined (WIN32) +#include +#include +#endif + +#define STYLE_PROP 0x01 +#define STYLE_CONDENSED 0x02 +#define STYLE_BOLD 0x04 +#define STYLE_DOUBLESTRIKE 0x08 +#define STYLE_DOUBLEWIDTH 0x10 +#define STYLE_ITALICS 0x20 +#define STYLE_UNDERLINE 0x40 +#define STYLE_SUPERSCRIPT 0x80 +#define STYLE_SUBSCRIPT 0x100 +#define STYLE_HALFHEIGHT 0x200 + +#define SCORE_NONE 0x00 +#define SCORE_SINGLE 0x01 +#define SCORE_DOUBLE 0x02 +#define SCORE_SINGLEBROKEN 0x05 +#define SCORE_DOUBLEBROKEN 0x06 + +#define QUALITY_DRAFT 0x01 +#define QUALITY_LQ 0x02 + +#define COLOR_BLACK 7<<5 +typedef unsigned Bitu; +typedef signed Bits; +typedef unsigned char Bit8u; +typedef signed char Bit8s; +typedef unsigned short Bit16u; +typedef signed short Bit16s; +typedef unsigned long Bit32u; +typedef signed long Bit32s; +typedef double Real64; +#if defined(_MSC_VER) +typedef unsigned __int64 Bit64u; +typedef signed __int64 Bit64s; +#else +typedef unsigned long long int Bit64u; +typedef signed long long int Bit64s; +#endif +enum IWTypeface +{ + fixed = 0, + prop = 1 +}; + +typedef struct { + Bitu codepage; + const Bit16u* map; +} IWCHARMAP; + + +class Imagewriter { +public: + + Imagewriter (Bit16u dpi, Bit16u paperSize, Bit16u bannerSize, char* output, bool multipageOutput); + virtual ~Imagewriter(); + + // Process one character sent to virtual printer + void printChar(Bit8u ch); + + // Hard Reset (like switching printer off and on) + void resetPrinterHard(); + + // Set Autofeed value + void setAutofeed(bool feed); + + // Get Autofeed value + bool getAutofeed(); + + // True if printer is unable to process more data right now (do not use printChar) + bool isBusy(); + + // True if the last sent character was received + bool ack(); + + // Manual formfeed + void formFeed(); + +#ifdef HAVE_SDL + // Returns true if the current page is blank + bool isBlank(); +#endif // HAVE_SDL + +private: + + // Resets the printer to the factory settings + void resetPrinter(); + + // Clears page. If save is true, saves the current page to a bitmap + void newPage(bool save, bool resetx); + + // Closes a multipage document + void finishMultipage(); + + // Output current page + void outputPage(); + +#ifdef HAVE_SDL + // used to fill the color "sub-pallettes" + void FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, + SDL_Palette* pal); + + // Checks if given char belongs to a command and process it. If false, the character + // should be printed + bool processCommandChar(Bit8u ch); + + // Reload font. Must be called after changing dpi, style or cpi + void updateFont(); + + // Reconfigures printer parameters after changing soft-switches with ESC Z and ESC D + void updateSwitch(); + + // Overprints a slash over zero if softswitch B-1 is set + void slashzero(Bit16u penX, Bit16u penY); + + // Blits the given glyph on the page surface. If add is true, the values of bitmap are + // added to the values of the pixels in the page + void blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add); + + // Draws an anti-aliased line from (fromx, y) to (tox, y). If broken is true, gaps are included + void drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken); + + // Setup the bitGraph structure + void setupBitImage(Bit8u dens, Bit16u numCols); + + // Process a character that is part of bit image. Must be called iff bitGraph.remBytes > 0. + void printBitGraph(Bit8u ch); + + // Copies the codepage mapping from the constant array to CurMap + void selectCodepage(Bit16u cp); + + // Prints out a byte using ASCII85 encoding (only outputs something every four bytes). When b>255, closes the ASCII85 string + void fprintASCII85(FILE* f, Bit16u b); + + // Returns value of the num-th pixel (couting left-right, top-down) in a safe way + Bit8u getPixel(Bit32u num); + Bit8u getxyPixel(Bit32u x,Bit32u y); + + FT_Library FTlib; // FreeType2 library used to render the characters + + SDL_Surface* page; // Surface representing the current page + FT_Face curFont; // The font currently used to render characters + Bit8u color; + Bit8u switcha; //Imagewriter softswitch A + Bit8u switchb; //Imagewriter softswitch B + + Real64 curX, curY; // Position of the print head (in inch) + + Bit16u dpi; // dpi of the page + Bit16u ESCCmd; // ESC-command that is currently processed + bool ESCSeen; // True if last read character was an ESC (0x1B) + bool FSSeen; // True if last read character was an FS (0x1C) (IBM commands) + Bit8u numParam, neededParam; // Numbers of parameters already read/needed to process command + + Bit8u params[20]; // Buffer for the read params + Bit16u style; // Style of font (see STYLE_* constants) + Real64 cpi, actcpi; // CPI value set by program and the actual one (taking in account font types) + Bit8u score; // Score for lines (see SCORE_* constants) + Bit8u verticalDot; // Vertical dot shift for Imagewriter LQ modes + + Real64 topMargin, bottomMargin, rightMargin, leftMargin; // Margins of the page (in inch) + Real64 pageWidth, pageHeight; // Size of page (in inch) + Real64 defaultPageWidth, defaultPageHeight; // Default size of page (in inch) + Real64 lineSpacing; // Size of one line (in inch) + + Real64 horiztabs[32]; // Stores the set horizontal tabs (in inch) + Bit8u numHorizTabs; // Number of configured tabs + + Real64 verttabs[16]; // Stores the set vertical tabs (in inch) + Bit8u numVertTabs; // Number of configured tabs + + Bit8u curCharTable; // Currently used char table und charset + Bit8u printQuality; // Print quality (see QUALITY_* constants) + Bit8u printRes; // Graphics resolution + IWTypeface LQtypeFace; // Typeface used in LQ printing mode + + Real64 extraIntraSpace; // Extra space between two characters (set by program, in inch) + + bool charRead; // True if a character was read since the printer was last initialized + bool autoFeed; // True if a LF should automatically added after a CR + bool printUpperContr; // True if the upper command characters should be printed + + struct bitGraphicParams // Holds information about printing bit images + { + Bit16u horizDens, vertDens; // Density of image to print (in dpi) + bool adjacent; // Print adjacent pixels? (ignored) + Bit8u bytesColumn; // Bytes per column + Bit16u remBytes; // Bytes left to read before image is done + Bit8u column[6]; // Bytes of the current and last column + Bit8u readBytesColumn; // Bytes read so far for the current column + } bitGraph; + + Bit8u densk, densl, densy, densz; // Image density modes used in ESC K/L/Y/Z commands + + Bit16u curMap[256]; // Currently used ASCII => Unicode mapping + Bit16u charTables[4]; // Charactertables + + Real64 definedUnit; // Unit used by some ESC/P2 commands (negative => use default) + + bool multipoint; // If multipoint mode is enabled + Real64 multiPointSize; // Point size of font in multipoint mode + Real64 multicpi; // CPI used in multipoint mode + + Real64 hmi; // Horizontal motion index (in inch; overrides CPI settings) + + Bit16u numPrintAsChar; // Number of bytes to print as characters (even when normally control codes) + +#if defined (WIN32) + HDC printerDC; // Win32 printer device +#endif + int port; // SCC Port + +#endif // HAVE_SDL + Bit8u msb; // MSB mode + + char* output; // Output method selected by user + void* outputHandle; // If not null, additional pages will be appended to the given handle + bool multipageOutput; // If true, all pages are combined to one file/print job etc. until the "eject page" button is pressed + Bit16u multiPageCounter; // Current page (when printing multipages) + + Bit8u ASCII85Buffer[4]; // Buffer used in ASCII85 encoding + Bit8u ASCII85BufferPos; // Position in ASCII85 encode buffer + Bit8u ASCII85CurCol; // Columns printed so far in the current lines +}; + +#endif + +//Interfaces to C code +#ifdef __cplusplus +extern "C" +{ #else #include typedef unsigned char Bit8u; -#endif - -void imagewriter_init(int pdpi, int ppaper, int banner, char* poutput, bool mpage); -void imagewriter_loop(Bit8u pchar); -void imagewriter_close(); -void imagewriter_feed(); -#ifdef __cplusplus -} -#endif - -#endif +#endif + +void imagewriter_init(int pdpi, int ppaper, int banner, char* poutput, bool mpage); +void imagewriter_loop(Bit8u pchar); +void imagewriter_close(); +void imagewriter_feed(); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/instable.h b/src/instable.h index 66b09c5..545866f 100644 --- a/src/instable.h +++ b/src/instable.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/iw_charmaps.h b/src/iw_charmaps.h index acf4854..5ca42ad 100644 --- a/src/iw_charmaps.h +++ b/src/iw_charmaps.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/iwm.c b/src/iwm.c index 048d0d7..0a2fe7d 100644 --- a/src/iwm.c +++ b/src/iwm.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -22,7 +24,7 @@ #include "defc.h" extern int Verbose; -extern word32 g_vbl_count; // OG change int to word32 +extern word32 g_vbl_count; // OG change int to word32 extern int g_c036_val_speed; const byte phys_to_dos_sec[] = { @@ -175,24 +177,24 @@ iwm_init() iwm_reset(); } -// OG Added shut function to IWM -// Free the memory, and more important free the open handle onto the disk -void -iwm_shut() -{ - int i; - for(i = 0; i < 2; i++) { - eject_disk(&iwm.drive525[i]); - eject_disk(&iwm.drive35[i]); - } - - for(i = 0; i < MAX_C7_DISKS; i++) { - eject_disk(&iwm.smartport[i]); - } - - from_disk_byte_valid = 0; -} - +// OG Added shut function to IWM +// Free the memory, and more important free the open handle onto the disk +void +iwm_shut() +{ + int i; + for(i = 0; i < 2; i++) { + eject_disk(&iwm.drive525[i]); + eject_disk(&iwm.drive35[i]); + } + + for(i = 0; i < MAX_C7_DISKS; i++) { + eject_disk(&iwm.smartport[i]); + } + + from_disk_byte_valid = 0; +} + void iwm_reset() { @@ -235,19 +237,19 @@ draw_iwm_status(int line, char *buf) flag[apple35_sel][iwm.drive_select] = "*"; } - #ifdef ACTIVEGS // OG Pass monitoring info - { - extern void ki_loading(int _motorOn,int _slot,int _drive, int _curtrack); - int curtrack=0; - if (apple35_sel) - curtrack = iwm.drive35[iwm.drive_select].cur_qtr_track ; - else - curtrack = iwm.drive525[iwm.drive_select].cur_qtr_track >> 2 ; - - ki_loading(g_iwm_motor_on,apple35_sel?5:6,iwm.drive_select+1,curtrack); - } - #endif - + #ifdef ACTIVEGS // OG Pass monitoring info + { + extern void ki_loading(int _motorOn,int _slot,int _drive, int _curtrack); + int curtrack=0; + if (apple35_sel) + curtrack = iwm.drive35[iwm.drive_select].cur_qtr_track ; + else + curtrack = iwm.drive525[iwm.drive_select].cur_qtr_track >> 2 ; + + ki_loading(g_iwm_motor_on,apple35_sel?5:6,iwm.drive_select+1,curtrack); + } + #endif + sprintf(buf, "s6d1:%2d%s s6d2:%2d%s s5d1:%2d/%d%s " "s5d2:%2d/%d%s fast_disk_emul:%d,%d c036:%02x", iwm.drive525[0].cur_qtr_track >> 2, flag[0][0], @@ -347,7 +349,7 @@ iwm_vbl_update(int doit_3_persec) int i; if(iwm.motor_on && iwm.motor_off) { - if((word32)iwm.motor_off_vbl_count <= g_vbl_count) { + if((word32)iwm.motor_off_vbl_count <= g_vbl_count) { printf("Disk timer expired, drive off: %08x\n", g_vbl_count); iwm.motor_on = 0; @@ -581,9 +583,9 @@ iwm525_phase_change(int drive, int phase) int half_track = qtr_track >> 1; delta = 0; - if (iwm.iwm_phase[(half_track + 1) & 3]) + if (iwm.iwm_phase[(half_track + 1) & 3]) delta += 2; - if (iwm.iwm_phase[(half_track + 3) & 3]) + if (iwm.iwm_phase[(half_track + 3) & 3]) delta -= 2; qtr_track += delta; @@ -754,12 +756,12 @@ iwm_do_action35(double dcycs) break; case 0x0d: /* eject disk */ eject_disk(dsk); - #ifdef ACTIVEGS // OG : pass eject info to the Control (ActiveX specific) - { - extern void ejectDisk(int slot,int disk); - ejectDisk(dsk->disk_525?6:5,dsk->drive+1); - } - #endif + #ifdef ACTIVEGS // OG : pass eject info to the Control (ActiveX specific) + { + extern void ejectDisk(int slot,int disk); + ejectDisk(dsk->disk_525?6:5,dsk->drive+1); + } + #endif break; case 0x02: case 0x07: @@ -1669,24 +1671,24 @@ disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf) return -1; } - if(disk_525) - { - // OG - // Add support for .nib file - if (dsk->image_type!=DSK_TYPE_NIB) + if(disk_525) + { + // OG + // Add support for .nib file + if (dsk->image_type!=DSK_TYPE_NIB) return iwm_denib_track525(dsk, trk, qtr_track, outbuf); - else - { - int len = trk->track_len; - byte* trk_ptr = trk->nib_area+1; - byte* nib_ptr = outbuf; - for(i = 0; i < len; i += 2) - { - *nib_ptr++ = *trk_ptr; - trk_ptr+=2; - } - return 1; - } + else + { + int len = trk->track_len; + byte* trk_ptr = trk->nib_area+1; + byte* nib_ptr = outbuf; + for(i = 0; i < len; i += 2) + { + *nib_ptr++ = *trk_ptr; + trk_ptr+=2; + } + return 1; + } } else { return iwm_denib_track35(dsk, trk, qtr_track, outbuf); } diff --git a/src/iwm.h b/src/iwm.h index 81e25d2..ccb5cfd 100644 --- a/src/iwm.h +++ b/src/iwm.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/iwm_35_525.h b/src/iwm_35_525.h index d59d4ac..c8b887d 100644 --- a/src/iwm_35_525.h +++ b/src/iwm_35_525.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/joystick_driver.c b/src/joystick_driver.c index 9e24630..875c1d5 100644 --- a/src/joystick_driver.c +++ b/src/joystick_driver.c @@ -1,5 +1,7 @@ /* GSport - an Apple //gs Emulator + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2013 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey diff --git a/src/macdriver_console.c b/src/macdriver_console.c index f18aef6..19019da 100755 --- a/src/macdriver_console.c +++ b/src/macdriver_console.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey diff --git a/src/macdriver_generic.c b/src/macdriver_generic.c index f733ac6..72264a1 100755 --- a/src/macdriver_generic.c +++ b/src/macdriver_generic.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/macsnd_driver.c b/src/macsnd_driver.c index 0a2ecb2..db9cb51 100644 --- a/src/macsnd_driver.c +++ b/src/macsnd_driver.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/moremem.c b/src/moremem.c index 4e2240d..8510796 100644 --- a/src/moremem.c +++ b/src/moremem.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2014 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey diff --git a/src/op_routs.h b/src/op_routs.h index f18940e..faaac6b 100644 --- a/src/op_routs.h +++ b/src/op_routs.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/osxdriver.c b/src/osxdriver.c index 6a47a4f..2cc5ae4 100644 --- a/src/osxdriver.c +++ b/src/osxdriver.c @@ -1,561 +1,563 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2012 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -// This is an experimental video driver for the KEGS/GSport emulator. -// It requires SDL2 libraries to build. I've tested on Mac, but should -// be easy to port to other platforms. -DagenBrock - -// @todo: mouse clip bugs.. great western shootout. -// @todo: force refresh after screen mode change - -#include "SDL.h" -#include -#include -#include -#include -#include "defc.h" - -// BITMASKS -#define ShiftMask 1 -#define ControlMask 4 -#define LockMask 2 - -int g_use_shmem = 0; - -int g_num_check_input_calls = 0; -int g_check_input_flush_rate = 2; -int g_win_status_debug = 0; // Current visibility of status lines. -int g_win_status_debug_request = 0; // Desired visibility of status lines. -int g_screen_mdepth = 0; -int kb_shift_control_state = 0; - -extern int g_screen_depth; -extern int g_quit_sim_now; -extern int g_border_sides_refresh_needed; -extern int g_border_special_refresh_needed; -extern int g_status_refresh_needed; -extern int g_lores_colors[]; -extern int g_a2vid_palette; -extern int g_installed_full_superhires_colormap; -extern char *g_status_ptrs[MAX_STATUS_LINES]; -extern word32 g_a2_screen_buffer_changed; -extern word32 g_full_refresh_needed; -extern word32 g_palette_8to1624[256]; -extern word32 g_a2palette_8to1624[256]; -extern Kimage g_mainwin_kimage; - -SDL_Window *window; // Declare a pointer -SDL_Renderer *renderer; -SDL_Texture *texture; - -void dev_video_init_sdl(); -void handle_sdl_key_event(SDL_Event event); -void check_input_events_sdl(); -int handle_sdl_mouse_motion_event(SDL_Event event); - -int g_num_a2_keycodes = 0; -int a2_key_to_sdlkeycode[][3] = { - { 0x12, SDLK_1, 0}, - { 0x35, SDLK_ESCAPE,0 }, - { 0x7a, SDLK_F1, 0 }, - { 0x78, SDLK_F2, 0 }, - { 0x63, SDLK_F3, 0 }, - { 0x76, SDLK_F4, 0 }, - { 0x60, SDLK_F5, 0 }, - { 0x61, SDLK_F6, 0 }, - { 0x62, SDLK_F7, 0 }, - { 0x64, SDLK_F8, 0 }, - { 0x65, SDLK_F9, 0 }, - { 0x6d, SDLK_F10, 0 }, - { 0x67, SDLK_F11, 0 }, - { 0x6f, SDLK_F12, 0 }, - { 0x69, SDLK_F13, 0 }, - { 0x6b, SDLK_F14, 0 }, - { 0x71, SDLK_F15, 0 }, - { 0x7f, SDLK_PAUSE, 0 }, - { 0x32, '`', '~' }, /* Key number 18? */ - { 0x12, '1', '!' }, - { 0x13, '2', '@' }, - { 0x14, '3', '#' }, - { 0x15, '4', '$' }, - { 0x17, '5', '%' }, - { 0x16, '6', '^' }, - { 0x1a, '7', '&' }, - { 0x1c, '8', '*' }, - { 0x19, '9', '(' }, - { 0x1d, '0', ')' }, - { 0x1b, '-', '_' }, - { 0x18, '=', '+' }, - { 0x33, SDLK_BACKSPACE, 0 }, - { 0x72, SDLK_INSERT, 0 }, /* Help? XK_Help */ -/* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ - { 0x74, SDLK_PAGEUP, 0 }, - { 0x47, SDLK_NUMLOCKCLEAR, 0 }, /* Clear, XK_Clear */ - { 0x51, SDLK_KP_EQUALS, 0 }, /* Note XK_Home alias! XK_Home */ - { 0x4b, SDLK_KP_DIVIDE, 0 }, - { 0x43, SDLK_KP_MULTIPLY, 0 }, - { 0x30, SDLK_TAB, 0 }, - { 0x0c, 'q', 'Q' }, - { 0x0d, 'w', 'W' }, - { 0x0e, 'e', 'E' }, - { 0x0f, 'r', 'R' }, - { 0x11, 't', 'T' }, - { 0x10, 'y', 'Y' }, - { 0x20, 'u', 'U' }, - { 0x22, 'i', 'I' }, - { 0x1f, 'o', 'O' }, - { 0x23, 'p', 'P' }, - { 0x21, '[', '{' }, - { 0x1e, ']', '}' }, - { 0x2a, 0x5c, '|' }, /* backslash, bar */ - { 0x75, SDLK_DELETE, 0 }, - { 0x77, SDLK_END, 0 }, - { 0x79, SDLK_PAGEDOWN, 0 }, - { 0x59, SDLK_KP_7, 0 }, - { 0x5b, SDLK_KP_8, 0 }, - { 0x5c, SDLK_KP_9, 0 }, - { 0x4e, SDLK_KP_MINUS, 0 }, - { 0x39, SDLK_CAPSLOCK, 0 }, - { 0x00, 'a', 'A' }, - { 0x01, 's', 'S' }, - { 0x02, 'd', 'D' }, - { 0x03, 'f', 'F' }, - { 0x05, 'g', 'G' }, - { 0x04, 'h', 'H' }, - { 0x26, 'j', 'J' }, - { 0x28, 'k', 'K' }, - { 0x25, 'l', 'L' }, - { 0x29, ';', ':' }, - { 0x27, 0x27, '"' }, /* single quote */ - { 0x24, SDLK_RETURN, 0 }, - { 0x56, SDLK_KP_4, SDLK_LEFT}, - { 0x57, SDLK_KP_5, 0 }, - { 0x58, SDLK_KP_6, SDLK_RIGHT }, - { 0x45, SDLK_KP_PLUS, 0 }, - { 0x38, SDLK_LSHIFT, SDLK_RSHIFT }, - { 0x06, 'z', 'Z' }, - { 0x07, 'x', 'X' }, - { 0x08, 'c', 'C' }, - { 0x09, 'v', 'V' }, - { 0x0b, 'b', 'B' }, - { 0x2d, 'n', 'N' }, - { 0x2e, 'm', 'M' }, - { 0x2b, ',', '<' }, - { 0x2f, '.', '>' }, - { 0x2c, '/', '?' }, - { 0x3e, SDLK_UP, 0 }, - { 0x53, SDLK_KP_1, 0 }, - { 0x54, SDLK_KP_2, SDLK_DOWN }, - { 0x55, SDLK_KP_3, 0 }, - { 0x36, SDLK_RCTRL, SDLK_LCTRL }, - { 0x3a, SDLK_LALT, SDLK_RALT }, /* Option */ - { 0x37, SDLK_LGUI, SDLK_RGUI }, /* Command */ - { 0x31, ' ', 0 }, - { 0x3b, SDLK_LEFT, 0 }, - { 0x3d, SDLK_DOWN, 0 }, - { 0x3c, SDLK_RIGHT, 0 }, - { 0x52, SDLK_KP_0, 0 }, - { 0x41, SDLK_KP_PERIOD, 0 }, - { 0x4c, SDLK_KP_ENTER, 0 }, - { -1, -1, -1 } - -}; -int -main(int argc, char **argv) -{ - return gsportmain(argc, argv); -} - - - -/// Queries the Screen to see if it's set to Fullscreen or Not -/// @return SDL_FALSE if windowed, SDL_TRUE if fullscreen -SDL_bool IsFullScreen(SDL_Window *win) -{ - Uint32 flags = SDL_GetWindowFlags(win); - if (flags & SDL_WINDOW_FULLSCREEN) return SDL_TRUE; // return SDL_TRUE if fullscreen - return SDL_FALSE; // Return SDL_FALSE if windowed -} - - - - -void -dev_video_init() -{ - word32 lores_col; - - // build keycode map ?? - g_num_a2_keycodes = 0; - int i; - int keycode; - int tmp_array[0x80]; - for(i = 0; i <= 0x7f; i++) { - tmp_array[i] = 0; - } - for(i = 0; i < 0x7f; i++) { - keycode = a2_key_to_sdlkeycode[i][0]; - if(keycode < 0) { - g_num_a2_keycodes = i; - break; - } else if(keycode > 0x7f) { - printf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); - exit(2); - } else { - if(tmp_array[keycode]) { - printf("a2_key_to_x[%d] = %02x used by %d\n", - i, keycode, tmp_array[keycode] - 1); - } - tmp_array[keycode] = i + 1; - } - } - - // This actually creates our window - dev_video_init_sdl(); - - // @todo DANGER DANGER. HARD CODING THESE.. there was logic for stepping values in xdriver - g_screen_depth = 24; - g_screen_mdepth =32; - video_get_kimages(); - video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,g_screen_mdepth); - - for(i = 0; i < 256; i++) { - //g_xcolor_a2vid_array[i].pixel = i; - lores_col = g_lores_colors[i & 0xf]; - video_update_color_raw(i, lores_col); - g_a2palette_8to1624[i] = g_palette_8to1624[i]; - } -} - - - -// Initialize our SDL window and texture -void -dev_video_init_sdl() -{ - - SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2 - - // Create an application window with the following settings: - window = SDL_CreateWindow( - "GSPLUS V.0", // window title - SDL_WINDOWPOS_UNDEFINED, // initial x position - SDL_WINDOWPOS_UNDEFINED, // initial y position - BASE_WINDOW_WIDTH, // width, in pixels - X_A2_WINDOW_HEIGHT, // height, in pixels - SDL_WINDOW_OPENGL // flags - see below - ); - - // Check that the window was successfully created - if (window == NULL) { - // In the case that the window could not be made... - printf("Could not create window: %s\n", SDL_GetError()); - //@todo die, i guess - } else { - printf("SDL Window has been created\n"); - } - - renderer = SDL_CreateRenderer(window, -1, 0); - - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother. - // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); // make the scaled rendering look smoother. - SDL_RenderSetLogicalSize(renderer, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); - - texture = SDL_CreateTexture(renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); - // The window is open: could enter program loop here (see SDL_PollEvent()) - - SDL_ShowCursor(SDL_DISABLE); - -} - - -// Copy a rect to our SDL window -void sdl_push_kimage(Kimage *kimage_ptr, - int destx, int desty, int srcx, int srcy, int width, int height) -{ - byte *src_ptr; - int pixel_size = 4; - src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pixel_size; - //src_ptr = kimage_ptr->data_ptr; - - SDL_Rect dstrect; - dstrect.x = destx; - dstrect.y = desty; - dstrect.w = width; - dstrect.h = height; - int pitch = 640; - if (width < 560) { - pitch = EFF_BORDER_WIDTH; - // This is another bad hack. Possibly not cross platform. - pitch = BORDER_WIDTH+72; - //printf("EFF_BORDER_WIDTH : %d" ,EFF_BORDER_WIDTH); - } - //SDL_UpdateTexture(texture, NULL, src_ptr, 640 * sizeof (Uint32)); - SDL_UpdateTexture(texture, &dstrect, src_ptr, pitch*4 ); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, NULL, NULL); - SDL_RenderPresent(renderer); - -} - - -void set_refresh_needed() { - g_a2_screen_buffer_changed = -1; - g_full_refresh_needed = -1; - - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_status_refresh_needed = 1; -} - - -void -x_get_kimage(Kimage *kimage_ptr) { - byte *data; - int width; - int height; - int depth; - - width = kimage_ptr->width_req; - height = kimage_ptr->height; - depth = kimage_ptr->depth; - // this might be too big!!! I had it at depth/3 but it segfaults - data = malloc(width*height*(depth/4)); - kimage_ptr->data_ptr = data; -} - - -void -check_input_events() -{ - check_input_events_sdl(); -} - - -void -check_input_events_sdl() -{ - // @todo: make sure it's not queueing events / processing full queue each call - int motion = 0; - SDL_Event event; - - while (SDL_PollEvent(&event)) { - switch( event.type ){ - case SDL_KEYDOWN: - case SDL_KEYUP: - handle_sdl_key_event(event); - break; - case SDL_MOUSEMOTION: - case SDL_MOUSEBUTTONUP: - case SDL_MOUSEBUTTONDOWN: - motion |= handle_sdl_mouse_motion_event(event); - break; - case SDL_QUIT: - //quit = 1; /* SDL_QUIT event (window close) */ - SDL_DestroyWindow(window); - iwm_shut(); - // Clean up - SDL_Quit(); - my_exit(1); - break; - default: - break; - } - } -} - - -int -sdl_keysym_to_a2code(int keysym, int is_up) -{ - int i; - - if(keysym == 0) { - return -1; - } - - if((keysym == SDLK_LSHIFT) || (keysym == SDLK_RSHIFT)) { - if(is_up) { - kb_shift_control_state &= ~ShiftMask; - } else { - kb_shift_control_state |= ShiftMask; - } - } - if(keysym == SDLK_CAPSLOCK) { - if(is_up) { - kb_shift_control_state &= ~LockMask; - } else { - kb_shift_control_state |= LockMask; - } - } - if((keysym == SDLK_LCTRL) || (keysym == SDLK_RCTRL)) { - if(is_up) { - kb_shift_control_state &= ~ControlMask; - } else { - kb_shift_control_state |= ControlMask; - } - } - - /* Look up Apple 2 keycode */ - for(i = g_num_a2_keycodes - 1; i >= 0; i--) { - if((keysym == a2_key_to_sdlkeycode[i][1]) || - (keysym == a2_key_to_sdlkeycode[i][2])) { - return a2_key_to_sdlkeycode[i][0]; - } - } - - return -1; -} - - -void -handle_sdl_key_event(SDL_Event event) -{ - - int state_xor; - int state = 0; - int is_up; - - int mod = event.key.keysym.mod; - - // simulate xmask style here - // @todo: this can probably all be refactored now that X is gone - //state = state & (ControlMask | LockMask | ShiftMask); - - // when mod key is first press, comes as event, otherwise just a modifier - if( mod & KMOD_LCTRL || mod & KMOD_RCTRL || - event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL))) { - state = state | ControlMask; - } - if( (mod & KMOD_LSHIFT) || (mod & KMOD_RSHIFT) || - event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT))) { - state = state | ShiftMask; - } - if( mod & KMOD_CAPS) { - state = state | LockMask; - } - - state_xor = kb_shift_control_state ^ state; - is_up = 0; - if(state_xor & ControlMask) { - is_up = ((state & ControlMask) == 0); - adb_physical_key_update(0x36, is_up); - } - if(state_xor & LockMask) { - is_up = ((state & LockMask) == 0); - adb_physical_key_update(0x39, is_up); - } - if(state_xor & ShiftMask) { - is_up = ((state & ShiftMask) == 0); - adb_physical_key_update(0x38, is_up); - } - - kb_shift_control_state = state; - - - is_up = 0; - int a2code; - if (event.type == SDL_KEYUP) { - is_up = 1; - } - switch( event.key.keysym.sym ){ - case SDLK_F11: - printf("Toggle Fullscreen"); - if (!is_up) { - if (!IsFullScreen(window)) { - SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); - } else { - SDL_SetWindowFullscreen(window, 0); - SDL_SetWindowSize(window, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); - } - } - break; - default: - a2code = sdl_keysym_to_a2code(event.key.keysym.sym, is_up); - if(a2code >= 0) { - adb_physical_key_update(a2code, is_up); - } - break; - } -} - - -int -handle_sdl_mouse_motion_event(SDL_Event event) { - int x, y; - // @todo: FIX MOUSE BUTTON MAPPING, AT LEAST CLEAN UP AND DOCUMENT BEHAVIOR - //printf (" %04x\t", event.motion.state &7); - x = event.motion.x - BASE_MARGIN_LEFT; - y = event.motion.y - BASE_MARGIN_TOP; - if (event.type == SDL_MOUSEBUTTONUP) { - return update_mouse(x, y, 0 , event.motion.state &7 ); - } else { - return update_mouse(x, y, event.motion.state, event.motion.state &7 ); - } -} - - -void -x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) -{ - sdl_push_kimage(kimage_ptr, destx, desty, srcx, srcy, width, height); -} - - -// called by src/sim65816.c -void -x_dialog_create_gsport_conf(const char *str) -{ - // Just write the config file already... - config_write_config_gsport_file(); -} - - - - -// Old driver cruft - -// called by src/sim65816.c -int x_show_alert(int is_fatal, const char *str) { return 0; } - -void get_ximage(Kimage *kimage_ptr) { } -void x_toggle_status_lines() { } -void x_redraw_status_lines() { } -void x_hide_pointer(int do_hide) { } -void x_auto_repeat_on(int must) { } -void x_auto_repeat_off(int must) { } -void x_full_screen(int do_full) { } -// OG Adding release -void x_release_kimage(Kimage* kimage_ptr) { } -// OG Addding ratio -int x_calc_ratio(float x,float y) { return 1; } -// TODO: Add clipboard support -void clipboard_paste(void) { } -int clipboard_get_char(void) { return 0; } -void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { return; } -void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { } -void x_update_physical_colormap() { } -void show_xcolor_array() { } -void xdriver_end() { } -void x_push_done() { } +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 - 2012 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// This is an experimental video driver for the KEGS/GSport emulator. +// It requires SDL2 libraries to build. I've tested on Mac, but should +// be easy to port to other platforms. -DagenBrock + +// @todo: mouse clip bugs.. great western shootout. +// @todo: force refresh after screen mode change + +#include "SDL.h" +#include +#include +#include +#include +#include "defc.h" + +// BITMASKS +#define ShiftMask 1 +#define ControlMask 4 +#define LockMask 2 + +int g_use_shmem = 0; + +int g_num_check_input_calls = 0; +int g_check_input_flush_rate = 2; +int g_win_status_debug = 0; // Current visibility of status lines. +int g_win_status_debug_request = 0; // Desired visibility of status lines. +int g_screen_mdepth = 0; +int kb_shift_control_state = 0; + +extern int g_screen_depth; +extern int g_quit_sim_now; +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; +extern int g_lores_colors[]; +extern int g_a2vid_palette; +extern int g_installed_full_superhires_colormap; +extern char *g_status_ptrs[MAX_STATUS_LINES]; +extern word32 g_a2_screen_buffer_changed; +extern word32 g_full_refresh_needed; +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; +extern Kimage g_mainwin_kimage; + +SDL_Window *window; // Declare a pointer +SDL_Renderer *renderer; +SDL_Texture *texture; + +void dev_video_init_sdl(); +void handle_sdl_key_event(SDL_Event event); +void check_input_events_sdl(); +int handle_sdl_mouse_motion_event(SDL_Event event); + +int g_num_a2_keycodes = 0; +int a2_key_to_sdlkeycode[][3] = { + { 0x12, SDLK_1, 0}, + { 0x35, SDLK_ESCAPE,0 }, + { 0x7a, SDLK_F1, 0 }, + { 0x78, SDLK_F2, 0 }, + { 0x63, SDLK_F3, 0 }, + { 0x76, SDLK_F4, 0 }, + { 0x60, SDLK_F5, 0 }, + { 0x61, SDLK_F6, 0 }, + { 0x62, SDLK_F7, 0 }, + { 0x64, SDLK_F8, 0 }, + { 0x65, SDLK_F9, 0 }, + { 0x6d, SDLK_F10, 0 }, + { 0x67, SDLK_F11, 0 }, + { 0x6f, SDLK_F12, 0 }, + { 0x69, SDLK_F13, 0 }, + { 0x6b, SDLK_F14, 0 }, + { 0x71, SDLK_F15, 0 }, + { 0x7f, SDLK_PAUSE, 0 }, + { 0x32, '`', '~' }, /* Key number 18? */ + { 0x12, '1', '!' }, + { 0x13, '2', '@' }, + { 0x14, '3', '#' }, + { 0x15, '4', '$' }, + { 0x17, '5', '%' }, + { 0x16, '6', '^' }, + { 0x1a, '7', '&' }, + { 0x1c, '8', '*' }, + { 0x19, '9', '(' }, + { 0x1d, '0', ')' }, + { 0x1b, '-', '_' }, + { 0x18, '=', '+' }, + { 0x33, SDLK_BACKSPACE, 0 }, + { 0x72, SDLK_INSERT, 0 }, /* Help? XK_Help */ +/* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ + { 0x74, SDLK_PAGEUP, 0 }, + { 0x47, SDLK_NUMLOCKCLEAR, 0 }, /* Clear, XK_Clear */ + { 0x51, SDLK_KP_EQUALS, 0 }, /* Note XK_Home alias! XK_Home */ + { 0x4b, SDLK_KP_DIVIDE, 0 }, + { 0x43, SDLK_KP_MULTIPLY, 0 }, + { 0x30, SDLK_TAB, 0 }, + { 0x0c, 'q', 'Q' }, + { 0x0d, 'w', 'W' }, + { 0x0e, 'e', 'E' }, + { 0x0f, 'r', 'R' }, + { 0x11, 't', 'T' }, + { 0x10, 'y', 'Y' }, + { 0x20, 'u', 'U' }, + { 0x22, 'i', 'I' }, + { 0x1f, 'o', 'O' }, + { 0x23, 'p', 'P' }, + { 0x21, '[', '{' }, + { 0x1e, ']', '}' }, + { 0x2a, 0x5c, '|' }, /* backslash, bar */ + { 0x75, SDLK_DELETE, 0 }, + { 0x77, SDLK_END, 0 }, + { 0x79, SDLK_PAGEDOWN, 0 }, + { 0x59, SDLK_KP_7, 0 }, + { 0x5b, SDLK_KP_8, 0 }, + { 0x5c, SDLK_KP_9, 0 }, + { 0x4e, SDLK_KP_MINUS, 0 }, + { 0x39, SDLK_CAPSLOCK, 0 }, + { 0x00, 'a', 'A' }, + { 0x01, 's', 'S' }, + { 0x02, 'd', 'D' }, + { 0x03, 'f', 'F' }, + { 0x05, 'g', 'G' }, + { 0x04, 'h', 'H' }, + { 0x26, 'j', 'J' }, + { 0x28, 'k', 'K' }, + { 0x25, 'l', 'L' }, + { 0x29, ';', ':' }, + { 0x27, 0x27, '"' }, /* single quote */ + { 0x24, SDLK_RETURN, 0 }, + { 0x56, SDLK_KP_4, SDLK_LEFT}, + { 0x57, SDLK_KP_5, 0 }, + { 0x58, SDLK_KP_6, SDLK_RIGHT }, + { 0x45, SDLK_KP_PLUS, 0 }, + { 0x38, SDLK_LSHIFT, SDLK_RSHIFT }, + { 0x06, 'z', 'Z' }, + { 0x07, 'x', 'X' }, + { 0x08, 'c', 'C' }, + { 0x09, 'v', 'V' }, + { 0x0b, 'b', 'B' }, + { 0x2d, 'n', 'N' }, + { 0x2e, 'm', 'M' }, + { 0x2b, ',', '<' }, + { 0x2f, '.', '>' }, + { 0x2c, '/', '?' }, + { 0x3e, SDLK_UP, 0 }, + { 0x53, SDLK_KP_1, 0 }, + { 0x54, SDLK_KP_2, SDLK_DOWN }, + { 0x55, SDLK_KP_3, 0 }, + { 0x36, SDLK_RCTRL, SDLK_LCTRL }, + { 0x3a, SDLK_LALT, SDLK_RALT }, /* Option */ + { 0x37, SDLK_LGUI, SDLK_RGUI }, /* Command */ + { 0x31, ' ', 0 }, + { 0x3b, SDLK_LEFT, 0 }, + { 0x3d, SDLK_DOWN, 0 }, + { 0x3c, SDLK_RIGHT, 0 }, + { 0x52, SDLK_KP_0, 0 }, + { 0x41, SDLK_KP_PERIOD, 0 }, + { 0x4c, SDLK_KP_ENTER, 0 }, + { -1, -1, -1 } + +}; +int +main(int argc, char **argv) +{ + return gsportmain(argc, argv); +} + + + +/// Queries the Screen to see if it's set to Fullscreen or Not +/// @return SDL_FALSE if windowed, SDL_TRUE if fullscreen +SDL_bool IsFullScreen(SDL_Window *win) +{ + Uint32 flags = SDL_GetWindowFlags(win); + if (flags & SDL_WINDOW_FULLSCREEN) return SDL_TRUE; // return SDL_TRUE if fullscreen + return SDL_FALSE; // Return SDL_FALSE if windowed +} + + + + +void +dev_video_init() +{ + word32 lores_col; + + // build keycode map ?? + g_num_a2_keycodes = 0; + int i; + int keycode; + int tmp_array[0x80]; + for(i = 0; i <= 0x7f; i++) { + tmp_array[i] = 0; + } + for(i = 0; i < 0x7f; i++) { + keycode = a2_key_to_sdlkeycode[i][0]; + if(keycode < 0) { + g_num_a2_keycodes = i; + break; + } else if(keycode > 0x7f) { + printf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); + exit(2); + } else { + if(tmp_array[keycode]) { + printf("a2_key_to_x[%d] = %02x used by %d\n", + i, keycode, tmp_array[keycode] - 1); + } + tmp_array[keycode] = i + 1; + } + } + + // This actually creates our window + dev_video_init_sdl(); + + // @todo DANGER DANGER. HARD CODING THESE.. there was logic for stepping values in xdriver + g_screen_depth = 24; + g_screen_mdepth =32; + video_get_kimages(); + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,g_screen_mdepth); + + for(i = 0; i < 256; i++) { + //g_xcolor_a2vid_array[i].pixel = i; + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } +} + + + +// Initialize our SDL window and texture +void +dev_video_init_sdl() +{ + + SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2 + + // Create an application window with the following settings: + window = SDL_CreateWindow( + "GSPLUS V.0", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + BASE_WINDOW_WIDTH, // width, in pixels + X_A2_WINDOW_HEIGHT, // height, in pixels + SDL_WINDOW_OPENGL // flags - see below + ); + + // Check that the window was successfully created + if (window == NULL) { + // In the case that the window could not be made... + printf("Could not create window: %s\n", SDL_GetError()); + //@todo die, i guess + } else { + printf("SDL Window has been created\n"); + } + + renderer = SDL_CreateRenderer(window, -1, 0); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother. + // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); // make the scaled rendering look smoother. + SDL_RenderSetLogicalSize(renderer, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); + + texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); + // The window is open: could enter program loop here (see SDL_PollEvent()) + + SDL_ShowCursor(SDL_DISABLE); + +} + + +// Copy a rect to our SDL window +void sdl_push_kimage(Kimage *kimage_ptr, + int destx, int desty, int srcx, int srcy, int width, int height) +{ + byte *src_ptr; + int pixel_size = 4; + src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pixel_size; + //src_ptr = kimage_ptr->data_ptr; + + SDL_Rect dstrect; + dstrect.x = destx; + dstrect.y = desty; + dstrect.w = width; + dstrect.h = height; + int pitch = 640; + if (width < 560) { + pitch = EFF_BORDER_WIDTH; + // This is another bad hack. Possibly not cross platform. + pitch = BORDER_WIDTH+72; + //printf("EFF_BORDER_WIDTH : %d" ,EFF_BORDER_WIDTH); + } + //SDL_UpdateTexture(texture, NULL, src_ptr, 640 * sizeof (Uint32)); + SDL_UpdateTexture(texture, &dstrect, src_ptr, pitch*4 ); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + +} + + +void set_refresh_needed() { + g_a2_screen_buffer_changed = -1; + g_full_refresh_needed = -1; + + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_status_refresh_needed = 1; +} + + +void +x_get_kimage(Kimage *kimage_ptr) { + byte *data; + int width; + int height; + int depth; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + // this might be too big!!! I had it at depth/3 but it segfaults + data = malloc(width*height*(depth/4)); + kimage_ptr->data_ptr = data; +} + + +void +check_input_events() +{ + check_input_events_sdl(); +} + + +void +check_input_events_sdl() +{ + // @todo: make sure it's not queueing events / processing full queue each call + int motion = 0; + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch( event.type ){ + case SDL_KEYDOWN: + case SDL_KEYUP: + handle_sdl_key_event(event); + break; + case SDL_MOUSEMOTION: + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + motion |= handle_sdl_mouse_motion_event(event); + break; + case SDL_QUIT: + //quit = 1; /* SDL_QUIT event (window close) */ + SDL_DestroyWindow(window); + iwm_shut(); + // Clean up + SDL_Quit(); + my_exit(1); + break; + default: + break; + } + } +} + + +int +sdl_keysym_to_a2code(int keysym, int is_up) +{ + int i; + + if(keysym == 0) { + return -1; + } + + if((keysym == SDLK_LSHIFT) || (keysym == SDLK_RSHIFT)) { + if(is_up) { + kb_shift_control_state &= ~ShiftMask; + } else { + kb_shift_control_state |= ShiftMask; + } + } + if(keysym == SDLK_CAPSLOCK) { + if(is_up) { + kb_shift_control_state &= ~LockMask; + } else { + kb_shift_control_state |= LockMask; + } + } + if((keysym == SDLK_LCTRL) || (keysym == SDLK_RCTRL)) { + if(is_up) { + kb_shift_control_state &= ~ControlMask; + } else { + kb_shift_control_state |= ControlMask; + } + } + + /* Look up Apple 2 keycode */ + for(i = g_num_a2_keycodes - 1; i >= 0; i--) { + if((keysym == a2_key_to_sdlkeycode[i][1]) || + (keysym == a2_key_to_sdlkeycode[i][2])) { + return a2_key_to_sdlkeycode[i][0]; + } + } + + return -1; +} + + +void +handle_sdl_key_event(SDL_Event event) +{ + + int state_xor; + int state = 0; + int is_up; + + int mod = event.key.keysym.mod; + + // simulate xmask style here + // @todo: this can probably all be refactored now that X is gone + //state = state & (ControlMask | LockMask | ShiftMask); + + // when mod key is first press, comes as event, otherwise just a modifier + if( mod & KMOD_LCTRL || mod & KMOD_RCTRL || + event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL))) { + state = state | ControlMask; + } + if( (mod & KMOD_LSHIFT) || (mod & KMOD_RSHIFT) || + event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT))) { + state = state | ShiftMask; + } + if( mod & KMOD_CAPS) { + state = state | LockMask; + } + + state_xor = kb_shift_control_state ^ state; + is_up = 0; + if(state_xor & ControlMask) { + is_up = ((state & ControlMask) == 0); + adb_physical_key_update(0x36, is_up); + } + if(state_xor & LockMask) { + is_up = ((state & LockMask) == 0); + adb_physical_key_update(0x39, is_up); + } + if(state_xor & ShiftMask) { + is_up = ((state & ShiftMask) == 0); + adb_physical_key_update(0x38, is_up); + } + + kb_shift_control_state = state; + + + is_up = 0; + int a2code; + if (event.type == SDL_KEYUP) { + is_up = 1; + } + switch( event.key.keysym.sym ){ + case SDLK_F11: + printf("Toggle Fullscreen"); + if (!is_up) { + if (!IsFullScreen(window)) { + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + } else { + SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowSize(window, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); + } + } + break; + default: + a2code = sdl_keysym_to_a2code(event.key.keysym.sym, is_up); + if(a2code >= 0) { + adb_physical_key_update(a2code, is_up); + } + break; + } +} + + +int +handle_sdl_mouse_motion_event(SDL_Event event) { + int x, y; + // @todo: FIX MOUSE BUTTON MAPPING, AT LEAST CLEAN UP AND DOCUMENT BEHAVIOR + //printf (" %04x\t", event.motion.state &7); + x = event.motion.x - BASE_MARGIN_LEFT; + y = event.motion.y - BASE_MARGIN_TOP; + if (event.type == SDL_MOUSEBUTTONUP) { + return update_mouse(x, y, 0 , event.motion.state &7 ); + } else { + return update_mouse(x, y, event.motion.state, event.motion.state &7 ); + } +} + + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) +{ + sdl_push_kimage(kimage_ptr, destx, desty, srcx, srcy, width, height); +} + + +// called by src/sim65816.c +void +x_dialog_create_gsport_conf(const char *str) +{ + // Just write the config file already... + config_write_config_gsport_file(); +} + + + + +// Old driver cruft + +// called by src/sim65816.c +int x_show_alert(int is_fatal, const char *str) { return 0; } + +void get_ximage(Kimage *kimage_ptr) { } +void x_toggle_status_lines() { } +void x_redraw_status_lines() { } +void x_hide_pointer(int do_hide) { } +void x_auto_repeat_on(int must) { } +void x_auto_repeat_off(int must) { } +void x_full_screen(int do_full) { } +// OG Adding release +void x_release_kimage(Kimage* kimage_ptr) { } +// OG Addding ratio +int x_calc_ratio(float x,float y) { return 1; } +// TODO: Add clipboard support +void clipboard_paste(void) { } +int clipboard_get_char(void) { return 0; } +void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { return; } +void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { } +void x_update_physical_colormap() { } +void show_xcolor_array() { } +void xdriver_end() { } +void x_push_done() { } diff --git a/src/paddles.c b/src/paddles.c index 196fd35..005f5eb 100644 --- a/src/paddles.c +++ b/src/paddles.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/parallel.c b/src/parallel.c index fe506cf..9314b55 100644 --- a/src/parallel.c +++ b/src/parallel.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/partls.c b/src/partls.c index f719666..be1a532 100755 --- a/src/partls.c +++ b/src/partls.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/printer.cpp b/src/printer.cpp index 660b7a4..3194834 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -1,2120 +1,2120 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2011 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * Copyright (C) 2002-2004 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -//Modified for the KEGS emulator by Christopher G. Mason 02/2010 -//Added support for configuring the built in printer fonts - -#include "printer.h" -#include -#include "support.h" -//#include "png.h" -//#pragma comment( lib, "libpng.lib" ) -//#pragma comment (lib, "zdll.lib" ) - -static CPrinter* defaultPrinter = NULL; - -static FILE *textPrinterFile = NULL; -#ifdef WIN32 -const char* const textPrinterFileName = ".\\printer.txt"; -#else -const char* const textPrinterFileName = "./printer.txt"; -#endif - -#define PARAM16(I) (params[I+1]*256+params[I]) -#define PIXX ((Bitu)floor(curX*dpi+0.5)) -#define PIXY ((Bitu)floor(curY*dpi+0.5)) - -static Bitu printer_timout; -static bool timeout_dirty; -static const char* document_path; -extern "C" char* g_printer_font_roman; -extern "C" char* g_printer_font_sans; -extern "C" char* g_printer_font_courier; -extern "C" char* g_printer_font_prestige; -extern "C" char* g_printer_font_script; -extern "C" char* g_printer_font_ocra; -Bit8u paramc = '0'; - -#include "printer_charmaps.h" - -#ifdef HAVE_SDL -void CPrinter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal) -{ - float red=redmax/30.9; - float green=greenmax/30.9; - float blue=bluemax/30.9; - - Bit8u colormask=colorID<<=5; - - for(int i = 0; i < 32;i++) { - pal->colors[i+colormask].r=255-(red*(float)i); - pal->colors[i+colormask].g=255-(green*(float)i); - pal->colors[i+colormask].b=255-(blue*(float)i); - } -} -#endif // HAVE_SDL - -CPrinter::CPrinter(Bit16u dpi, Bit16u width, Bit16u height, char* output, bool multipageOutput) -{ -#ifdef HAVE_SDL - if (FT_Init_FreeType(&FTlib)) - { - page = NULL; - } - else - { - this->dpi = dpi; - this->output = output; - this->multipageOutput = multipageOutput; - - defaultPageWidth = (Real64)width/(Real64)10; - defaultPageHeight = (Real64)height/(Real64)10; - - // Create page - page = SDL_CreateRGBSurface( - SDL_SWSURFACE, - (Bitu)(defaultPageWidth*dpi), - (Bitu)(defaultPageHeight*dpi), - 8, - 0, - 0, - 0, - 0); - - // Set a grey palette - SDL_Palette* palette = page->format->palette; - - for (Bitu i=0; i<32; i++) - { - palette->colors[i].r =255; - palette->colors[i].g =255; - palette->colors[i].b =255; - } - // 0 = all white needed for logic 000 - FillPalette( 0, 0, 0, 1, palette); - // 1 = magenta* 001 - FillPalette( 0, 255, 0, 1, palette); - // 2 = cyan* 010 - FillPalette(255, 0, 0, 2, palette); - // 3 = "violet" 011 - FillPalette(255, 255, 0, 3, palette); - // 4 = yellow* 100 - FillPalette( 0, 0, 255, 4, palette); - // 5 = red 101 - FillPalette( 0, 255, 255, 5, palette); - // 6 = green 110 - FillPalette(255, 0, 255, 6, palette); - // 7 = black 111 - FillPalette(255, 255, 255, 7, palette); - - // yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max - // Printing colors on top of each other ORs them and gets the - // correct resulting color. - // i.e. magenta on blank page yyy=001 - // then yellow on magenta 001 | 100 = 101 = red - - color=COLOR_BLACK; - - curFont = NULL; - charRead = false; - autoFeed = false; - outputHandle = NULL; - - resetPrinter(); - - if (strcasecmp(output, "printer") == 0) - { -#if defined (WIN32) - // Show Print dialog to obtain a printer device context - - PRINTDLG pd; - pd.lStructSize = sizeof(PRINTDLG); - pd.hDevMode = (HANDLE) NULL; - pd.hDevNames = (HANDLE) NULL; - pd.Flags = PD_RETURNDC; - pd.hwndOwner = NULL; - pd.hDC = (HDC) NULL; - pd.nFromPage = 1; - pd.nToPage = 1; - pd.nMinPage = 0; - pd.nMaxPage = 0; - pd.nCopies = 1; - pd.hInstance = NULL; - pd.lCustData = 0L; - pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; - pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; - pd.lpPrintTemplateName = (LPCSTR) NULL; - pd.lpSetupTemplateName = (LPCSTR) NULL; - pd.hPrintTemplate = (HANDLE) NULL; - pd.hSetupTemplate = (HANDLE) NULL; - PrintDlg(&pd); - // TODO: what if user presses cancel? - printerDC = pd.hDC; -#endif // WIN32 - } - } -#endif // HAVE_SDL -#ifndef HAVE_SDL - this->output = output; - this->multipageOutput = multipageOutput; -#endif // !HAVE_SDL -}; - -void CPrinter::resetPrinterHard() -{ -#ifdef HAVE_SDL - charRead = false; - resetPrinter(); -#endif // HAVE_SDL -} - -void CPrinter::resetPrinter() -{ -#ifdef HAVE_SDL - color=COLOR_BLACK; - curX = curY = 0.0; - ESCSeen = false; - FSSeen = false; - ESCCmd = 0; - numParam = neededParam = 0; - topMargin = 0.0; - leftMargin = 0.0; - rightMargin = pageWidth = defaultPageWidth; - bottomMargin = pageHeight = defaultPageHeight; - lineSpacing = (Real64)1/6; - cpi = 10.0; - curCharTable = 1; - style = 0; - extraIntraSpace = 0.0; - printUpperContr = true; - bitGraph.remBytes = 0; - densk = 0; - densl = 1; - densy = 2; - densz = 3; - charTables[0] = 0; // Italics - charTables[1] = charTables[2] = charTables[3] = 437; - definedUnit = -1; - multipoint = false; - multiPointSize = 0.0; - multicpi = 0.0; - hmi = -1.0; - msb = 255; - numPrintAsChar = 0; - LQtypeFace = roman; - - selectCodepage(charTables[curCharTable]); - - updateFont(); - -#endif // HAVE_SDL - newPage(false,true); -#ifdef HAVE_SDL - - // Default tabs => Each eight characters - for (Bitu i=0;i<32;i++) - horiztabs[i] = i*8*(1/(Real64)cpi); - numHorizTabs = 32; - - numVertTabs = 255; -#endif // HAVE_SDL -} - - -CPrinter::~CPrinter(void) -{ -#ifdef HAVE_SDL - finishMultipage(); - if (page != NULL) - { - SDL_FreeSurface(page); - page = NULL; - FT_Done_FreeType(FTlib); - } -#if defined (WIN32) - DeleteDC(printerDC); -#endif -#endif // HAVE_SDL -}; - -#ifdef HAVE_SDL -void CPrinter::selectCodepage(Bit16u cp) -{ - Bit16u *mapToUse = NULL; - - switch(cp) - { - case 0: // Italics, use cp437 - case 437: - mapToUse = (Bit16u*)&cp437Map; - break; - case 737: - mapToUse = (Bit16u*)&cp737Map; - break; - case 775: - mapToUse = (Bit16u*)&cp775Map; - break; - case 850: - mapToUse = (Bit16u*)&cp850Map; - break; - case 852: - mapToUse = (Bit16u*)&cp852Map; - break; - case 855: - mapToUse = (Bit16u*)&cp855Map; - break; - case 857: - mapToUse = (Bit16u*)&cp857Map; - break; - case 860: - mapToUse = (Bit16u*)&cp860Map; - break; - case 861: - mapToUse = (Bit16u*)&cp861Map; - break; - case 863: - mapToUse = (Bit16u*)&cp863Map; - break; - case 864: - mapToUse = (Bit16u*)&cp864Map; - break; - case 865: - mapToUse = (Bit16u*)&cp865Map; - break; - case 866: - mapToUse = (Bit16u*)&cp866Map; - break; - default: - //LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp); - mapToUse = (Bit16u*)&cp437Map; - } - - for (int i=0; i<256; i++) - curMap[i] = mapToUse[i]; -} -#endif // HAVE_SDL - -#ifdef HAVE_SDL -void CPrinter::updateFont() -{ - // char buffer[1000]; - if (curFont != NULL) - FT_Done_Face(curFont); - - char* fontName; - - switch (LQtypeFace) - { - case roman: - fontName = g_printer_font_roman; - break; - case sansserif: - fontName = g_printer_font_sans; - break; - case courier: - fontName = g_printer_font_courier; - break; - case prestige: - fontName = g_printer_font_prestige; - break; - case script: - fontName = g_printer_font_script; - break; - case ocra: - case ocrb: - fontName = g_printer_font_ocra; - break; - default: - fontName = g_printer_font_roman; - } - - if (FT_New_Face(FTlib, fontName, 0, &curFont)) - { - - printf("Unable to load font\n"); - //LOG_MSG("Unable to load font %s", fontName); - curFont = NULL; - } - - Real64 horizPoints = 10.5; - Real64 vertPoints = 10.5; - - if (!multipoint) { - actcpi = cpi; - /* - switch(style & (STYLE_CONDENSED|STYLE_PROP)) { - case STYLE_CONDENSED: // only condensed - if (cpi == 10.0) { - actcpi = 17.14; - horizPoints *= 10.0/17.14; - } else if(cpi == 12.0) { - actcpi = 20.0; - horizPoints *= 10.0/20.0; - vertPoints *= 10.0/12.0; - } else { - // ignored - } - break; - case STYLE_PROP|STYLE_CONDENSED: - horizPoints /= 2.0; - break; - case 0: // neither - case STYLE_PROP: // only proportional - horizPoints *= 10.0/cpi; - vertPoints *= 10.0/cpi; - break; - } - */ - if (!(style & STYLE_CONDENSED)) { - horizPoints *= 10.0/cpi; - vertPoints *= 10.0/cpi; - } - - if (!(style & STYLE_PROP)) { - if ((cpi == 10.0) && (style & STYLE_CONDENSED)) { - actcpi = 17.14; - horizPoints *= 10.0/17.14; - } - if ((cpi == 12.0) && (style & STYLE_CONDENSED)) { - actcpi = 20.0; - horizPoints *= 10.0/20.0; - vertPoints *= 10.0/12.0; - } - } else if (style & STYLE_CONDENSED) horizPoints /= 2.0; - - - if ((style & STYLE_DOUBLEWIDTH) || (style & STYLE_DOUBLEWIDTHONELINE)) { - actcpi /= 2.0; - horizPoints *= 2.0; - } - - if (style & STYLE_DOUBLEHEIGHT) vertPoints *= 2.0; - } else { // multipoint true - actcpi = multicpi; - horizPoints = vertPoints = multiPointSize; - } - - if ((style & STYLE_SUPERSCRIPT) || (style & STYLE_SUBSCRIPT)) { - horizPoints *= 2.0/3.0; - vertPoints *= 2.0/3.0; - actcpi /= 2.0/3.0; - } - - FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi); - - if (style & STYLE_ITALICS || charTables[curCharTable] == 0) - { - FT_Matrix matrix; - matrix.xx = 0x10000L; - matrix.xy = (FT_Fixed)(0.20 * 0x10000L); - matrix.yx = 0; - matrix.yy = 0x10000L; - FT_Set_Transform(curFont, &matrix, 0); - } -} -#endif // HAVE_SDL - -#ifdef HAVE_SDL -bool CPrinter::processCommandChar(Bit8u ch) -{ - if (ESCSeen || FSSeen) - { - ESCCmd = ch; - if(FSSeen) ESCCmd |= 0x800; - ESCSeen = FSSeen = false; - numParam = 0; - - switch (ESCCmd) { - case 0x02: // Undocumented - case 0x0a: // Reverse line feed (ESC LF) - case 0x0c: // Return to top of current page (ESC FF) - case 0x0e: // Select double-width printing (one line) (ESC SO) - case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x31: // Select 7/60-inch line spacing (ESC 1) - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper control codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x38: // Disable paper-out detector (ESC 8) - case 0x39: // Enable paper-out detector (ESC 9) - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin [conflict] (ESC O) - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character (ESC ^) - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - - case 0x834: // Select italic font (FS 4) (= ESC 4) - case 0x835: // Cancel italic font (FS 5) (= ESC 5) - case 0x846: // Select forward feed mode (FS F) - case 0x852: // Select reverse feed mode (FS R) - neededParam = 0; - break; - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing (ESC A) - case 0x43: // Set page length in lines (ESC C) - case 0x49: // Select character type and print pitch (ESC I) - case 0x4a: // Advance print position vertically (ESC J) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an international character set (ESC R) - case 0x53: // Select superscript/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - //case 0x56: // Repeat data (ESC V) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x66: // Absolute horizontal tab in columns [conflict] (ESC f) - case 0x68: // Select double or quadruple size (ESC h) - case 0x69: // Immediate print (ESC i) - case 0x6a: // Reverse paper feed (ESC j) - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x73: // Low-speed mode on/off (ESC s) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) - - case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) - case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) - case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) - case 0x843: // Select LQ type style (FS C) (= ESC k) - case 0x845: // Select character width (FS E) - case 0x849: // Select character table (FS I) (= ESC t) - case 0x853: // Select High Speed/High Density elite pitch (FS S) - case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) - neededParam = 1; - break; - case 0x24: // Set absolute horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set relative horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) [conflict] (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) - case 0x85a: // Print 24-bit hex-density graphics (FS Z) - neededParam = 2; - break; - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point [conflict] (ESC X) - neededParam = 3; - break; - case 0x5b: // Select character height, width, line spacing - neededParam = 7; - break; - case 0x62: // Set vertical tabs in VFU channels (ESC b) - case 0x42: // Set vertical tabs (ESC B) - numVertTabs = 0; - return true; - case 0x44: // Set horizontal tabs (ESC D) - numHorizTabs = 0; - return true; - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) - //LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!"); - return true; - case 0x28: // Two bytes sequence - return true; - default: - /*LOG_MSG("PRINTER: Unknown command %c (%02Xh) %c , unable to skip parameters.", - (ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd);*/ - - neededParam = 0; - ESCCmd = 0; - return true; - } - - if (neededParam > 0) - return true; - } - - // Two bytes sequence - if (ESCCmd == '(') - { - ESCCmd = 0x200 + ch; - - switch (ESCCmd) - { - case 0x242: // Bar code setup and print (ESC (B) - case 0x25e: // Print data as characters (ESC (^) - neededParam = 2; - break; - case 0x255: // Set unit (ESC (U) - neededParam = 3; - break; - case 0x243: // Set page length in defined unit (ESC (C) - case 0x256: // Set absolute vertical print position (ESC (V) - case 0x276: // Set relative vertical print position (ESC (v) - neededParam = 4; - break; - case 0x274: // Assign character table (ESC (t) - case 0x22d: // Select line/score (ESC (-) - neededParam = 5; - break; - case 0x263: // Set page format (ESC (c) - neededParam = 6; - break; - default: - // ESC ( commands are always followed by a "number of parameters" word parameter - //LOG(LOG_MISC,LOG_ERROR) - printf("PRINTER: Skipping unsupported command ESC ( %c (%02X).", ESCCmd, ESCCmd); - neededParam = 2; - ESCCmd = 0x101; - return true; - } - - if (neededParam > 0) - return true; - } - - // Ignore VFU channel setting - if (ESCCmd == 0x62) { - ESCCmd = 0x42; - return true; - } - - // Collect vertical tabs - if (ESCCmd == 0x42) { - if (ch == 0 || (numVertTabs>0 && verttabs[numVertTabs-1] > (Real64)ch*lineSpacing)) // Done - ESCCmd = 0; - else - if (numVertTabs < 16) - verttabs[numVertTabs++] = (Real64)ch*lineSpacing; - } - - // Collect horizontal tabs - if (ESCCmd == 0x44) - { - if (ch == 0 || (numHorizTabs>0 && horiztabs[numHorizTabs-1] > (Real64)ch*(1/(Real64)cpi))) // Done - ESCCmd = 0; - else - if (numHorizTabs < 32) - horiztabs[numHorizTabs++] = (Real64)ch*(1/(Real64)cpi); - } - - if (numParam < neededParam) - { - params[numParam++] = ch; - - if (numParam < neededParam) - return true; - } - - if (ESCCmd != 0) - { - switch (ESCCmd) - { - case 0x02: // Undocumented - // Ignore - break; - case 0x0e: // Select double-width printing (one line) (ESC SO) - if (!multipoint) - { - hmi = -1; - style |= STYLE_DOUBLEWIDTHONELINE; - updateFont(); - } - break; - case 0x0f: // Select condensed printing (ESC SI) - if (!multipoint && (cpi!=15.0)) { - hmi = -1; - style |= STYLE_CONDENSED; - updateFont(); - } - break; - case 0x19: // Control paper loading/ejecting (ESC EM) - // We are not really loading paper, so most commands can be ignored - if (params[0] == 'R') - newPage(true,false); // TODO resetx? - break; - case 0x20: // Set intercharacter space (ESC SP) - if (!multipoint) - { - extraIntraSpace = (Real64)params[0] / (printQuality==QUALITY_DRAFT?120:180); - hmi = -1; - updateFont(); - } - break; - case 0x21: // Master select (ESC !) - cpi = params[0] & 0x01 ? 12:10; - - // Reset first seven bits - style &= 0xFF80; - if (params[0] & 0x02) - style |= STYLE_PROP; - if (params[0] & 0x04) - style |= STYLE_CONDENSED; - if (params[0] & 0x08) - style |= STYLE_BOLD; - if (params[0] & 0x10) - style |= STYLE_DOUBLESTRIKE; - if (params[0] & 0x20) - style |= STYLE_DOUBLEWIDTH; - if (params[0] & 0x40) - style |= STYLE_ITALICS; - if (params[0] & 0x80) - { - score = SCORE_SINGLE; - style |= STYLE_UNDERLINE; - } - - hmi = -1; - multipoint = false; - updateFont(); - break; - case 0x23: // Cancel MSB control (ESC #) - msb = 255; - break; - case 0x24: // Set absolute horizontal print position (ESC $) - { - Real64 unitSize = definedUnit; - if (unitSize < 0) - unitSize = (Real64)60.0; - - Real64 newX = leftMargin + ((Real64)PARAM16(0)/unitSize); - if (newX <= rightMargin) - curX = newX; - } - break; - case 0x85a: // Print 24-bit hex-density graphics (FS Z) - setupBitImage(40, PARAM16(0)); - break; - case 0x2a: // Select bit image (ESC *) - setupBitImage(params[0], PARAM16(1)); - break; - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x833: // Set n/360-inch line spacing (FS 3) - lineSpacing = (Real64)params[0]/360; - break; - case 0x2d: // Turn underline on/off (ESC -) - if (params[0] == 0 || params[0] == 48) - style &= ~STYLE_UNDERLINE; - if (params[0] == 1 || params[0] == 49) - { - style |= STYLE_UNDERLINE; - score = SCORE_SINGLE; - } - updateFont(); - break; - case 0x2f: // Select vertical tab channel (ESC /) - // Ignore - break; - case 0x30: // Select 1/8-inch line spacing (ESC 0) - lineSpacing = (Real64)1/8; - break; - case 0x32: // Select 1/6-inch line spacing (ESC 2) - lineSpacing = (Real64)1/6; - break; - case 0x33: // Set n/180-inch line spacing (ESC 3) - lineSpacing = (Real64)params[0]/180; - break; - case 0x34: // Select italic font (ESC 4) - style |= STYLE_ITALICS; - updateFont(); - break; - case 0x35: // Cancel italic font (ESC 5) - style &= ~STYLE_ITALICS; - updateFont(); - break; - case 0x36: // Enable printing of upper control codes (ESC 6) - printUpperContr = true; - break; - case 0x37: // Enable upper control codes (ESC 7) - printUpperContr = false; - break; - case 0x3c: // Unidirectional mode (one line) (ESC <) - // We don't have a print head, so just ignore this - break; - case 0x3d: // Set MSB to 0 (ESC =) - msb = 0; - break; - case 0x3e: // Set MSB to 1 (ESC >) - msb = 1; - break; - case 0x3f: // Reassign bit-image mode (ESC ?) - if (params[0] == 75) - densk = params[1]; - if (params[0] == 76) - densl = params[1]; - if (params[0] == 89) - densy = params[1]; - if (params[0] == 90) - densz = params[1]; - break; - case 0x40: // Initialize printer (ESC @) - resetPrinter(); - break; - case 0x41: // Set n/60-inch line spacing - case 0x841: - lineSpacing = (Real64)params[0]/60; - break; - case 0x43: // Set page length in lines (ESC C) - if (params[0] != 0) - pageHeight = bottomMargin = (Real64)params[0] * lineSpacing; - else // == 0 => Set page length in inches - { - neededParam = 1; - numParam = 0; - ESCCmd = 0x100; - return true; - } - break; - case 0x45: // Select bold font (ESC E) - style |= STYLE_BOLD; - updateFont(); - break; - case 0x46: // Cancel bold font (ESC F) - style &= ~STYLE_BOLD; - updateFont(); - break; - case 0x47: // Select dobule-strike printing (ESC G) - style |= STYLE_DOUBLESTRIKE; - break; - case 0x48: // Cancel double-strike printing (ESC H) - style &= ~STYLE_DOUBLESTRIKE; - break; - case 0x4a: // Advance print position vertically (ESC J n) - curY += (Real64)((Real64)params[0] / 180); - if (curY > bottomMargin) - newPage(true,false); - break; - case 0x4b: // Select 60-dpi graphics (ESC K) - setupBitImage(densk, PARAM16(0)); - break; - case 0x4c: // Select 120-dpi graphics (ESC L) - setupBitImage(densl, PARAM16(0)); - break; - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - cpi = 12; - hmi = -1; - multipoint = false; - updateFont(); - break; - case 0x4e: // Set bottom margin (ESC N) - topMargin = 0.0; - bottomMargin = (Real64)params[0] * lineSpacing; - break; - case 0x4f: // Cancel bottom (and top) margin - topMargin = 0.0; - bottomMargin = pageHeight; - break; - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - cpi = 10; - hmi = -1; - multipoint = false; - updateFont(); - break; - case 0x51: // Set right margin - rightMargin = (Real64)(params[0]-1.0) / (Real64)cpi; - break; - case 0x52: // Select an international character set (ESC R) - if (params[0] <= 13 || params[0] == 64) - { - if (params[0] == 64) - params[0] = 14; - - curMap[0x23] = intCharSets[params[0]][0]; - curMap[0x24] = intCharSets[params[0]][1]; - curMap[0x40] = intCharSets[params[0]][2]; - curMap[0x5b] = intCharSets[params[0]][3]; - curMap[0x5c] = intCharSets[params[0]][4]; - curMap[0x5d] = intCharSets[params[0]][5]; - curMap[0x5e] = intCharSets[params[0]][6]; - curMap[0x60] = intCharSets[params[0]][7]; - curMap[0x7b] = intCharSets[params[0]][8]; - curMap[0x7c] = intCharSets[params[0]][9]; - curMap[0x7d] = intCharSets[params[0]][10]; - curMap[0x7e] = intCharSets[params[0]][11]; - } - break; - case 0x53: // Select superscript/subscript printing (ESC S) - if (params[0] == 0 || params[0] == 48) - style |= STYLE_SUBSCRIPT; - if (params[0] == 1 || params[1] == 49) - style |= STYLE_SUPERSCRIPT; - updateFont(); - break; - case 0x54: // Cancel superscript/subscript printing (ESC T) - style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; - updateFont(); - break; - case 0x55: // Turn unidirectional mode on/off (ESC U) - // We don't have a print head, so just ignore this - break; - case 0x57: // Turn double-width printing on/off (ESC W) - if (!multipoint) - { - hmi = -1; - if (params[0] == 0 || params[0] == 48) - style &= ~STYLE_DOUBLEWIDTH; - if (params[0] == 1 || params[0] == 49) - style |= STYLE_DOUBLEWIDTH; - updateFont(); - } - break; - case 0x58: // Select font by pitch and point (ESC X) - multipoint = true; - // Copy currently non-multipoint CPI if no value was set so far - if (multicpi == 0) - multicpi = cpi; - if (params[0] > 0) // Set CPI - { - if (params[0] == 1) // Proportional spacing - style |= STYLE_PROP; - else if (params[0] >= 5) - multicpi = (Real64)360 / (Real64)params[0]; - } - if (multiPointSize == 0) - multiPointSize = (Real64)10.5; - if (PARAM16(1) > 0) // Set points - multiPointSize = ((Real64)PARAM16(1)) / 2; - updateFont(); - break; - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - setupBitImage(densy, PARAM16(0)); - break; - case 0x5a: // Select 240-dpi graphics (ESC Z) - setupBitImage(densz, PARAM16(0)); - break; - case 0x5c: // Set relative horizontal print position (ESC \) - { - Bit16s toMove = PARAM16(0); - Real64 unitSize = definedUnit; - if (unitSize < 0) - unitSize = (Real64)(printQuality==QUALITY_DRAFT?120.0:180.0); - curX += (Real64)((Real64)toMove / unitSize); - } - break; - case 0x61: // Select justification (ESC a) - // Ignore - break; - case 0x63: // Set horizontal motion index (HMI) (ESC c) - hmi = (Real64)PARAM16(0) / (Real64)360.0; - extraIntraSpace = 0.0; - break; - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - cpi = 15; - hmi = -1; - multipoint = false; - updateFont(); - break; - case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet - if(lineSpacing < 0) lineSpacing *= -1; - break; - case 0x6a: // Reverse paper feed (ESC j) - { - Real64 reverse = (Real64)PARAM16(0) / (Real64)216.0; - reverse = curY - reverse; - if(reverse < leftMargin) curY = leftMargin; - else curY = reverse; - break; - } - case 0x6b: // Select typeface (ESC k) - paramc = params[0]-'0'; - //if (params[0] <= 11 || params[0] == 30 || params[0] == 31) - if (paramc <= 11 || paramc == 30 || paramc == 31) - LQtypeFace = (Typeface)paramc; - updateFont(); - break; - case 0x6c: // Set left margin (ESC l) - leftMargin = (Real64)(params[0]-1.0) / (Real64)cpi; - if (curX < leftMargin) - curX = leftMargin; - break; - case 0x70: // Turn proportional mode on/off (ESC p) - if (params[0] == 0 || params[0] == 48) - style &= (0xffff - STYLE_PROP); - if (params[0] == 1 || params[0] == 49) - { - style |= STYLE_PROP; - printQuality = QUALITY_LQ; - } - multipoint = false; - hmi = -1; - updateFont(); - break; - case 0x72: // Select printing color (ESC r) - - if(params[0]==0 || params[0] > 6) color = COLOR_BLACK; - else color = params[0]<<5; - break; - case 0x73: // Select low-speed mode (ESC s) - // Ignore - break; - case 0x74: // Select character table (ESC t) - case 0x849: // Select character table (FS I) - if (params[0] < 4) - curCharTable = params[0]; - if (params[0] >= 48 && params[0] <= 51) - curCharTable = params[0] - 48; - selectCodepage(charTables[curCharTable]); - updateFont(); - break; - case 0x77: // Turn double-height printing on/off (ESC w) - if (!multipoint) - { - if (params[0] == 0 || params[0] == 48) - style &= ~STYLE_DOUBLEHEIGHT; - if (params[0] == 1 || params[0] == 49) - style |= STYLE_DOUBLEHEIGHT; - updateFont(); - } - break; - case 0x78: // Select LQ or draft (ESC x) - if (params[0] == 0 || params[0] == 48) { - printQuality = QUALITY_DRAFT; - style |= STYLE_CONDENSED; - } - if (params[0] == 1 || params[0] == 49) { - printQuality = QUALITY_LQ; - style &= ~STYLE_CONDENSED; - } - hmi = -1; - updateFont(); - break; - case 0x100: // Set page length in inches (ESC C NUL) - pageHeight = (Real64)params[0]; - bottomMargin = pageHeight; - topMargin = 0.0; - break; - case 0x101: // Skip unsupported ESC ( command - neededParam = PARAM16(0); - numParam = 0; - break; - case 0x274: // Assign character table (ESC (t) - if (params[2] < 4 && params[3] < 16) - { - charTables[params[2]] = codepages[params[3]]; - //LOG_MSG("curr table: %d, p2: %d, p3: %d",curCharTable,params[2],params[3]); - if (params[2] == curCharTable) - selectCodepage(charTables[curCharTable]); - } - break; - case 0x22d: // Select line/score (ESC (-) - style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); - score = params[4]; - if (score) - { - if (params[3] == 1) - style |= STYLE_UNDERLINE; - if (params[3] == 2) - style |= STYLE_STRIKETHROUGH; - if (params[3] == 3) - style |= STYLE_OVERSCORE; - } - updateFont(); - break; - case 0x242: // Bar code setup and print (ESC (B) - //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Bardcode printing not supported"); - // Find out how many bytes to skip - neededParam = PARAM16(0); - numParam = 0; - break; - case 0x243: // Set page length in defined unit (ESC (C) - if (params[0] != 0 && definedUnit > 0) - { - pageHeight = bottomMargin = ((Real64)PARAM16(2)) * definedUnit; - topMargin = 0.0; - } - break; - case 0x255: // Set unit (ESC (U) - definedUnit = (Real64)params[2] / (Real64)3600; - break; - case 0x256: // Set absolute vertical print position (ESC (V) - { - Real64 unitSize = definedUnit; - if (unitSize < 0) - unitSize = (Real64)360.0; - Real64 newPos = topMargin + (((Real64)PARAM16(2)) * unitSize); - if (newPos > bottomMargin) - newPage(true,false); - else - curY = newPos; - } - break; - case 0x25e: // Print data as characters (ESC (^) - numPrintAsChar = PARAM16(0); - break; - case 0x263: // Set page format (ESC (c) - if (definedUnit > 0) - { - Real64 newTop, newBottom; - newTop = ((Real64)PARAM16(2)) * definedUnit; - newBottom = ((Real64)PARAM16(4)) * definedUnit; - if(newTop >= newBottom) break; - if(newTop < pageHeight) topMargin = newTop; - if(newBottom < pageHeight) bottomMargin = newBottom; - if(topMargin > curY) curY = topMargin; - //LOG_MSG("du %d, p1 %d, p2 %d, newtop %f, newbott %f, nt %f, nb %f, ph %f", - // (Bitu)definedUnit,PARAM16(2),PARAM16(4),topMargin,bottomMargin, - // newTop,newBottom,pageHeight); - } - break; - case 0x276: // Set relative vertical print position (ESC (v) - { - Real64 unitSize = definedUnit; - if (unitSize < 0) - unitSize = (Real64)360.0; - Real64 newPos = curY + ((Real64)((Bit16s)PARAM16(2)) * unitSize); - if (newPos > topMargin) - { - if (newPos > bottomMargin) - newPage(true,false); - else - curY = newPos; - } - } - break; - default: - if (ESCCmd < 0x100); - //LOG(LOG_MISC,LOG_WARN) - //LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd); - else; - //LOG(LOG_MISC,LOG_WARN) - //LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200); - } - - ESCCmd = 0; - return true; - } - - switch (ch) - { - case 0x00: // NUL is ignored by the printer - return true; - case 0x07: // Beeper (BEL) - // BEEEP! - return true; - case 0x08: // Backspace (BS) - { - Real64 newX = curX - (1/(Real64)actcpi); - if (hmi > 0) - newX = curX - hmi; - if (newX >= leftMargin) - curX = newX; - } - return true; - case 0x09: // Tab horizontally (HT) - { - // Find tab right to current pos - Real64 moveTo = -1; - for (Bit8u i=0; i curX) - moveTo = horiztabs[i]; - // Nothing found => Ignore - if (moveTo > 0 && moveTo < rightMargin) - curX = moveTo; - } - return true; - case 0x0b: // Tab vertically (VT) - if (numVertTabs == 0) // All tabs cancelled => Act like CR - curX = leftMargin; - else if (numVertTabs == 255) // No tabs set since reset => Act like LF - { - curX = leftMargin; - curY += lineSpacing; - if (curY > bottomMargin) - newPage(true,false); - } - else - { - // Find tab below current pos - Real64 moveTo = -1; - for (Bit8u i=0; i curY) - moveTo = verttabs[i]; - - // Nothing found => Act like FF - if (moveTo > bottomMargin || moveTo < 0) - newPage(true,false); - else - curY = moveTo; - } - if (style & STYLE_DOUBLEWIDTHONELINE) - { - style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; - updateFont(); - } - return true; - case 0x0c: // Form feed (FF) - if (style & STYLE_DOUBLEWIDTHONELINE) - { - style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; - updateFont(); - } - newPage(true,true); - return true; - case 0x0d: // Carriage Return (CR) - curX = leftMargin; - if (!autoFeed) - return true; - case 0x0a: // Line feed - if (style & STYLE_DOUBLEWIDTHONELINE) - { - style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; - updateFont(); - } - curX = leftMargin; - curY += lineSpacing; - if (curY > bottomMargin) - newPage(true,false); - return true; - case 0x0e: //Select Real64-width printing (one line) (SO) - if (!multipoint) - { - hmi = -1; - style |= STYLE_DOUBLEWIDTHONELINE; - updateFont(); - } - return true; - case 0x0f: // Select condensed printing (SI) - if (!multipoint && (cpi!=15.0)) { - hmi = -1; - style |= STYLE_CONDENSED; - updateFont(); - } - return true; - case 0x11: // Select printer (DC1) - // Ignore - return true; - case 0x12: // Cancel condensed printing (DC2) - hmi = -1; - style &= ~STYLE_CONDENSED; - updateFont(); - return true; - case 0x13: // Deselect printer (DC3) - // Ignore - return true; - case 0x14: // Cancel double-width printing (one line) (DC4) - hmi = -1; - style &= ~STYLE_DOUBLEWIDTHONELINE; - updateFont(); - return true; - case 0x18: // Cancel line (CAN) - return true; - case 0x1b: // ESC - ESCSeen = true; - return true; - case 0x1c: // FS (IBM commands) - FSSeen = true; - return true; - default: - return false; - } - - return false; -} -#endif // HAVE_SDL - -//static void PRINTER_EventHandler(Bitu param); - -void CPrinter::newPage(bool save, bool resetx) -{ - //PIC_RemoveEvents(PRINTER_EventHandler); - if(printer_timout) timeout_dirty=false; - -#ifdef HAVE_SDL - if (save) - outputPage(); - - if(resetx) curX=leftMargin; - curY = topMargin; - - SDL_Rect rect; - rect.x = 0; - rect.y = 0; - rect.w = page->w; - rect.h = page->h; - SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255)); - - /*for(int i = 0; i < 256; i++) - { - *((Bit8u*)page->pixels+i)=i; - }*/ -#endif // HAVE_SDL - if (strcasecmp(output, "text") == 0) { /* Text file */ - if (textPrinterFile) { - fclose(textPrinterFile); - textPrinterFile = NULL; - } - } -} - -void CPrinter::printChar(Bit8u ch) -{ -#ifdef HAVE_SDL - - charRead = true; - if (page == NULL) return; -#endif // HAVE_SDL - // Don't think that DOS programs uses this but well: Apply MSB if desired - if (msb != 255) { - if (msb == 0) ch &= 0x7F; - if (msb == 1) ch |= 0x80; - } - if (strcasecmp(output, "text") == 0) { - if (!textPrinterFile) { - textPrinterFile = fopen(textPrinterFileName,"ab"); - } - fprintf(textPrinterFile,"%c",ch); - fflush(textPrinterFile); - return; - } -#ifdef HAVE_SDL - - // Are we currently printing a bit graphic? - if (bitGraph.remBytes > 0) { - printBitGraph(ch); - return; - } - - // Print everything? - if (numPrintAsChar > 0) numPrintAsChar--; - else if (processCommandChar(ch)) return; - - // Do not print if no font is available - if (!curFont) return; - if(ch==0x1) ch=0x20; - - // Find the glyph for the char to render - FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]); - - // Load the glyph - FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT); - - // Render a high-quality bitmap - FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL); - - Bit16u penX = PIXX + curFont->glyph->bitmap_left; - Bit16u penY = PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender/64; - - if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2; - - // Copy bitmap into page - SDL_LockSurface(page); - - blitGlyph(curFont->glyph->bitmap, penX, penY, false); - blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); - - // Doublestrike => Print the glyph a second time one pixel below - if (style & STYLE_DOUBLESTRIKE) { - blitGlyph(curFont->glyph->bitmap, penX, penY+1, true); - blitGlyph(curFont->glyph->bitmap, penX+1, penY+1, true); - } - - // Bold => Print the glyph a second time one pixel to the right - // or be a bit more bold... - if (style & STYLE_BOLD) { - blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); - blitGlyph(curFont->glyph->bitmap, penX+2, penY, true); - blitGlyph(curFont->glyph->bitmap, penX+3, penY, true); - } - SDL_UnlockSurface(page); - - // For line printing - Bit16u lineStart = PIXX; - - // advance the cursor to the right - Real64 x_advance; - if (style & STYLE_PROP) - x_advance = (Real64)((Real64)(curFont->glyph->advance.x)/(Real64)(dpi*64)); - else { - if (hmi < 0) x_advance = 1/(Real64)actcpi; - else x_advance = hmi; - } - x_advance += extraIntraSpace; - curX += x_advance; - - // Draw lines if desired - if ((score != SCORE_NONE) && (style & - (STYLE_UNDERLINE|STYLE_STRIKETHROUGH|STYLE_OVERSCORE))) - { - // Find out where to put the line - Bit16u lineY = PIXY; - double height = (curFont->size->metrics.height>>6); // TODO height is fixed point madness... - - if (style & STYLE_UNDERLINE) lineY = PIXY + (Bit16u)(height*0.9); - else if (style & STYLE_STRIKETHROUGH) lineY = PIXY + (Bit16u)(height*0.45); - else if (style & STYLE_OVERSCORE) - lineY = PIXY - (((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN))?5:0); - - drawLine(lineStart, PIXX, lineY, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); - - // draw second line if needed - if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN)) - drawLine(lineStart, PIXX, lineY + 5, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); - } - // If the next character would go beyond the right margin, line-wrap. - if((curX + x_advance) > rightMargin) { - curX = leftMargin; - curY += lineSpacing; - if (curY > bottomMargin) newPage(true,false); - } -#endif // HAVE_SDL -} - -#ifdef HAVE_SDL -void CPrinter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) { - for (Bitu y=0; y 0 && (destx+x < page->w) && (desty+y < page->h) ) { - Bit8u* target = (Bit8u*)page->pixels + (x+destx) + (y+desty)*page->pitch; - source>>=3; - - if (add) { - if (((*target)&0x1f )+ source > 31) *target |= (color|0x1f); - else { - *target += source; - *target |= color; - } - } - else *target = source|color; - } - } - } -} - -void CPrinter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken) -{ - SDL_LockSurface(page); - - Bitu breakmod = dpi / 15; - Bitu gapstart = (breakmod * 4)/5; - - // Draw anti-aliased line - for (Bitu x=fromx; x<=tox; x++) - { - // Skip parts if broken line or going over the border - if ((!broken || (x%breakmod <= gapstart)) && (x < page->w)) - { - if (y > 0 && (y-1) < page->h) - *((Bit8u*)page->pixels + x + (y-1)*page->pitch) = 240; - if (y < page->h) - *((Bit8u*)page->pixels + x + y*page->pitch) = !broken?255:240; - if (y+1 < page->h) - *((Bit8u*)page->pixels + x + (y+1)*page->pitch) = 240; - } - } - SDL_UnlockSurface(page); -} - -void CPrinter::setAutofeed(bool feed) { - autoFeed = feed; -} - -bool CPrinter::getAutofeed() { - return autoFeed; -} - -bool CPrinter::isBusy() { - // We're never busy - return false; -} - -bool CPrinter::ack() { - // Acknowledge last char read - if(charRead) { - charRead=false; - return true; - } - return false; -} - -void CPrinter::setupBitImage(Bit8u dens, Bit16u numCols) { - switch (dens) - { - case 0: - bitGraph.horizDens = 60; - bitGraph.vertDens = 60; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 1: - bitGraph.horizDens = 120; - bitGraph.vertDens = 60; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 2: - bitGraph.horizDens = 120; - bitGraph.vertDens = 60; - bitGraph.adjacent = false; - bitGraph.bytesColumn = 1; - break; - case 3: - bitGraph.horizDens = 60; - bitGraph.vertDens = 240; - bitGraph.adjacent = false; - bitGraph.bytesColumn = 1; - break; - case 4: - bitGraph.horizDens = 80; - bitGraph.vertDens = 60; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 6: - bitGraph.horizDens = 90; - bitGraph.vertDens = 60; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 1; - break; - case 32: - bitGraph.horizDens = 60; - bitGraph.vertDens = 180; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 33: - bitGraph.horizDens = 120; - bitGraph.vertDens = 180; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 38: - bitGraph.horizDens = 90; - bitGraph.vertDens = 180; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 39: - bitGraph.horizDens = 180; - bitGraph.vertDens = 180; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 3; - break; - case 40: - bitGraph.horizDens = 360; - bitGraph.vertDens = 180; - bitGraph.adjacent = false; - bitGraph.bytesColumn = 3; - break; - case 71: - bitGraph.horizDens = 180; - bitGraph.vertDens = 360; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 6; - break; - case 72: - bitGraph.horizDens = 360; - bitGraph.vertDens = 360; - bitGraph.adjacent = false; - bitGraph.bytesColumn = 6; - break; - case 73: - bitGraph.horizDens = 360; - bitGraph.vertDens = 360; - bitGraph.adjacent = true; - bitGraph.bytesColumn = 6; - break; - default: - //break; - printf("PRINTER: Unsupported bit image density"); - } - - bitGraph.remBytes = numCols * bitGraph.bytesColumn; - bitGraph.readBytesColumn = 0; -} - -void CPrinter::printBitGraph(Bit8u ch) -{ - bitGraph.column[bitGraph.readBytesColumn++] = ch; - bitGraph.remBytes--; - - // Only print after reading a full column - if (bitGraph.readBytesColumn < bitGraph.bytesColumn) - return; - - Real64 oldY = curY; - - SDL_LockSurface(page); - - // When page dpi is greater than graphics dpi, the drawn pixels get "bigger" - Bitu pixsizeX=1; - Bitu pixsizeY=1; - if(bitGraph.adjacent) { - pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; - pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; - } - // TODO figure this out for 360dpi mode in windows - -// Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; -// Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; - - for (Bitu i=0; i>=1) { // for each bit - if (bitGraph.column[i] & j) { - for (Bitu xx=0; xxw) && ((PIXY + yy) < page->h)) - *((Bit8u*)page->pixels + (PIXX+xx) + (PIXY+yy)*page->pitch) |= (color|0x1F); - } - } // else white pixel - - curY += (Real64)1/(Real64)bitGraph.vertDens; // TODO line wrap? - } - } - SDL_UnlockSurface(page); - - curY = oldY; - - bitGraph.readBytesColumn = 0; - - // Advance to the left - curX += (Real64)1/(Real64)bitGraph.horizDens; -} -#endif // HAVE_SDL - -void CPrinter::formFeed() -{ -#ifdef HAVE_SDL - // Don't output blank pages - newPage(!isBlank(),true); - finishMultipage(); -#endif // HAVE_SDL -} - -#ifdef HAVE_SDL -static void findNextName(char* front, char* ext, char* fname) -{ - document_path = ""; - Bitu i = 1; - Bitu slen = strlen(document_path); - if(slen>(200-15)) { - fname[0]=0; - return; - } - FILE *test = NULL; - do - { - strcpy(fname, document_path); - printf(fname); -#ifdef WIN32 - const char* const pathstring = ".\\%s%d%s"; -#else - const char* const pathstring = "./%s%d%s"; -#endif - sprintf(fname+strlen(fname), pathstring, front,i++,ext); - test = fopen(fname, "rb"); - if (test != NULL) - fclose(test); - } - while (test != NULL ); -} - -void CPrinter::outputPage() -{ -/* SDL_Surface *screen; - -screen = SDL_SetVideoMode(1024, 768, 16, SDL_DOUBLEBUF | SDL_RESIZABLE); -if (screen == NULL) { - printf("Unable to set video mode: %s\n", SDL_GetError()); -} -SDL_Surface *image; -SDL_LockSurface(page); -image = SDL_DisplayFormat(page); -SDL_UnlockSurface(page); -SDL_Rect src, dest; - -src.x = 0; -src.y = 0; -src.w = image->w; -src.h = image->h; - -dest.x = 100; -dest.y = 100; -dest.w = image->w; -dest.h = image->h; - -SDL_BlitSurface(image, &src, screen, &dest); -SDL_Flip(screen); - -SDL_Delay(2000); -SDL_FreeSurface(image);*/ - - char fname[200]; - - if (strcasecmp(output, "printer") == 0) - { -#if defined (WIN32) - - Bit16u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH); - Bit16u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT); - - Real64 scaleW, scaleH; - - if (page->w > physW) - scaleW = (Real64)page->w / (Real64)physW; - else - scaleW = (Real64)physW / (Real64)page->w; - - if (page->h > physH) - scaleH = (Real64)page->h / (Real64)physH; - else - scaleH = (Real64)physH / (Real64)page->h; - - HDC memHDC = CreateCompatibleDC(printerDC); - BITMAPINFO *BitmapInfo; - HBITMAP bitmap; - - // Start new printer job? - if (outputHandle == NULL) - { - DOCINFO docinfo; - docinfo.cbSize = sizeof(docinfo); - docinfo.lpszDocName = "GSport Virtual Printer"; - docinfo.lpszOutput = NULL; - docinfo.lpszDatatype = NULL; - docinfo.fwType = 0; - - StartDoc(printerDC, &docinfo); - multiPageCounter = 1; - } - SDL_LockSurface(page); - StartPage(printerDC); - DWORD TotalSize; - HGDIOBJ Prev; - void* Pixels; - BitmapInfo = (BITMAPINFO*) - malloc (sizeof (BITMAPINFO)+255*sizeof (RGBQUAD)); - memset (BitmapInfo,0,sizeof (bitmap)); - BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - BitmapInfo->bmiHeader.biWidth = page->w; - BitmapInfo->bmiHeader.biHeight = -page->h; - BitmapInfo->bmiHeader.biPlanes = 1; - BitmapInfo->bmiHeader.biBitCount = page->format->BitsPerPixel; - BitmapInfo->bmiHeader.biCompression = BI_RGB; - BitmapInfo->bmiHeader.biSizeImage = page->h * page->pitch; - BitmapInfo->bmiHeader.biXPelsPerMeter = 0; - BitmapInfo->bmiHeader.biYPelsPerMeter = 0; - BitmapInfo->bmiHeader.biClrUsed = page->format->palette->ncolors; - BitmapInfo->bmiHeader.biClrImportant = 0; - if (page->format->palette) { - for (int I=0; Iformat->palette->ncolors; I++) { - BitmapInfo->bmiColors[I].rgbRed = - (page->format->palette->colors+I)->r; - BitmapInfo->bmiColors[I].rgbGreen = - (page->format->palette->colors+I)->g; - BitmapInfo->bmiColors[I].rgbBlue = - (page->format->palette->colors+I)->b; - } - } - memHDC = CreateCompatibleDC(printerDC); - if (memHDC) { - bitmap = CreateDIBSection(memHDC, BitmapInfo, DIB_RGB_COLORS, - (&Pixels), NULL, 0); - if (bitmap) { - memcpy (Pixels, page->pixels, - BitmapInfo->bmiHeader.biSizeImage); - Prev = SelectObject (memHDC, bitmap); - StretchBlt(printerDC, 0, 0, physW, physH, memHDC, 0, 0, page->w, page->h, SRCCOPY); - SelectObject (memHDC,Prev); - DeleteObject (bitmap); - } - } - free (BitmapInfo); - SDL_UnlockSurface(page); - EndPage(printerDC); - - if (multipageOutput) - { - multiPageCounter++; - outputHandle = printerDC; - } - else - { - EndDoc(printerDC); - outputHandle = NULL; - } - DeleteObject(bitmap); - DeleteDC(memHDC); -#else - //LOG_MSG("PRINTER: Direct printing not supported under this OS"); -#endif - } -#ifdef C_LIBPNG - else if (strcasecmp(output, "png") == 0) - { - // Find a page that does not exists - findNextName("page", ".png", &fname[0]); - - png_structp png_ptr; - png_infop info_ptr; - png_bytep * row_pointers; - png_color palette[256]; - Bitu i; - - /* Open the actual file */ - FILE * fp=fopen(fname,"wb"); - if (!fp) - { - //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); - return; - } - - /* First try to alloacte the png structures */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); - if (!png_ptr) return; - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr,(png_infopp)NULL); - return; - } - - /* Finalize the initing of png library */ - png_init_io(png_ptr, fp); - png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192); - - - png_set_IHDR(png_ptr, info_ptr, page->w, page->h, - 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - for (i=0;i<256;i++) - { - palette[i].red = page->format->palette->colors[i].r; - palette[i].green = page->format->palette->colors[i].g; - palette[i].blue = page->format->palette->colors[i].b; - } - png_set_PLTE(png_ptr, info_ptr, palette,256); - png_set_packing(png_ptr); - SDL_LockSurface(page); - - // Allocate an array of scanline pointers - row_pointers = (png_bytep*)malloc(page->h*sizeof(png_bytep)); - for (i=0; ih; i++) - row_pointers[i] = ((Bit8u*)page->pixels+(i*page->pitch)); - - // tell the png library what to encode. - png_set_rows(png_ptr, info_ptr, row_pointers); - - // Write image to file - png_write_png(png_ptr, info_ptr, 0, NULL); - - - - - SDL_UnlockSurface(page); - - /*close file*/ - fclose(fp); - - /*Destroy PNG structs*/ - png_destroy_write_struct(&png_ptr, &info_ptr); - - /*clean up dynamically allocated RAM.*/ - free(row_pointers); - } -#endif - else if (strcasecmp(output, "ps") == 0) - { - FILE* psfile = NULL; - - // Continue postscript file? - if (outputHandle != NULL) - psfile = (FILE*)outputHandle; - - // Create new file? - if (psfile == NULL) - { - if (!multipageOutput) - findNextName("page", ".ps", &fname[0]); - else - findNextName("doc", ".ps", &fname[0]); - - psfile = fopen(fname, "wb"); - if (!psfile) - { - printf("PRINTER: Can't open file %s for printer output", fname); - return; - } - - // Print header - fprintf(psfile, "%%!PS-Adobe-3.0\n"); - fprintf(psfile, "%%%%Pages: (atend)\n"); - fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); - fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n"); - fprintf(psfile, "%%%%DocumentData: Clean7Bit\n"); - fprintf(psfile, "%%%%LanguageLevel: 2\n"); - fprintf(psfile, "%%%%EndComments\n"); - multiPageCounter = 1; - } - - fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); - fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); - fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); - fprintf(psfile, "currentfile\n"); - fprintf(psfile, "/ASCII85Decode filter\n"); - fprintf(psfile, "/RunLengthDecode filter\n"); - fprintf(psfile, "image\n"); - - SDL_LockSurface(page); - - Bit32u pix = 0; - Bit32u numpix = page->h*page->w; - ASCII85BufferPos = ASCII85CurCol = 0; - - while (pix < numpix) - { - // Compress data using RLE - - if ((pix < numpix-2) && (getPixel(pix) == getPixel(pix+1)) && (getPixel(pix) == getPixel(pix+2))) - { - // Found three or more pixels with the same color - Bit8u sameCount = 3; - Bit8u col = getPixel(pix); - while (sameCount < 128 && sameCount+pix < numpix && col == getPixel(pix+sameCount)) - sameCount++; - - fprintASCII85(psfile, 257-sameCount); - fprintASCII85(psfile, 255-col); - - // Skip ahead - pix += sameCount; - } - else - { - // Find end of heterogenous area - Bit8u diffCount = 1; - while (diffCount < 128 && diffCount+pix < numpix && - ( - (diffCount+pix < numpix-2) - || (getPixel(pix+diffCount) != getPixel(pix+diffCount+1)) - || (getPixel(pix+diffCount) != getPixel(pix+diffCount+2)) - )) - diffCount++; - - fprintASCII85(psfile, diffCount-1); - for (Bit8u i=0; i= 79) - { - ASCII85CurCol = 0; - fprintf(f, "\n"); - } - } - else - { - char buffer[5]; - for (Bit8s i=4; i>=0; i--) - { - buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85); - buffer[i] += 33; - num /= (Bit32u)85; - } - - // Make sure a line never starts with a % (which may be mistaken as start of a comment) - if (ASCII85CurCol == 0 && buffer[0] == '%') - fprintf(f, " "); - - for (int i=0; i<((b != 257)?5:ASCII85BufferPos+1); i++) - { - fprintf(f, "%c", buffer[i]); - if (++ASCII85CurCol >= 79) - { - ASCII85CurCol = 0; - fprintf(f, "\n"); - } - } - } - - ASCII85BufferPos = 0; - } - - } - else // Close string - { - // Partial tupel if there are still bytes in the buffer - if (ASCII85BufferPos > 0) - { - for (Bit8u i = ASCII85BufferPos; i < 4; i++) - ASCII85Buffer[i] = 0; - - fprintASCII85(f, 257); - } - - fprintf(f, "~"); - fprintf(f, ">\n"); - } -} - -void CPrinter::finishMultipage() -{ - if (outputHandle != NULL) - { - if (strcasecmp(output, "ps") == 0) - { - FILE* psfile = (FILE*)outputHandle; - fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); - fprintf(psfile, "%%%%EOF\n"); - fclose(psfile); - } - else if (strcasecmp(output, "printer") == 0) - { -#if defined (WIN32) - EndDoc(printerDC); -#endif - } - outputHandle = NULL; - } -} - -bool CPrinter::isBlank() { - bool blank = true; - SDL_LockSurface(page); - - for (Bit16u y=0; yh; y++) - for (Bit16u x=0; xw; x++) - if (*((Bit8u*)page->pixels + x + (y*page->pitch)) != 0) - blank = false; - - SDL_UnlockSurface(page); - return blank; -} - -Bit8u CPrinter::getPixel(Bit32u num) { - Bit32u pixel = *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); - return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); -} -#endif // HAVE_SDL - -//Interfaces to C code - - -extern "C" void printer_init(int pdpi, int pwidth, int pheight, char* poutput, bool mpage) -{ - if (defaultPrinter != NULL) return; - defaultPrinter = new CPrinter(pdpi, pwidth,pheight, poutput, mpage); -} -extern "C" void printer_loop(Bit8u pchar) -{ - if (defaultPrinter == NULL) return; - defaultPrinter->printChar(pchar); -} - -extern "C" void printer_close() -{ - delete defaultPrinter; - defaultPrinter = NULL; -} -extern "C" void printer_feed() -{ - if(defaultPrinter == NULL) return; - defaultPrinter->formFeed(); -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2010 - 2011 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Copyright (C) 2002-2004 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +//Modified for the KEGS emulator by Christopher G. Mason 02/2010 +//Added support for configuring the built in printer fonts + +#include "printer.h" +#include +#include "support.h" +//#include "png.h" +//#pragma comment( lib, "libpng.lib" ) +//#pragma comment (lib, "zdll.lib" ) + +static CPrinter* defaultPrinter = NULL; + +static FILE *textPrinterFile = NULL; +#ifdef WIN32 +const char* const textPrinterFileName = ".\\printer.txt"; +#else +const char* const textPrinterFileName = "./printer.txt"; +#endif + +#define PARAM16(I) (params[I+1]*256+params[I]) +#define PIXX ((Bitu)floor(curX*dpi+0.5)) +#define PIXY ((Bitu)floor(curY*dpi+0.5)) + +static Bitu printer_timout; +static bool timeout_dirty; +static const char* document_path; +extern "C" char* g_printer_font_roman; +extern "C" char* g_printer_font_sans; +extern "C" char* g_printer_font_courier; +extern "C" char* g_printer_font_prestige; +extern "C" char* g_printer_font_script; +extern "C" char* g_printer_font_ocra; +Bit8u paramc = '0'; + +#include "printer_charmaps.h" + +#ifdef HAVE_SDL +void CPrinter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal) +{ + float red=redmax/30.9; + float green=greenmax/30.9; + float blue=bluemax/30.9; + + Bit8u colormask=colorID<<=5; + + for(int i = 0; i < 32;i++) { + pal->colors[i+colormask].r=255-(red*(float)i); + pal->colors[i+colormask].g=255-(green*(float)i); + pal->colors[i+colormask].b=255-(blue*(float)i); + } +} +#endif // HAVE_SDL + +CPrinter::CPrinter(Bit16u dpi, Bit16u width, Bit16u height, char* output, bool multipageOutput) +{ +#ifdef HAVE_SDL + if (FT_Init_FreeType(&FTlib)) + { + page = NULL; + } + else + { + this->dpi = dpi; + this->output = output; + this->multipageOutput = multipageOutput; + + defaultPageWidth = (Real64)width/(Real64)10; + defaultPageHeight = (Real64)height/(Real64)10; + + // Create page + page = SDL_CreateRGBSurface( + SDL_SWSURFACE, + (Bitu)(defaultPageWidth*dpi), + (Bitu)(defaultPageHeight*dpi), + 8, + 0, + 0, + 0, + 0); + + // Set a grey palette + SDL_Palette* palette = page->format->palette; + + for (Bitu i=0; i<32; i++) + { + palette->colors[i].r =255; + palette->colors[i].g =255; + palette->colors[i].b =255; + } + // 0 = all white needed for logic 000 + FillPalette( 0, 0, 0, 1, palette); + // 1 = magenta* 001 + FillPalette( 0, 255, 0, 1, palette); + // 2 = cyan* 010 + FillPalette(255, 0, 0, 2, palette); + // 3 = "violet" 011 + FillPalette(255, 255, 0, 3, palette); + // 4 = yellow* 100 + FillPalette( 0, 0, 255, 4, palette); + // 5 = red 101 + FillPalette( 0, 255, 255, 5, palette); + // 6 = green 110 + FillPalette(255, 0, 255, 6, palette); + // 7 = black 111 + FillPalette(255, 255, 255, 7, palette); + + // yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max + // Printing colors on top of each other ORs them and gets the + // correct resulting color. + // i.e. magenta on blank page yyy=001 + // then yellow on magenta 001 | 100 = 101 = red + + color=COLOR_BLACK; + + curFont = NULL; + charRead = false; + autoFeed = false; + outputHandle = NULL; + + resetPrinter(); + + if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + // Show Print dialog to obtain a printer device context + + PRINTDLG pd; + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = (HANDLE) NULL; + pd.hDevNames = (HANDLE) NULL; + pd.Flags = PD_RETURNDC; + pd.hwndOwner = NULL; + pd.hDC = (HDC) NULL; + pd.nFromPage = 1; + pd.nToPage = 1; + pd.nMinPage = 0; + pd.nMaxPage = 0; + pd.nCopies = 1; + pd.hInstance = NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPCSTR) NULL; + pd.lpSetupTemplateName = (LPCSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + PrintDlg(&pd); + // TODO: what if user presses cancel? + printerDC = pd.hDC; +#endif // WIN32 + } + } +#endif // HAVE_SDL +#ifndef HAVE_SDL + this->output = output; + this->multipageOutput = multipageOutput; +#endif // !HAVE_SDL +}; + +void CPrinter::resetPrinterHard() +{ +#ifdef HAVE_SDL + charRead = false; + resetPrinter(); +#endif // HAVE_SDL +} + +void CPrinter::resetPrinter() +{ +#ifdef HAVE_SDL + color=COLOR_BLACK; + curX = curY = 0.0; + ESCSeen = false; + FSSeen = false; + ESCCmd = 0; + numParam = neededParam = 0; + topMargin = 0.0; + leftMargin = 0.0; + rightMargin = pageWidth = defaultPageWidth; + bottomMargin = pageHeight = defaultPageHeight; + lineSpacing = (Real64)1/6; + cpi = 10.0; + curCharTable = 1; + style = 0; + extraIntraSpace = 0.0; + printUpperContr = true; + bitGraph.remBytes = 0; + densk = 0; + densl = 1; + densy = 2; + densz = 3; + charTables[0] = 0; // Italics + charTables[1] = charTables[2] = charTables[3] = 437; + definedUnit = -1; + multipoint = false; + multiPointSize = 0.0; + multicpi = 0.0; + hmi = -1.0; + msb = 255; + numPrintAsChar = 0; + LQtypeFace = roman; + + selectCodepage(charTables[curCharTable]); + + updateFont(); + +#endif // HAVE_SDL + newPage(false,true); +#ifdef HAVE_SDL + + // Default tabs => Each eight characters + for (Bitu i=0;i<32;i++) + horiztabs[i] = i*8*(1/(Real64)cpi); + numHorizTabs = 32; + + numVertTabs = 255; +#endif // HAVE_SDL +} + + +CPrinter::~CPrinter(void) +{ +#ifdef HAVE_SDL + finishMultipage(); + if (page != NULL) + { + SDL_FreeSurface(page); + page = NULL; + FT_Done_FreeType(FTlib); + } +#if defined (WIN32) + DeleteDC(printerDC); +#endif +#endif // HAVE_SDL +}; + +#ifdef HAVE_SDL +void CPrinter::selectCodepage(Bit16u cp) +{ + Bit16u *mapToUse = NULL; + + switch(cp) + { + case 0: // Italics, use cp437 + case 437: + mapToUse = (Bit16u*)&cp437Map; + break; + case 737: + mapToUse = (Bit16u*)&cp737Map; + break; + case 775: + mapToUse = (Bit16u*)&cp775Map; + break; + case 850: + mapToUse = (Bit16u*)&cp850Map; + break; + case 852: + mapToUse = (Bit16u*)&cp852Map; + break; + case 855: + mapToUse = (Bit16u*)&cp855Map; + break; + case 857: + mapToUse = (Bit16u*)&cp857Map; + break; + case 860: + mapToUse = (Bit16u*)&cp860Map; + break; + case 861: + mapToUse = (Bit16u*)&cp861Map; + break; + case 863: + mapToUse = (Bit16u*)&cp863Map; + break; + case 864: + mapToUse = (Bit16u*)&cp864Map; + break; + case 865: + mapToUse = (Bit16u*)&cp865Map; + break; + case 866: + mapToUse = (Bit16u*)&cp866Map; + break; + default: + //LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp); + mapToUse = (Bit16u*)&cp437Map; + } + + for (int i=0; i<256; i++) + curMap[i] = mapToUse[i]; +} +#endif // HAVE_SDL + +#ifdef HAVE_SDL +void CPrinter::updateFont() +{ + // char buffer[1000]; + if (curFont != NULL) + FT_Done_Face(curFont); + + char* fontName; + + switch (LQtypeFace) + { + case roman: + fontName = g_printer_font_roman; + break; + case sansserif: + fontName = g_printer_font_sans; + break; + case courier: + fontName = g_printer_font_courier; + break; + case prestige: + fontName = g_printer_font_prestige; + break; + case script: + fontName = g_printer_font_script; + break; + case ocra: + case ocrb: + fontName = g_printer_font_ocra; + break; + default: + fontName = g_printer_font_roman; + } + + if (FT_New_Face(FTlib, fontName, 0, &curFont)) + { + + printf("Unable to load font\n"); + //LOG_MSG("Unable to load font %s", fontName); + curFont = NULL; + } + + Real64 horizPoints = 10.5; + Real64 vertPoints = 10.5; + + if (!multipoint) { + actcpi = cpi; + /* + switch(style & (STYLE_CONDENSED|STYLE_PROP)) { + case STYLE_CONDENSED: // only condensed + if (cpi == 10.0) { + actcpi = 17.14; + horizPoints *= 10.0/17.14; + } else if(cpi == 12.0) { + actcpi = 20.0; + horizPoints *= 10.0/20.0; + vertPoints *= 10.0/12.0; + } else { + // ignored + } + break; + case STYLE_PROP|STYLE_CONDENSED: + horizPoints /= 2.0; + break; + case 0: // neither + case STYLE_PROP: // only proportional + horizPoints *= 10.0/cpi; + vertPoints *= 10.0/cpi; + break; + } + */ + if (!(style & STYLE_CONDENSED)) { + horizPoints *= 10.0/cpi; + vertPoints *= 10.0/cpi; + } + + if (!(style & STYLE_PROP)) { + if ((cpi == 10.0) && (style & STYLE_CONDENSED)) { + actcpi = 17.14; + horizPoints *= 10.0/17.14; + } + if ((cpi == 12.0) && (style & STYLE_CONDENSED)) { + actcpi = 20.0; + horizPoints *= 10.0/20.0; + vertPoints *= 10.0/12.0; + } + } else if (style & STYLE_CONDENSED) horizPoints /= 2.0; + + + if ((style & STYLE_DOUBLEWIDTH) || (style & STYLE_DOUBLEWIDTHONELINE)) { + actcpi /= 2.0; + horizPoints *= 2.0; + } + + if (style & STYLE_DOUBLEHEIGHT) vertPoints *= 2.0; + } else { // multipoint true + actcpi = multicpi; + horizPoints = vertPoints = multiPointSize; + } + + if ((style & STYLE_SUPERSCRIPT) || (style & STYLE_SUBSCRIPT)) { + horizPoints *= 2.0/3.0; + vertPoints *= 2.0/3.0; + actcpi /= 2.0/3.0; + } + + FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi); + + if (style & STYLE_ITALICS || charTables[curCharTable] == 0) + { + FT_Matrix matrix; + matrix.xx = 0x10000L; + matrix.xy = (FT_Fixed)(0.20 * 0x10000L); + matrix.yx = 0; + matrix.yy = 0x10000L; + FT_Set_Transform(curFont, &matrix, 0); + } +} +#endif // HAVE_SDL + +#ifdef HAVE_SDL +bool CPrinter::processCommandChar(Bit8u ch) +{ + if (ESCSeen || FSSeen) + { + ESCCmd = ch; + if(FSSeen) ESCCmd |= 0x800; + ESCSeen = FSSeen = false; + numParam = 0; + + switch (ESCCmd) { + case 0x02: // Undocumented + case 0x0a: // Reverse line feed (ESC LF) + case 0x0c: // Return to top of current page (ESC FF) + case 0x0e: // Select double-width printing (one line) (ESC SO) + case 0x0f: // Select condensed printing (ESC SI) + case 0x23: // Cancel MSB control (ESC #) + case 0x30: // Select 1/8-inch line spacing (ESC 0) + case 0x31: // Select 7/60-inch line spacing (ESC 1) + case 0x32: // Select 1/6-inch line spacing (ESC 2) + case 0x34: // Select italic font (ESC 4) + case 0x35: // Cancel italic font (ESC 5) + case 0x36: // Enable printing of upper control codes (ESC 6) + case 0x37: // Enable upper control codes (ESC 7) + case 0x38: // Disable paper-out detector (ESC 8) + case 0x39: // Enable paper-out detector (ESC 9) + case 0x3c: // Unidirectional mode (one line) (ESC <) + case 0x3d: // Set MSB to 0 (ESC =) + case 0x3e: // Set MSB to 1 (ESC >) + case 0x40: // Initialize printer (ESC @) + case 0x45: // Select bold font (ESC E) + case 0x46: // Cancel bold font (ESC F) + case 0x47: // Select double-strike printing (ESC G) + case 0x48: // Cancel double-strike printing (ESC H) + case 0x4d: // Select 10.5-point, 12-cpi (ESC M) + case 0x4f: // Cancel bottom margin [conflict] (ESC O) + case 0x50: // Select 10.5-point, 10-cpi (ESC P) + case 0x54: // Cancel superscript/subscript printing (ESC T) + case 0x5e: // Enable printing of all character codes on next character (ESC ^) + case 0x67: // Select 10.5-point, 15-cpi (ESC g) + + case 0x834: // Select italic font (FS 4) (= ESC 4) + case 0x835: // Cancel italic font (FS 5) (= ESC 5) + case 0x846: // Select forward feed mode (FS F) + case 0x852: // Select reverse feed mode (FS R) + neededParam = 0; + break; + case 0x19: // Control paper loading/ejecting (ESC EM) + case 0x20: // Set intercharacter space (ESC SP) + case 0x21: // Master select (ESC !) + case 0x2b: // Set n/360-inch line spacing (ESC +) + case 0x2d: // Turn underline on/off (ESC -) + case 0x2f: // Select vertical tab channel (ESC /) + case 0x33: // Set n/180-inch line spacing (ESC 3) + case 0x41: // Set n/60-inch line spacing (ESC A) + case 0x43: // Set page length in lines (ESC C) + case 0x49: // Select character type and print pitch (ESC I) + case 0x4a: // Advance print position vertically (ESC J) + case 0x4e: // Set bottom margin (ESC N) + case 0x51: // Set right margin (ESC Q) + case 0x52: // Select an international character set (ESC R) + case 0x53: // Select superscript/subscript printing (ESC S) + case 0x55: // Turn unidirectional mode on/off (ESC U) + //case 0x56: // Repeat data (ESC V) + case 0x57: // Turn double-width printing on/off (ESC W) + case 0x61: // Select justification (ESC a) + case 0x66: // Absolute horizontal tab in columns [conflict] (ESC f) + case 0x68: // Select double or quadruple size (ESC h) + case 0x69: // Immediate print (ESC i) + case 0x6a: // Reverse paper feed (ESC j) + case 0x6b: // Select typeface (ESC k) + case 0x6c: // Set left margin (ESC 1) + case 0x70: // Turn proportional mode on/off (ESC p) + case 0x72: // Select printing color (ESC r) + case 0x73: // Low-speed mode on/off (ESC s) + case 0x74: // Select character table (ESC t) + case 0x77: // Turn double-height printing on/off (ESC w) + case 0x78: // Select LQ or draft (ESC x) + case 0x7e: // Select/Deselect slash zero (ESC ~) + + case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) + case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) + case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) + case 0x843: // Select LQ type style (FS C) (= ESC k) + case 0x845: // Select character width (FS E) + case 0x849: // Select character table (FS I) (= ESC t) + case 0x853: // Select High Speed/High Density elite pitch (FS S) + case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + neededParam = 1; + break; + case 0x24: // Set absolute horizontal print position (ESC $) + case 0x3f: // Reassign bit-image mode (ESC ?) + case 0x4b: // Select 60-dpi graphics (ESC K) + case 0x4c: // Select 120-dpi graphics (ESC L) + case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) + case 0x5a: // Select 240-dpi graphics (ESC Z) + case 0x5c: // Set relative horizontal print position (ESC \) + case 0x63: // Set horizontal motion index (HMI) [conflict] (ESC c) + case 0x65: // Set vertical tab stops every n lines (ESC e) + case 0x85a: // Print 24-bit hex-density graphics (FS Z) + neededParam = 2; + break; + case 0x2a: // Select bit image (ESC *) + case 0x58: // Select font by pitch and point [conflict] (ESC X) + neededParam = 3; + break; + case 0x5b: // Select character height, width, line spacing + neededParam = 7; + break; + case 0x62: // Set vertical tabs in VFU channels (ESC b) + case 0x42: // Set vertical tabs (ESC B) + numVertTabs = 0; + return true; + case 0x44: // Set horizontal tabs (ESC D) + numHorizTabs = 0; + return true; + case 0x25: // Select user-defined set (ESC %) + case 0x26: // Define user-defined characters (ESC &) + case 0x3a: // Copy ROM to RAM (ESC :) + //LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!"); + return true; + case 0x28: // Two bytes sequence + return true; + default: + /*LOG_MSG("PRINTER: Unknown command %c (%02Xh) %c , unable to skip parameters.", + (ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd);*/ + + neededParam = 0; + ESCCmd = 0; + return true; + } + + if (neededParam > 0) + return true; + } + + // Two bytes sequence + if (ESCCmd == '(') + { + ESCCmd = 0x200 + ch; + + switch (ESCCmd) + { + case 0x242: // Bar code setup and print (ESC (B) + case 0x25e: // Print data as characters (ESC (^) + neededParam = 2; + break; + case 0x255: // Set unit (ESC (U) + neededParam = 3; + break; + case 0x243: // Set page length in defined unit (ESC (C) + case 0x256: // Set absolute vertical print position (ESC (V) + case 0x276: // Set relative vertical print position (ESC (v) + neededParam = 4; + break; + case 0x274: // Assign character table (ESC (t) + case 0x22d: // Select line/score (ESC (-) + neededParam = 5; + break; + case 0x263: // Set page format (ESC (c) + neededParam = 6; + break; + default: + // ESC ( commands are always followed by a "number of parameters" word parameter + //LOG(LOG_MISC,LOG_ERROR) + printf("PRINTER: Skipping unsupported command ESC ( %c (%02X).", ESCCmd, ESCCmd); + neededParam = 2; + ESCCmd = 0x101; + return true; + } + + if (neededParam > 0) + return true; + } + + // Ignore VFU channel setting + if (ESCCmd == 0x62) { + ESCCmd = 0x42; + return true; + } + + // Collect vertical tabs + if (ESCCmd == 0x42) { + if (ch == 0 || (numVertTabs>0 && verttabs[numVertTabs-1] > (Real64)ch*lineSpacing)) // Done + ESCCmd = 0; + else + if (numVertTabs < 16) + verttabs[numVertTabs++] = (Real64)ch*lineSpacing; + } + + // Collect horizontal tabs + if (ESCCmd == 0x44) + { + if (ch == 0 || (numHorizTabs>0 && horiztabs[numHorizTabs-1] > (Real64)ch*(1/(Real64)cpi))) // Done + ESCCmd = 0; + else + if (numHorizTabs < 32) + horiztabs[numHorizTabs++] = (Real64)ch*(1/(Real64)cpi); + } + + if (numParam < neededParam) + { + params[numParam++] = ch; + + if (numParam < neededParam) + return true; + } + + if (ESCCmd != 0) + { + switch (ESCCmd) + { + case 0x02: // Undocumented + // Ignore + break; + case 0x0e: // Select double-width printing (one line) (ESC SO) + if (!multipoint) + { + hmi = -1; + style |= STYLE_DOUBLEWIDTHONELINE; + updateFont(); + } + break; + case 0x0f: // Select condensed printing (ESC SI) + if (!multipoint && (cpi!=15.0)) { + hmi = -1; + style |= STYLE_CONDENSED; + updateFont(); + } + break; + case 0x19: // Control paper loading/ejecting (ESC EM) + // We are not really loading paper, so most commands can be ignored + if (params[0] == 'R') + newPage(true,false); // TODO resetx? + break; + case 0x20: // Set intercharacter space (ESC SP) + if (!multipoint) + { + extraIntraSpace = (Real64)params[0] / (printQuality==QUALITY_DRAFT?120:180); + hmi = -1; + updateFont(); + } + break; + case 0x21: // Master select (ESC !) + cpi = params[0] & 0x01 ? 12:10; + + // Reset first seven bits + style &= 0xFF80; + if (params[0] & 0x02) + style |= STYLE_PROP; + if (params[0] & 0x04) + style |= STYLE_CONDENSED; + if (params[0] & 0x08) + style |= STYLE_BOLD; + if (params[0] & 0x10) + style |= STYLE_DOUBLESTRIKE; + if (params[0] & 0x20) + style |= STYLE_DOUBLEWIDTH; + if (params[0] & 0x40) + style |= STYLE_ITALICS; + if (params[0] & 0x80) + { + score = SCORE_SINGLE; + style |= STYLE_UNDERLINE; + } + + hmi = -1; + multipoint = false; + updateFont(); + break; + case 0x23: // Cancel MSB control (ESC #) + msb = 255; + break; + case 0x24: // Set absolute horizontal print position (ESC $) + { + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)60.0; + + Real64 newX = leftMargin + ((Real64)PARAM16(0)/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + case 0x85a: // Print 24-bit hex-density graphics (FS Z) + setupBitImage(40, PARAM16(0)); + break; + case 0x2a: // Select bit image (ESC *) + setupBitImage(params[0], PARAM16(1)); + break; + case 0x2b: // Set n/360-inch line spacing (ESC +) + case 0x833: // Set n/360-inch line spacing (FS 3) + lineSpacing = (Real64)params[0]/360; + break; + case 0x2d: // Turn underline on/off (ESC -) + if (params[0] == 0 || params[0] == 48) + style &= ~STYLE_UNDERLINE; + if (params[0] == 1 || params[0] == 49) + { + style |= STYLE_UNDERLINE; + score = SCORE_SINGLE; + } + updateFont(); + break; + case 0x2f: // Select vertical tab channel (ESC /) + // Ignore + break; + case 0x30: // Select 1/8-inch line spacing (ESC 0) + lineSpacing = (Real64)1/8; + break; + case 0x32: // Select 1/6-inch line spacing (ESC 2) + lineSpacing = (Real64)1/6; + break; + case 0x33: // Set n/180-inch line spacing (ESC 3) + lineSpacing = (Real64)params[0]/180; + break; + case 0x34: // Select italic font (ESC 4) + style |= STYLE_ITALICS; + updateFont(); + break; + case 0x35: // Cancel italic font (ESC 5) + style &= ~STYLE_ITALICS; + updateFont(); + break; + case 0x36: // Enable printing of upper control codes (ESC 6) + printUpperContr = true; + break; + case 0x37: // Enable upper control codes (ESC 7) + printUpperContr = false; + break; + case 0x3c: // Unidirectional mode (one line) (ESC <) + // We don't have a print head, so just ignore this + break; + case 0x3d: // Set MSB to 0 (ESC =) + msb = 0; + break; + case 0x3e: // Set MSB to 1 (ESC >) + msb = 1; + break; + case 0x3f: // Reassign bit-image mode (ESC ?) + if (params[0] == 75) + densk = params[1]; + if (params[0] == 76) + densl = params[1]; + if (params[0] == 89) + densy = params[1]; + if (params[0] == 90) + densz = params[1]; + break; + case 0x40: // Initialize printer (ESC @) + resetPrinter(); + break; + case 0x41: // Set n/60-inch line spacing + case 0x841: + lineSpacing = (Real64)params[0]/60; + break; + case 0x43: // Set page length in lines (ESC C) + if (params[0] != 0) + pageHeight = bottomMargin = (Real64)params[0] * lineSpacing; + else // == 0 => Set page length in inches + { + neededParam = 1; + numParam = 0; + ESCCmd = 0x100; + return true; + } + break; + case 0x45: // Select bold font (ESC E) + style |= STYLE_BOLD; + updateFont(); + break; + case 0x46: // Cancel bold font (ESC F) + style &= ~STYLE_BOLD; + updateFont(); + break; + case 0x47: // Select dobule-strike printing (ESC G) + style |= STYLE_DOUBLESTRIKE; + break; + case 0x48: // Cancel double-strike printing (ESC H) + style &= ~STYLE_DOUBLESTRIKE; + break; + case 0x4a: // Advance print position vertically (ESC J n) + curY += (Real64)((Real64)params[0] / 180); + if (curY > bottomMargin) + newPage(true,false); + break; + case 0x4b: // Select 60-dpi graphics (ESC K) + setupBitImage(densk, PARAM16(0)); + break; + case 0x4c: // Select 120-dpi graphics (ESC L) + setupBitImage(densl, PARAM16(0)); + break; + case 0x4d: // Select 10.5-point, 12-cpi (ESC M) + cpi = 12; + hmi = -1; + multipoint = false; + updateFont(); + break; + case 0x4e: // Set bottom margin (ESC N) + topMargin = 0.0; + bottomMargin = (Real64)params[0] * lineSpacing; + break; + case 0x4f: // Cancel bottom (and top) margin + topMargin = 0.0; + bottomMargin = pageHeight; + break; + case 0x50: // Select 10.5-point, 10-cpi (ESC P) + cpi = 10; + hmi = -1; + multipoint = false; + updateFont(); + break; + case 0x51: // Set right margin + rightMargin = (Real64)(params[0]-1.0) / (Real64)cpi; + break; + case 0x52: // Select an international character set (ESC R) + if (params[0] <= 13 || params[0] == 64) + { + if (params[0] == 64) + params[0] = 14; + + curMap[0x23] = intCharSets[params[0]][0]; + curMap[0x24] = intCharSets[params[0]][1]; + curMap[0x40] = intCharSets[params[0]][2]; + curMap[0x5b] = intCharSets[params[0]][3]; + curMap[0x5c] = intCharSets[params[0]][4]; + curMap[0x5d] = intCharSets[params[0]][5]; + curMap[0x5e] = intCharSets[params[0]][6]; + curMap[0x60] = intCharSets[params[0]][7]; + curMap[0x7b] = intCharSets[params[0]][8]; + curMap[0x7c] = intCharSets[params[0]][9]; + curMap[0x7d] = intCharSets[params[0]][10]; + curMap[0x7e] = intCharSets[params[0]][11]; + } + break; + case 0x53: // Select superscript/subscript printing (ESC S) + if (params[0] == 0 || params[0] == 48) + style |= STYLE_SUBSCRIPT; + if (params[0] == 1 || params[1] == 49) + style |= STYLE_SUPERSCRIPT; + updateFont(); + break; + case 0x54: // Cancel superscript/subscript printing (ESC T) + style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + updateFont(); + break; + case 0x55: // Turn unidirectional mode on/off (ESC U) + // We don't have a print head, so just ignore this + break; + case 0x57: // Turn double-width printing on/off (ESC W) + if (!multipoint) + { + hmi = -1; + if (params[0] == 0 || params[0] == 48) + style &= ~STYLE_DOUBLEWIDTH; + if (params[0] == 1 || params[0] == 49) + style |= STYLE_DOUBLEWIDTH; + updateFont(); + } + break; + case 0x58: // Select font by pitch and point (ESC X) + multipoint = true; + // Copy currently non-multipoint CPI if no value was set so far + if (multicpi == 0) + multicpi = cpi; + if (params[0] > 0) // Set CPI + { + if (params[0] == 1) // Proportional spacing + style |= STYLE_PROP; + else if (params[0] >= 5) + multicpi = (Real64)360 / (Real64)params[0]; + } + if (multiPointSize == 0) + multiPointSize = (Real64)10.5; + if (PARAM16(1) > 0) // Set points + multiPointSize = ((Real64)PARAM16(1)) / 2; + updateFont(); + break; + case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) + setupBitImage(densy, PARAM16(0)); + break; + case 0x5a: // Select 240-dpi graphics (ESC Z) + setupBitImage(densz, PARAM16(0)); + break; + case 0x5c: // Set relative horizontal print position (ESC \) + { + Bit16s toMove = PARAM16(0); + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)(printQuality==QUALITY_DRAFT?120.0:180.0); + curX += (Real64)((Real64)toMove / unitSize); + } + break; + case 0x61: // Select justification (ESC a) + // Ignore + break; + case 0x63: // Set horizontal motion index (HMI) (ESC c) + hmi = (Real64)PARAM16(0) / (Real64)360.0; + extraIntraSpace = 0.0; + break; + case 0x67: // Select 10.5-point, 15-cpi (ESC g) + cpi = 15; + hmi = -1; + multipoint = false; + updateFont(); + break; + case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet + if(lineSpacing < 0) lineSpacing *= -1; + break; + case 0x6a: // Reverse paper feed (ESC j) + { + Real64 reverse = (Real64)PARAM16(0) / (Real64)216.0; + reverse = curY - reverse; + if(reverse < leftMargin) curY = leftMargin; + else curY = reverse; + break; + } + case 0x6b: // Select typeface (ESC k) + paramc = params[0]-'0'; + //if (params[0] <= 11 || params[0] == 30 || params[0] == 31) + if (paramc <= 11 || paramc == 30 || paramc == 31) + LQtypeFace = (Typeface)paramc; + updateFont(); + break; + case 0x6c: // Set left margin (ESC l) + leftMargin = (Real64)(params[0]-1.0) / (Real64)cpi; + if (curX < leftMargin) + curX = leftMargin; + break; + case 0x70: // Turn proportional mode on/off (ESC p) + if (params[0] == 0 || params[0] == 48) + style &= (0xffff - STYLE_PROP); + if (params[0] == 1 || params[0] == 49) + { + style |= STYLE_PROP; + printQuality = QUALITY_LQ; + } + multipoint = false; + hmi = -1; + updateFont(); + break; + case 0x72: // Select printing color (ESC r) + + if(params[0]==0 || params[0] > 6) color = COLOR_BLACK; + else color = params[0]<<5; + break; + case 0x73: // Select low-speed mode (ESC s) + // Ignore + break; + case 0x74: // Select character table (ESC t) + case 0x849: // Select character table (FS I) + if (params[0] < 4) + curCharTable = params[0]; + if (params[0] >= 48 && params[0] <= 51) + curCharTable = params[0] - 48; + selectCodepage(charTables[curCharTable]); + updateFont(); + break; + case 0x77: // Turn double-height printing on/off (ESC w) + if (!multipoint) + { + if (params[0] == 0 || params[0] == 48) + style &= ~STYLE_DOUBLEHEIGHT; + if (params[0] == 1 || params[0] == 49) + style |= STYLE_DOUBLEHEIGHT; + updateFont(); + } + break; + case 0x78: // Select LQ or draft (ESC x) + if (params[0] == 0 || params[0] == 48) { + printQuality = QUALITY_DRAFT; + style |= STYLE_CONDENSED; + } + if (params[0] == 1 || params[0] == 49) { + printQuality = QUALITY_LQ; + style &= ~STYLE_CONDENSED; + } + hmi = -1; + updateFont(); + break; + case 0x100: // Set page length in inches (ESC C NUL) + pageHeight = (Real64)params[0]; + bottomMargin = pageHeight; + topMargin = 0.0; + break; + case 0x101: // Skip unsupported ESC ( command + neededParam = PARAM16(0); + numParam = 0; + break; + case 0x274: // Assign character table (ESC (t) + if (params[2] < 4 && params[3] < 16) + { + charTables[params[2]] = codepages[params[3]]; + //LOG_MSG("curr table: %d, p2: %d, p3: %d",curCharTable,params[2],params[3]); + if (params[2] == curCharTable) + selectCodepage(charTables[curCharTable]); + } + break; + case 0x22d: // Select line/score (ESC (-) + style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); + score = params[4]; + if (score) + { + if (params[3] == 1) + style |= STYLE_UNDERLINE; + if (params[3] == 2) + style |= STYLE_STRIKETHROUGH; + if (params[3] == 3) + style |= STYLE_OVERSCORE; + } + updateFont(); + break; + case 0x242: // Bar code setup and print (ESC (B) + //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Bardcode printing not supported"); + // Find out how many bytes to skip + neededParam = PARAM16(0); + numParam = 0; + break; + case 0x243: // Set page length in defined unit (ESC (C) + if (params[0] != 0 && definedUnit > 0) + { + pageHeight = bottomMargin = ((Real64)PARAM16(2)) * definedUnit; + topMargin = 0.0; + } + break; + case 0x255: // Set unit (ESC (U) + definedUnit = (Real64)params[2] / (Real64)3600; + break; + case 0x256: // Set absolute vertical print position (ESC (V) + { + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)360.0; + Real64 newPos = topMargin + (((Real64)PARAM16(2)) * unitSize); + if (newPos > bottomMargin) + newPage(true,false); + else + curY = newPos; + } + break; + case 0x25e: // Print data as characters (ESC (^) + numPrintAsChar = PARAM16(0); + break; + case 0x263: // Set page format (ESC (c) + if (definedUnit > 0) + { + Real64 newTop, newBottom; + newTop = ((Real64)PARAM16(2)) * definedUnit; + newBottom = ((Real64)PARAM16(4)) * definedUnit; + if(newTop >= newBottom) break; + if(newTop < pageHeight) topMargin = newTop; + if(newBottom < pageHeight) bottomMargin = newBottom; + if(topMargin > curY) curY = topMargin; + //LOG_MSG("du %d, p1 %d, p2 %d, newtop %f, newbott %f, nt %f, nb %f, ph %f", + // (Bitu)definedUnit,PARAM16(2),PARAM16(4),topMargin,bottomMargin, + // newTop,newBottom,pageHeight); + } + break; + case 0x276: // Set relative vertical print position (ESC (v) + { + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)360.0; + Real64 newPos = curY + ((Real64)((Bit16s)PARAM16(2)) * unitSize); + if (newPos > topMargin) + { + if (newPos > bottomMargin) + newPage(true,false); + else + curY = newPos; + } + } + break; + default: + if (ESCCmd < 0x100); + //LOG(LOG_MISC,LOG_WARN) + //LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd); + else; + //LOG(LOG_MISC,LOG_WARN) + //LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200); + } + + ESCCmd = 0; + return true; + } + + switch (ch) + { + case 0x00: // NUL is ignored by the printer + return true; + case 0x07: // Beeper (BEL) + // BEEEP! + return true; + case 0x08: // Backspace (BS) + { + Real64 newX = curX - (1/(Real64)actcpi); + if (hmi > 0) + newX = curX - hmi; + if (newX >= leftMargin) + curX = newX; + } + return true; + case 0x09: // Tab horizontally (HT) + { + // Find tab right to current pos + Real64 moveTo = -1; + for (Bit8u i=0; i curX) + moveTo = horiztabs[i]; + // Nothing found => Ignore + if (moveTo > 0 && moveTo < rightMargin) + curX = moveTo; + } + return true; + case 0x0b: // Tab vertically (VT) + if (numVertTabs == 0) // All tabs cancelled => Act like CR + curX = leftMargin; + else if (numVertTabs == 255) // No tabs set since reset => Act like LF + { + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + } + else + { + // Find tab below current pos + Real64 moveTo = -1; + for (Bit8u i=0; i curY) + moveTo = verttabs[i]; + + // Nothing found => Act like FF + if (moveTo > bottomMargin || moveTo < 0) + newPage(true,false); + else + curY = moveTo; + } + if (style & STYLE_DOUBLEWIDTHONELINE) + { + style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + updateFont(); + } + return true; + case 0x0c: // Form feed (FF) + if (style & STYLE_DOUBLEWIDTHONELINE) + { + style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + updateFont(); + } + newPage(true,true); + return true; + case 0x0d: // Carriage Return (CR) + curX = leftMargin; + if (!autoFeed) + return true; + case 0x0a: // Line feed + if (style & STYLE_DOUBLEWIDTHONELINE) + { + style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + updateFont(); + } + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + return true; + case 0x0e: //Select Real64-width printing (one line) (SO) + if (!multipoint) + { + hmi = -1; + style |= STYLE_DOUBLEWIDTHONELINE; + updateFont(); + } + return true; + case 0x0f: // Select condensed printing (SI) + if (!multipoint && (cpi!=15.0)) { + hmi = -1; + style |= STYLE_CONDENSED; + updateFont(); + } + return true; + case 0x11: // Select printer (DC1) + // Ignore + return true; + case 0x12: // Cancel condensed printing (DC2) + hmi = -1; + style &= ~STYLE_CONDENSED; + updateFont(); + return true; + case 0x13: // Deselect printer (DC3) + // Ignore + return true; + case 0x14: // Cancel double-width printing (one line) (DC4) + hmi = -1; + style &= ~STYLE_DOUBLEWIDTHONELINE; + updateFont(); + return true; + case 0x18: // Cancel line (CAN) + return true; + case 0x1b: // ESC + ESCSeen = true; + return true; + case 0x1c: // FS (IBM commands) + FSSeen = true; + return true; + default: + return false; + } + + return false; +} +#endif // HAVE_SDL + +//static void PRINTER_EventHandler(Bitu param); + +void CPrinter::newPage(bool save, bool resetx) +{ + //PIC_RemoveEvents(PRINTER_EventHandler); + if(printer_timout) timeout_dirty=false; + +#ifdef HAVE_SDL + if (save) + outputPage(); + + if(resetx) curX=leftMargin; + curY = topMargin; + + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = page->w; + rect.h = page->h; + SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255)); + + /*for(int i = 0; i < 256; i++) + { + *((Bit8u*)page->pixels+i)=i; + }*/ +#endif // HAVE_SDL + if (strcasecmp(output, "text") == 0) { /* Text file */ + if (textPrinterFile) { + fclose(textPrinterFile); + textPrinterFile = NULL; + } + } +} + +void CPrinter::printChar(Bit8u ch) +{ +#ifdef HAVE_SDL + + charRead = true; + if (page == NULL) return; +#endif // HAVE_SDL + // Don't think that DOS programs uses this but well: Apply MSB if desired + if (msb != 255) { + if (msb == 0) ch &= 0x7F; + if (msb == 1) ch |= 0x80; + } + if (strcasecmp(output, "text") == 0) { + if (!textPrinterFile) { + textPrinterFile = fopen(textPrinterFileName,"ab"); + } + fprintf(textPrinterFile,"%c",ch); + fflush(textPrinterFile); + return; + } +#ifdef HAVE_SDL + + // Are we currently printing a bit graphic? + if (bitGraph.remBytes > 0) { + printBitGraph(ch); + return; + } + + // Print everything? + if (numPrintAsChar > 0) numPrintAsChar--; + else if (processCommandChar(ch)) return; + + // Do not print if no font is available + if (!curFont) return; + if(ch==0x1) ch=0x20; + + // Find the glyph for the char to render + FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]); + + // Load the glyph + FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT); + + // Render a high-quality bitmap + FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL); + + Bit16u penX = PIXX + curFont->glyph->bitmap_left; + Bit16u penY = PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender/64; + + if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2; + + // Copy bitmap into page + SDL_LockSurface(page); + + blitGlyph(curFont->glyph->bitmap, penX, penY, false); + blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); + + // Doublestrike => Print the glyph a second time one pixel below + if (style & STYLE_DOUBLESTRIKE) { + blitGlyph(curFont->glyph->bitmap, penX, penY+1, true); + blitGlyph(curFont->glyph->bitmap, penX+1, penY+1, true); + } + + // Bold => Print the glyph a second time one pixel to the right + // or be a bit more bold... + if (style & STYLE_BOLD) { + blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); + blitGlyph(curFont->glyph->bitmap, penX+2, penY, true); + blitGlyph(curFont->glyph->bitmap, penX+3, penY, true); + } + SDL_UnlockSurface(page); + + // For line printing + Bit16u lineStart = PIXX; + + // advance the cursor to the right + Real64 x_advance; + if (style & STYLE_PROP) + x_advance = (Real64)((Real64)(curFont->glyph->advance.x)/(Real64)(dpi*64)); + else { + if (hmi < 0) x_advance = 1/(Real64)actcpi; + else x_advance = hmi; + } + x_advance += extraIntraSpace; + curX += x_advance; + + // Draw lines if desired + if ((score != SCORE_NONE) && (style & + (STYLE_UNDERLINE|STYLE_STRIKETHROUGH|STYLE_OVERSCORE))) + { + // Find out where to put the line + Bit16u lineY = PIXY; + double height = (curFont->size->metrics.height>>6); // TODO height is fixed point madness... + + if (style & STYLE_UNDERLINE) lineY = PIXY + (Bit16u)(height*0.9); + else if (style & STYLE_STRIKETHROUGH) lineY = PIXY + (Bit16u)(height*0.45); + else if (style & STYLE_OVERSCORE) + lineY = PIXY - (((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN))?5:0); + + drawLine(lineStart, PIXX, lineY, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); + + // draw second line if needed + if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN)) + drawLine(lineStart, PIXX, lineY + 5, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); + } + // If the next character would go beyond the right margin, line-wrap. + if((curX + x_advance) > rightMargin) { + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) newPage(true,false); + } +#endif // HAVE_SDL +} + +#ifdef HAVE_SDL +void CPrinter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) { + for (Bitu y=0; y 0 && (destx+x < page->w) && (desty+y < page->h) ) { + Bit8u* target = (Bit8u*)page->pixels + (x+destx) + (y+desty)*page->pitch; + source>>=3; + + if (add) { + if (((*target)&0x1f )+ source > 31) *target |= (color|0x1f); + else { + *target += source; + *target |= color; + } + } + else *target = source|color; + } + } + } +} + +void CPrinter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken) +{ + SDL_LockSurface(page); + + Bitu breakmod = dpi / 15; + Bitu gapstart = (breakmod * 4)/5; + + // Draw anti-aliased line + for (Bitu x=fromx; x<=tox; x++) + { + // Skip parts if broken line or going over the border + if ((!broken || (x%breakmod <= gapstart)) && (x < page->w)) + { + if (y > 0 && (y-1) < page->h) + *((Bit8u*)page->pixels + x + (y-1)*page->pitch) = 240; + if (y < page->h) + *((Bit8u*)page->pixels + x + y*page->pitch) = !broken?255:240; + if (y+1 < page->h) + *((Bit8u*)page->pixels + x + (y+1)*page->pitch) = 240; + } + } + SDL_UnlockSurface(page); +} + +void CPrinter::setAutofeed(bool feed) { + autoFeed = feed; +} + +bool CPrinter::getAutofeed() { + return autoFeed; +} + +bool CPrinter::isBusy() { + // We're never busy + return false; +} + +bool CPrinter::ack() { + // Acknowledge last char read + if(charRead) { + charRead=false; + return true; + } + return false; +} + +void CPrinter::setupBitImage(Bit8u dens, Bit16u numCols) { + switch (dens) + { + case 0: + bitGraph.horizDens = 60; + bitGraph.vertDens = 60; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 1: + bitGraph.horizDens = 120; + bitGraph.vertDens = 60; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 2: + bitGraph.horizDens = 120; + bitGraph.vertDens = 60; + bitGraph.adjacent = false; + bitGraph.bytesColumn = 1; + break; + case 3: + bitGraph.horizDens = 60; + bitGraph.vertDens = 240; + bitGraph.adjacent = false; + bitGraph.bytesColumn = 1; + break; + case 4: + bitGraph.horizDens = 80; + bitGraph.vertDens = 60; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 6: + bitGraph.horizDens = 90; + bitGraph.vertDens = 60; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 32: + bitGraph.horizDens = 60; + bitGraph.vertDens = 180; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 33: + bitGraph.horizDens = 120; + bitGraph.vertDens = 180; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 38: + bitGraph.horizDens = 90; + bitGraph.vertDens = 180; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 39: + bitGraph.horizDens = 180; + bitGraph.vertDens = 180; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 40: + bitGraph.horizDens = 360; + bitGraph.vertDens = 180; + bitGraph.adjacent = false; + bitGraph.bytesColumn = 3; + break; + case 71: + bitGraph.horizDens = 180; + bitGraph.vertDens = 360; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 6; + break; + case 72: + bitGraph.horizDens = 360; + bitGraph.vertDens = 360; + bitGraph.adjacent = false; + bitGraph.bytesColumn = 6; + break; + case 73: + bitGraph.horizDens = 360; + bitGraph.vertDens = 360; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 6; + break; + default: + //break; + printf("PRINTER: Unsupported bit image density"); + } + + bitGraph.remBytes = numCols * bitGraph.bytesColumn; + bitGraph.readBytesColumn = 0; +} + +void CPrinter::printBitGraph(Bit8u ch) +{ + bitGraph.column[bitGraph.readBytesColumn++] = ch; + bitGraph.remBytes--; + + // Only print after reading a full column + if (bitGraph.readBytesColumn < bitGraph.bytesColumn) + return; + + Real64 oldY = curY; + + SDL_LockSurface(page); + + // When page dpi is greater than graphics dpi, the drawn pixels get "bigger" + Bitu pixsizeX=1; + Bitu pixsizeY=1; + if(bitGraph.adjacent) { + pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; + pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; + } + // TODO figure this out for 360dpi mode in windows + +// Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; +// Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; + + for (Bitu i=0; i>=1) { // for each bit + if (bitGraph.column[i] & j) { + for (Bitu xx=0; xxw) && ((PIXY + yy) < page->h)) + *((Bit8u*)page->pixels + (PIXX+xx) + (PIXY+yy)*page->pitch) |= (color|0x1F); + } + } // else white pixel + + curY += (Real64)1/(Real64)bitGraph.vertDens; // TODO line wrap? + } + } + SDL_UnlockSurface(page); + + curY = oldY; + + bitGraph.readBytesColumn = 0; + + // Advance to the left + curX += (Real64)1/(Real64)bitGraph.horizDens; +} +#endif // HAVE_SDL + +void CPrinter::formFeed() +{ +#ifdef HAVE_SDL + // Don't output blank pages + newPage(!isBlank(),true); + finishMultipage(); +#endif // HAVE_SDL +} + +#ifdef HAVE_SDL +static void findNextName(char* front, char* ext, char* fname) +{ + document_path = ""; + Bitu i = 1; + Bitu slen = strlen(document_path); + if(slen>(200-15)) { + fname[0]=0; + return; + } + FILE *test = NULL; + do + { + strcpy(fname, document_path); + printf(fname); +#ifdef WIN32 + const char* const pathstring = ".\\%s%d%s"; +#else + const char* const pathstring = "./%s%d%s"; +#endif + sprintf(fname+strlen(fname), pathstring, front,i++,ext); + test = fopen(fname, "rb"); + if (test != NULL) + fclose(test); + } + while (test != NULL ); +} + +void CPrinter::outputPage() +{ +/* SDL_Surface *screen; + +screen = SDL_SetVideoMode(1024, 768, 16, SDL_DOUBLEBUF | SDL_RESIZABLE); +if (screen == NULL) { + printf("Unable to set video mode: %s\n", SDL_GetError()); +} +SDL_Surface *image; +SDL_LockSurface(page); +image = SDL_DisplayFormat(page); +SDL_UnlockSurface(page); +SDL_Rect src, dest; + +src.x = 0; +src.y = 0; +src.w = image->w; +src.h = image->h; + +dest.x = 100; +dest.y = 100; +dest.w = image->w; +dest.h = image->h; + +SDL_BlitSurface(image, &src, screen, &dest); +SDL_Flip(screen); + +SDL_Delay(2000); +SDL_FreeSurface(image);*/ + + char fname[200]; + + if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + + Bit16u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH); + Bit16u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT); + + Real64 scaleW, scaleH; + + if (page->w > physW) + scaleW = (Real64)page->w / (Real64)physW; + else + scaleW = (Real64)physW / (Real64)page->w; + + if (page->h > physH) + scaleH = (Real64)page->h / (Real64)physH; + else + scaleH = (Real64)physH / (Real64)page->h; + + HDC memHDC = CreateCompatibleDC(printerDC); + BITMAPINFO *BitmapInfo; + HBITMAP bitmap; + + // Start new printer job? + if (outputHandle == NULL) + { + DOCINFO docinfo; + docinfo.cbSize = sizeof(docinfo); + docinfo.lpszDocName = "GSport Virtual Printer"; + docinfo.lpszOutput = NULL; + docinfo.lpszDatatype = NULL; + docinfo.fwType = 0; + + StartDoc(printerDC, &docinfo); + multiPageCounter = 1; + } + SDL_LockSurface(page); + StartPage(printerDC); + DWORD TotalSize; + HGDIOBJ Prev; + void* Pixels; + BitmapInfo = (BITMAPINFO*) + malloc (sizeof (BITMAPINFO)+255*sizeof (RGBQUAD)); + memset (BitmapInfo,0,sizeof (bitmap)); + BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + BitmapInfo->bmiHeader.biWidth = page->w; + BitmapInfo->bmiHeader.biHeight = -page->h; + BitmapInfo->bmiHeader.biPlanes = 1; + BitmapInfo->bmiHeader.biBitCount = page->format->BitsPerPixel; + BitmapInfo->bmiHeader.biCompression = BI_RGB; + BitmapInfo->bmiHeader.biSizeImage = page->h * page->pitch; + BitmapInfo->bmiHeader.biXPelsPerMeter = 0; + BitmapInfo->bmiHeader.biYPelsPerMeter = 0; + BitmapInfo->bmiHeader.biClrUsed = page->format->palette->ncolors; + BitmapInfo->bmiHeader.biClrImportant = 0; + if (page->format->palette) { + for (int I=0; Iformat->palette->ncolors; I++) { + BitmapInfo->bmiColors[I].rgbRed = + (page->format->palette->colors+I)->r; + BitmapInfo->bmiColors[I].rgbGreen = + (page->format->palette->colors+I)->g; + BitmapInfo->bmiColors[I].rgbBlue = + (page->format->palette->colors+I)->b; + } + } + memHDC = CreateCompatibleDC(printerDC); + if (memHDC) { + bitmap = CreateDIBSection(memHDC, BitmapInfo, DIB_RGB_COLORS, + (&Pixels), NULL, 0); + if (bitmap) { + memcpy (Pixels, page->pixels, + BitmapInfo->bmiHeader.biSizeImage); + Prev = SelectObject (memHDC, bitmap); + StretchBlt(printerDC, 0, 0, physW, physH, memHDC, 0, 0, page->w, page->h, SRCCOPY); + SelectObject (memHDC,Prev); + DeleteObject (bitmap); + } + } + free (BitmapInfo); + SDL_UnlockSurface(page); + EndPage(printerDC); + + if (multipageOutput) + { + multiPageCounter++; + outputHandle = printerDC; + } + else + { + EndDoc(printerDC); + outputHandle = NULL; + } + DeleteObject(bitmap); + DeleteDC(memHDC); +#else + //LOG_MSG("PRINTER: Direct printing not supported under this OS"); +#endif + } +#ifdef C_LIBPNG + else if (strcasecmp(output, "png") == 0) + { + // Find a page that does not exists + findNextName("page", ".png", &fname[0]); + + png_structp png_ptr; + png_infop info_ptr; + png_bytep * row_pointers; + png_color palette[256]; + Bitu i; + + /* Open the actual file */ + FILE * fp=fopen(fname,"wb"); + if (!fp) + { + //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); + return; + } + + /* First try to alloacte the png structures */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); + if (!png_ptr) return; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + return; + } + + /* Finalize the initing of png library */ + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192); + + + png_set_IHDR(png_ptr, info_ptr, page->w, page->h, + 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + for (i=0;i<256;i++) + { + palette[i].red = page->format->palette->colors[i].r; + palette[i].green = page->format->palette->colors[i].g; + palette[i].blue = page->format->palette->colors[i].b; + } + png_set_PLTE(png_ptr, info_ptr, palette,256); + png_set_packing(png_ptr); + SDL_LockSurface(page); + + // Allocate an array of scanline pointers + row_pointers = (png_bytep*)malloc(page->h*sizeof(png_bytep)); + for (i=0; ih; i++) + row_pointers[i] = ((Bit8u*)page->pixels+(i*page->pitch)); + + // tell the png library what to encode. + png_set_rows(png_ptr, info_ptr, row_pointers); + + // Write image to file + png_write_png(png_ptr, info_ptr, 0, NULL); + + + + + SDL_UnlockSurface(page); + + /*close file*/ + fclose(fp); + + /*Destroy PNG structs*/ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /*clean up dynamically allocated RAM.*/ + free(row_pointers); + } +#endif + else if (strcasecmp(output, "ps") == 0) + { + FILE* psfile = NULL; + + // Continue postscript file? + if (outputHandle != NULL) + psfile = (FILE*)outputHandle; + + // Create new file? + if (psfile == NULL) + { + if (!multipageOutput) + findNextName("page", ".ps", &fname[0]); + else + findNextName("doc", ".ps", &fname[0]); + + psfile = fopen(fname, "wb"); + if (!psfile) + { + printf("PRINTER: Can't open file %s for printer output", fname); + return; + } + + // Print header + fprintf(psfile, "%%!PS-Adobe-3.0\n"); + fprintf(psfile, "%%%%Pages: (atend)\n"); + fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); + fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n"); + fprintf(psfile, "%%%%DocumentData: Clean7Bit\n"); + fprintf(psfile, "%%%%LanguageLevel: 2\n"); + fprintf(psfile, "%%%%EndComments\n"); + multiPageCounter = 1; + } + + fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); + fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72)); + fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); + fprintf(psfile, "currentfile\n"); + fprintf(psfile, "/ASCII85Decode filter\n"); + fprintf(psfile, "/RunLengthDecode filter\n"); + fprintf(psfile, "image\n"); + + SDL_LockSurface(page); + + Bit32u pix = 0; + Bit32u numpix = page->h*page->w; + ASCII85BufferPos = ASCII85CurCol = 0; + + while (pix < numpix) + { + // Compress data using RLE + + if ((pix < numpix-2) && (getPixel(pix) == getPixel(pix+1)) && (getPixel(pix) == getPixel(pix+2))) + { + // Found three or more pixels with the same color + Bit8u sameCount = 3; + Bit8u col = getPixel(pix); + while (sameCount < 128 && sameCount+pix < numpix && col == getPixel(pix+sameCount)) + sameCount++; + + fprintASCII85(psfile, 257-sameCount); + fprintASCII85(psfile, 255-col); + + // Skip ahead + pix += sameCount; + } + else + { + // Find end of heterogenous area + Bit8u diffCount = 1; + while (diffCount < 128 && diffCount+pix < numpix && + ( + (diffCount+pix < numpix-2) + || (getPixel(pix+diffCount) != getPixel(pix+diffCount+1)) + || (getPixel(pix+diffCount) != getPixel(pix+diffCount+2)) + )) + diffCount++; + + fprintASCII85(psfile, diffCount-1); + for (Bit8u i=0; i= 79) + { + ASCII85CurCol = 0; + fprintf(f, "\n"); + } + } + else + { + char buffer[5]; + for (Bit8s i=4; i>=0; i--) + { + buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85); + buffer[i] += 33; + num /= (Bit32u)85; + } + + // Make sure a line never starts with a % (which may be mistaken as start of a comment) + if (ASCII85CurCol == 0 && buffer[0] == '%') + fprintf(f, " "); + + for (int i=0; i<((b != 257)?5:ASCII85BufferPos+1); i++) + { + fprintf(f, "%c", buffer[i]); + if (++ASCII85CurCol >= 79) + { + ASCII85CurCol = 0; + fprintf(f, "\n"); + } + } + } + + ASCII85BufferPos = 0; + } + + } + else // Close string + { + // Partial tupel if there are still bytes in the buffer + if (ASCII85BufferPos > 0) + { + for (Bit8u i = ASCII85BufferPos; i < 4; i++) + ASCII85Buffer[i] = 0; + + fprintASCII85(f, 257); + } + + fprintf(f, "~"); + fprintf(f, ">\n"); + } +} + +void CPrinter::finishMultipage() +{ + if (outputHandle != NULL) + { + if (strcasecmp(output, "ps") == 0) + { + FILE* psfile = (FILE*)outputHandle; + fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); + fprintf(psfile, "%%%%EOF\n"); + fclose(psfile); + } + else if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + EndDoc(printerDC); +#endif + } + outputHandle = NULL; + } +} + +bool CPrinter::isBlank() { + bool blank = true; + SDL_LockSurface(page); + + for (Bit16u y=0; yh; y++) + for (Bit16u x=0; xw; x++) + if (*((Bit8u*)page->pixels + x + (y*page->pitch)) != 0) + blank = false; + + SDL_UnlockSurface(page); + return blank; +} + +Bit8u CPrinter::getPixel(Bit32u num) { + Bit32u pixel = *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); + return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); +} +#endif // HAVE_SDL + +//Interfaces to C code + + +extern "C" void printer_init(int pdpi, int pwidth, int pheight, char* poutput, bool mpage) +{ + if (defaultPrinter != NULL) return; + defaultPrinter = new CPrinter(pdpi, pwidth,pheight, poutput, mpage); +} +extern "C" void printer_loop(Bit8u pchar) +{ + if (defaultPrinter == NULL) return; + defaultPrinter->printChar(pchar); +} + +extern "C" void printer_close() +{ + delete defaultPrinter; + defaultPrinter = NULL; +} +extern "C" void printer_feed() +{ + if(defaultPrinter == NULL) return; + defaultPrinter->formFeed(); +} diff --git a/src/printer.h b/src/printer.h index a4a80ad..2e624d0 100644 --- a/src/printer.h +++ b/src/printer.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2010 - 2014 by GSport contributors + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/printer_charmaps.h b/src/printer_charmaps.h index cb34121..b37c74b 100644 --- a/src/printer_charmaps.h +++ b/src/printer_charmaps.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/prodos.h b/src/prodos.h index d46ffb3..713a30f 100755 --- a/src/prodos.h +++ b/src/prodos.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/prodos_protos.h b/src/prodos_protos.h index 4cf50d9..b7f73e4 100755 --- a/src/prodos_protos.h +++ b/src/prodos_protos.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/protos.h b/src/protos.h index 6ce873c..2f55b48 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey diff --git a/src/protos_engine_c.h b/src/protos_engine_c.h index c2bfecc..f170531 100644 --- a/src/protos_engine_c.h +++ b/src/protos_engine_c.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/protos_macdriver.h b/src/protos_macdriver.h index 7cfb26a..a5f6842 100644 --- a/src/protos_macdriver.h +++ b/src/protos_macdriver.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/protos_macsnd_driver.h b/src/protos_macsnd_driver.h index 87e9eb4..e8ea792 100644 --- a/src/protos_macsnd_driver.h +++ b/src/protos_macsnd_driver.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/protos_windriver.h b/src/protos_windriver.h index ec34847..605269c 100644 --- a/src/protos_windriver.h +++ b/src/protos_windriver.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/protos_xdriver.h b/src/protos_xdriver.h index 0f9dc03..3b0a1f1 100644 --- a/src/protos_xdriver.h +++ b/src/protos_xdriver.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/resource b/src/resource index 13fcc90..11e8c2c 100644 --- a/src/resource +++ b/src/resource @@ -1,58 +1,58 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by gsport32.rc -// -#define IDD_ABOUT_DIALOG 101 -#define IDC_GSPORT32 102 -#define IDR_TOOLBAR 103 -#define IDD_DLG_DISKCONF 104 -#define IDR_ACCEL 105 -#define IDD_GSPORT32_KEY 106 -#define IDD_SPEEDDIALOG 117 -#define IDC_SLOW 1007 -#define IDC_CUSTOM 1008 -#define IDC_EDITCUSTOM 1009 -#define IDC_NORMAL 1010 -#define IDC_FASTEST 1011 -#define ID_TOOLBAR 5000 -#define ID_STATUSBAR 5001 -#define IDC_EDIT_S5D1 10051 -#define IDC_EDIT_S5D2 10052 -#define IDC_EDIT_S6D1 10061 -#define IDC_EDIT_S6D2 10062 -#define IDC_EDIT_S7D1 10071 -#define IDC_EDIT_S7D2 10072 -#define IDC_BTN_S5D1 11051 -#define IDC_BTN_S5D2 11052 -#define IDC_BTN_S6D1 11061 -#define IDC_BTN_S6D2 11062 -#define IDC_BTN_S7D1 11071 -#define IDC_BTN_S7D2 11072 -#define ID_HELP_ABOUT 40001 -#define ID_FILE_EXIT 40002 -#define ID_FILE_DISK 40003 -#define ID_FILE_SENDRESET 40004 -#define ID_FILE_JOYSTICK 40005 -#define ID_FILE_DEBUGSTAT 40006 -#define ID_FILE_SENDREBOOT 40007 -#define ID_FILE_FULLSCREEN 40012 -#define ID_FILE_SPEED 40013 -#define ID_HELP_KEY 40014 -#define ID_FILE_SEND_REBOOT 40014 -#define ID_Menu 40015 -#define ID_EMULATOR_FLUSHPRINTER 40016 -#define ID_FILE_FLUSHPRINTER 40017 -#define ID_SPEED_1MHZ 50001 -#define ID_SPEED_2MHZ 50002 -#define ID_SPEED_FMHZ 50003 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 116 -#define _APS_NEXT_COMMAND_VALUE 40018 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by gsport32.rc +// +#define IDD_ABOUT_DIALOG 101 +#define IDC_GSPORT32 102 +#define IDR_TOOLBAR 103 +#define IDD_DLG_DISKCONF 104 +#define IDR_ACCEL 105 +#define IDD_GSPORT32_KEY 106 +#define IDD_SPEEDDIALOG 117 +#define IDC_SLOW 1007 +#define IDC_CUSTOM 1008 +#define IDC_EDITCUSTOM 1009 +#define IDC_NORMAL 1010 +#define IDC_FASTEST 1011 +#define ID_TOOLBAR 5000 +#define ID_STATUSBAR 5001 +#define IDC_EDIT_S5D1 10051 +#define IDC_EDIT_S5D2 10052 +#define IDC_EDIT_S6D1 10061 +#define IDC_EDIT_S6D2 10062 +#define IDC_EDIT_S7D1 10071 +#define IDC_EDIT_S7D2 10072 +#define IDC_BTN_S5D1 11051 +#define IDC_BTN_S5D2 11052 +#define IDC_BTN_S6D1 11061 +#define IDC_BTN_S6D2 11062 +#define IDC_BTN_S7D1 11071 +#define IDC_BTN_S7D2 11072 +#define ID_HELP_ABOUT 40001 +#define ID_FILE_EXIT 40002 +#define ID_FILE_DISK 40003 +#define ID_FILE_SENDRESET 40004 +#define ID_FILE_JOYSTICK 40005 +#define ID_FILE_DEBUGSTAT 40006 +#define ID_FILE_SENDREBOOT 40007 +#define ID_FILE_FULLSCREEN 40012 +#define ID_FILE_SPEED 40013 +#define ID_HELP_KEY 40014 +#define ID_FILE_SEND_REBOOT 40014 +#define ID_Menu 40015 +#define ID_EMULATOR_FLUSHPRINTER 40016 +#define ID_FILE_FLUSHPRINTER 40017 +#define ID_SPEED_1MHZ 50001 +#define ID_SPEED_2MHZ 50002 +#define ID_SPEED_FMHZ 50003 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 116 +#define _APS_NEXT_COMMAND_VALUE 40018 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/resource.h b/src/resource.h index 289d009..a87daa0 100644 --- a/src/resource.h +++ b/src/resource.h @@ -1,57 +1,57 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by gsport32.rc -// -#define IDD_ABOUT_DIALOG 101 -#define IDC_GSPORT32 102 -#define IDR_TOOLBAR 103 -#define IDD_DLG_DISKCONF 104 -#define IDR_ACCEL 105 -#define IDD_GSPORT32_KEY 106 -#define ID_TOOLBAR 5000 -#define ID_STATUSBAR 5001 -#define IDC_EDIT_S5D1 10051 -#define IDC_EDIT_S5D2 10052 -#define IDC_EDIT_S6D1 10061 -#define IDC_EDIT_S6D2 10062 -#define IDC_EDIT_S7D1 10071 -#define IDC_EDIT_S7D2 10072 -#define IDC_BTN_S5D1 11051 -#define IDC_BTN_S5D2 11052 -#define IDC_BTN_S6D1 11061 -#define IDC_BTN_S6D2 11062 -#define IDC_BTN_S7D1 11071 -#define IDC_BTN_S7D2 11072 -#define ID_HELP_ABOUT 40001 -#define ID_FILE_EXIT 40002 -#define ID_FILE_DISK 40003 -#define ID_FILE_SENDRESET 40004 -#define ID_FILE_JOYSTICK 40005 -#define ID_FILE_DEBUGSTAT 40006 -#define ID_FILE_SENDREBOOT 40007 -#define ID_FILE_FULLSCREEN 40012 -#define ID_FILE_SPEED 40013 -#define ID_HELP_KEY 40014 -#define ID_SPEED_1MHZ 50001 -#define ID_SPEED_2MHZ 50002 -#define ID_SPEED_FMHZ 50003 - -#define IDD_SPEEDDIALOG 117 -#define IDC_SLOW 1007 -#define IDC_CUSTOM 1008 -#define IDC_EDITCUSTOM 1009 -#define IDC_NORMAL 1010 -#define IDC_FASTEST 1011 - -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 111 -#define _APS_NEXT_COMMAND_VALUE 40013 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gsport32.rc +// +#define IDD_ABOUT_DIALOG 101 +#define IDC_GSPORT32 102 +#define IDR_TOOLBAR 103 +#define IDD_DLG_DISKCONF 104 +#define IDR_ACCEL 105 +#define IDD_GSPORT32_KEY 106 +#define ID_TOOLBAR 5000 +#define ID_STATUSBAR 5001 +#define IDC_EDIT_S5D1 10051 +#define IDC_EDIT_S5D2 10052 +#define IDC_EDIT_S6D1 10061 +#define IDC_EDIT_S6D2 10062 +#define IDC_EDIT_S7D1 10071 +#define IDC_EDIT_S7D2 10072 +#define IDC_BTN_S5D1 11051 +#define IDC_BTN_S5D2 11052 +#define IDC_BTN_S6D1 11061 +#define IDC_BTN_S6D2 11062 +#define IDC_BTN_S7D1 11071 +#define IDC_BTN_S7D2 11072 +#define ID_HELP_ABOUT 40001 +#define ID_FILE_EXIT 40002 +#define ID_FILE_DISK 40003 +#define ID_FILE_SENDRESET 40004 +#define ID_FILE_JOYSTICK 40005 +#define ID_FILE_DEBUGSTAT 40006 +#define ID_FILE_SENDREBOOT 40007 +#define ID_FILE_FULLSCREEN 40012 +#define ID_FILE_SPEED 40013 +#define ID_HELP_KEY 40014 +#define ID_SPEED_1MHZ 50001 +#define ID_SPEED_2MHZ 50002 +#define ID_SPEED_FMHZ 50003 + +#define IDD_SPEEDDIALOG 117 +#define IDC_SLOW 1007 +#define IDC_CUSTOM 1008 +#define IDC_EDITCUSTOM 1009 +#define IDC_NORMAL 1010 +#define IDC_FASTEST 1011 + +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40013 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/scc.c b/src/scc.c index 67103d9..25296b4 100644 --- a/src/scc.c +++ b/src/scc.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2014 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -54,7 +56,7 @@ extern int g_appletalk_turbo; Scc scc_stat[2]; int g_baud_table[] = { - 110, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400 + 110, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400 }; static char* wr_names[] = { @@ -114,7 +116,7 @@ scc_init() scc_ptr->rx_event_pending = 0; scc_ptr->tx_event_pending = 0; scc_ptr->char_size = 8; - scc_ptr->baud_rate = 115200; + scc_ptr->baud_rate = 115200; scc_ptr->telnet_mode = 0; scc_ptr->telnet_iac = 0; scc_ptr->out_char_dcycs = 0.0; @@ -367,37 +369,37 @@ scc_regen_clocks(int port) scc_ptr->tx_dcycs = tx_dcycs * tx_char_size; scc_ptr->rx_dcycs = rx_dcycs * rx_char_size; - switch (scc_ptr->state) { - case 1: /* socket */ - scc_socket_change_params(port); - break; - case 2: /* real serial ports */ + switch (scc_ptr->state) { + case 1: /* socket */ + scc_socket_change_params(port); + break; + case 2: /* real serial ports */ #ifdef MAC scc_serial_mac_change_params(port); #endif #ifdef _WIN32 scc_serial_win_change_params(port); #endif - break; - case 3: /* localtalk */ - if (g_appletalk_turbo) - { - // If the user has selected AppleTalk "turbo" mode, increase the baud - // rate to be as fast as possible, limited primarily by the ability of - // the emulated GS to handle data. - scc_ptr->baud_rate = 0; - scc_ptr->br_dcycs = 1; - scc_ptr->tx_dcycs = 1; - scc_ptr->rx_dcycs = 1; - } - break; - case 4: /* Imagewriter */ - scc_ptr->baud_rate = 0; - scc_ptr->tx_dcycs = tx_dcycs * 1.2; //Somehow this speeds up serial transfer without overrunning the buffer - scc_ptr->rx_dcycs = rx_dcycs * 1.2; - break; + break; + case 3: /* localtalk */ + if (g_appletalk_turbo) + { + // If the user has selected AppleTalk "turbo" mode, increase the baud + // rate to be as fast as possible, limited primarily by the ability of + // the emulated GS to handle data. + scc_ptr->baud_rate = 0; + scc_ptr->br_dcycs = 1; + scc_ptr->tx_dcycs = 1; + scc_ptr->rx_dcycs = 1; + } + break; + case 4: /* Imagewriter */ + scc_ptr->baud_rate = 0; + scc_ptr->tx_dcycs = tx_dcycs * 1.2; //Somehow this speeds up serial transfer without overrunning the buffer + scc_ptr->rx_dcycs = rx_dcycs * 1.2; + break; } - + } void @@ -416,9 +418,9 @@ scc_port_init(int port) state = scc_serial_win_init(port); #endif break; - case 2: - state = scc_imagewriter_init(port); - break; + case 2: + state = scc_imagewriter_init(port); + break; default: break; } @@ -455,15 +457,15 @@ scc_try_to_empty_writebuf(int port, double dcycs) case 1: scc_socket_empty_writebuf(port, dcycs); - break; - - case 3: - // When we're doing LocalTalk, the write buffer gets emptied at the end of the frame and does not use this function. - break; - - case 4: - scc_imagewriter_empty_writebuf(port, dcycs); - break; + break; + + case 3: + // When we're doing LocalTalk, the write buffer gets emptied at the end of the frame and does not use this function. + break; + + case 4: + scc_imagewriter_empty_writebuf(port, dcycs); + break; } } @@ -509,21 +511,21 @@ scc_try_fill_readbuf(int port, double dcycs) case 1: scc_socket_fill_readbuf(port, space_left, dcycs); - break; - - case 3: - // LLAP deals with packets, and we only allow one packet in the read buffer at a time. - // If the buffer is empty, try to fill it with another packet. - if (g_appletalk_bridging && (space_used_before_rx == 0) && (scc_ptr->rx_queue_depth == 0) && !(scc_ptr->sdlc_eof)) - { - scc_llap_fill_readbuf(port, space_left, dcycs); - //scc_maybe_rx_event(port, dcycs); - scc_ptr->sdlc_eof = 0; - break; - - case 4: - scc_imagewriter_fill_readbuf(port, space_left, dcycs); - break; + break; + + case 3: + // LLAP deals with packets, and we only allow one packet in the read buffer at a time. + // If the buffer is empty, try to fill it with another packet. + if (g_appletalk_bridging && (space_used_before_rx == 0) && (scc_ptr->rx_queue_depth == 0) && !(scc_ptr->sdlc_eof)) + { + scc_llap_fill_readbuf(port, space_left, dcycs); + //scc_maybe_rx_event(port, dcycs); + scc_ptr->sdlc_eof = 0; + break; + + case 4: + scc_imagewriter_fill_readbuf(port, space_left, dcycs); + break; } break; } diff --git a/src/scc.h b/src/scc.h index 8e0173f..b69a777 100644 --- a/src/scc.h +++ b/src/scc.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/scc_imagewriter.c b/src/scc_imagewriter.c index 48616c7..be9d9b1 100644 --- a/src/scc_imagewriter.c +++ b/src/scc_imagewriter.c @@ -1,159 +1,161 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2013 - 2014 by GSport contributors - Originally authored by Christopher Mason - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is an interface between the SCC emulation and the Virtual Imagewriter. */ - -#include "defc.h" -#include "scc.h" -#include "imagewriter.h" -extern Scc scc_stat[2]; -extern word32 g_vbl_count; - -extern int g_imagewriter; -extern int g_imagewriter_dpi; -extern char* g_imagewriter_output; -extern int g_imagewriter_multipage; -extern int g_imagewriter_timeout; -extern int g_imagewriter_paper; -extern int g_imagewriter_banner; - -word32 imagewriter_vbl_count = 0; -int imagewriter_port_block = 0; -int iw_scc_write = 0; - -int scc_imagewriter_init(int port) -{ - Scc *scc_ptr; - scc_ptr = &(scc_stat[port]); - imagewriter_init(g_imagewriter_dpi,g_imagewriter_paper,g_imagewriter_banner,g_imagewriter_output,g_imagewriter_multipage); - scc_ptr->state = 4; - return 4; -} - -/** Transfer data from Imagewriter to the SCC **/ -void scc_imagewriter_fill_readbuf(int port, int space_left, double dcycs) -{ - if (iw_scc_write) - { - size_t bytes_read; - size_t i; - byte data[9]; - if (g_imagewriter == 1) - { - //Imagewriter LQ self ID string. Tell machine we have a color ribbon and sheet feeder installed. - data[0] = 0; //Start bit - data[1] ='L'; //Printer type is Imagewriter LQ - data[2] ='Q'; //(cont) - data[3] ='1'; //15 inch carriage width - data[4] ='C'; //Color ribbon installed - data[5] ='F'; //Sheet feeder installed, no envelope attachment - data[6] ='1'; //Number of sheet feeder bins - data[7] = 0x0D; //CR terminates string - data[8] = 0; //Stop bit - bytes_read = 9; - } - else - { - //Imagewriter II self ID string. Tell machine we have a color ribbon and sheet feeder installed. - data[0] = 0; //Start bit - data[1] ='I'; //Printer type is Imagewriter II - data[2] ='W'; //(cont) - data[3] ='1'; //10 inch carriage width - data[4] ='0'; //(cont) - data[5] ='C'; //Color ribbon installed - data[6] ='F'; //Sheet feeder installed - data[7] = 0; //Stop bit - bytes_read = 8; - } - for(i = 0; i < bytes_read; i++) { - scc_add_to_readbuf(port, data[i], dcycs); - } - iw_scc_write = 0; - } -} - -/** Transfer data from the SCC to the Imagewriter. **/ -void scc_imagewriter_empty_writebuf(int port, double dcycs) -{ - Scc* scc_ptr; - - int rdptr; - int wrptr; - int len; - int done; - //int ret; - unsigned long bytes_written; - - scc_ptr = &(scc_stat[port]); - done = 0; - while(!done) { - rdptr = scc_ptr->out_rdptr; - wrptr = scc_ptr->out_wrptr; - if(rdptr == wrptr) { - //printf("...rdptr == wrptr\n"); - done = 1; - break; - } - len = wrptr - rdptr; - if(len < 0) { - len = SCC_OUTBUF_SIZE - rdptr; - } - if(len > 32) { - len = 32; - } - if(len <= 0) { - done = 1; - break; - } - bytes_written = 1; - imagewriter_port_block = 1; - imagewriter_loop(scc_ptr->out_buf[rdptr]); - imagewriter_vbl_count = g_vbl_count+(g_imagewriter_timeout*60); - imagewriter_port_block = 0; - //printf("Write Imagewriter ret: %d, bytes_written:%d, len:%d\n", ret, - //(int)bytes_written, len); - - if (bytes_written == 0) { - done = 1; - break; - } else { - rdptr = rdptr + bytes_written; - if(rdptr >= SCC_OUTBUF_SIZE) { - rdptr = rdptr - SCC_OUTBUF_SIZE; - } - scc_ptr->out_rdptr = rdptr; - } - } -} - -//This function handles the automatic timeout of the virtual printer if an -//application doesn't send a form feed at the end of the page. It also -//allows multipage mode Postscript and native printer documents to -//print somewhat how a regular application would. -void imagewriter_update() -{ - if (imagewriter_port_block != 1 && imagewriter_vbl_count != 0 && g_vbl_count >= imagewriter_vbl_count) - { - printf("Calling imagewriter_update and flushing!\n"); - imagewriter_feed(); - imagewriter_vbl_count = 0; - } - return; -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2013 - 2014 by GSport contributors + Originally authored by Christopher Mason + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* This is an interface between the SCC emulation and the Virtual Imagewriter. */ + +#include "defc.h" +#include "scc.h" +#include "imagewriter.h" +extern Scc scc_stat[2]; +extern word32 g_vbl_count; + +extern int g_imagewriter; +extern int g_imagewriter_dpi; +extern char* g_imagewriter_output; +extern int g_imagewriter_multipage; +extern int g_imagewriter_timeout; +extern int g_imagewriter_paper; +extern int g_imagewriter_banner; + +word32 imagewriter_vbl_count = 0; +int imagewriter_port_block = 0; +int iw_scc_write = 0; + +int scc_imagewriter_init(int port) +{ + Scc *scc_ptr; + scc_ptr = &(scc_stat[port]); + imagewriter_init(g_imagewriter_dpi,g_imagewriter_paper,g_imagewriter_banner,g_imagewriter_output,g_imagewriter_multipage); + scc_ptr->state = 4; + return 4; +} + +/** Transfer data from Imagewriter to the SCC **/ +void scc_imagewriter_fill_readbuf(int port, int space_left, double dcycs) +{ + if (iw_scc_write) + { + size_t bytes_read; + size_t i; + byte data[9]; + if (g_imagewriter == 1) + { + //Imagewriter LQ self ID string. Tell machine we have a color ribbon and sheet feeder installed. + data[0] = 0; //Start bit + data[1] ='L'; //Printer type is Imagewriter LQ + data[2] ='Q'; //(cont) + data[3] ='1'; //15 inch carriage width + data[4] ='C'; //Color ribbon installed + data[5] ='F'; //Sheet feeder installed, no envelope attachment + data[6] ='1'; //Number of sheet feeder bins + data[7] = 0x0D; //CR terminates string + data[8] = 0; //Stop bit + bytes_read = 9; + } + else + { + //Imagewriter II self ID string. Tell machine we have a color ribbon and sheet feeder installed. + data[0] = 0; //Start bit + data[1] ='I'; //Printer type is Imagewriter II + data[2] ='W'; //(cont) + data[3] ='1'; //10 inch carriage width + data[4] ='0'; //(cont) + data[5] ='C'; //Color ribbon installed + data[6] ='F'; //Sheet feeder installed + data[7] = 0; //Stop bit + bytes_read = 8; + } + for(i = 0; i < bytes_read; i++) { + scc_add_to_readbuf(port, data[i], dcycs); + } + iw_scc_write = 0; + } +} + +/** Transfer data from the SCC to the Imagewriter. **/ +void scc_imagewriter_empty_writebuf(int port, double dcycs) +{ + Scc* scc_ptr; + + int rdptr; + int wrptr; + int len; + int done; + //int ret; + unsigned long bytes_written; + + scc_ptr = &(scc_stat[port]); + done = 0; + while(!done) { + rdptr = scc_ptr->out_rdptr; + wrptr = scc_ptr->out_wrptr; + if(rdptr == wrptr) { + //printf("...rdptr == wrptr\n"); + done = 1; + break; + } + len = wrptr - rdptr; + if(len < 0) { + len = SCC_OUTBUF_SIZE - rdptr; + } + if(len > 32) { + len = 32; + } + if(len <= 0) { + done = 1; + break; + } + bytes_written = 1; + imagewriter_port_block = 1; + imagewriter_loop(scc_ptr->out_buf[rdptr]); + imagewriter_vbl_count = g_vbl_count+(g_imagewriter_timeout*60); + imagewriter_port_block = 0; + //printf("Write Imagewriter ret: %d, bytes_written:%d, len:%d\n", ret, + //(int)bytes_written, len); + + if (bytes_written == 0) { + done = 1; + break; + } else { + rdptr = rdptr + bytes_written; + if(rdptr >= SCC_OUTBUF_SIZE) { + rdptr = rdptr - SCC_OUTBUF_SIZE; + } + scc_ptr->out_rdptr = rdptr; + } + } +} + +//This function handles the automatic timeout of the virtual printer if an +//application doesn't send a form feed at the end of the page. It also +//allows multipage mode Postscript and native printer documents to +//print somewhat how a regular application would. +void imagewriter_update() +{ + if (imagewriter_port_block != 1 && imagewriter_vbl_count != 0 && g_vbl_count >= imagewriter_vbl_count) + { + printf("Calling imagewriter_update and flushing!\n"); + imagewriter_feed(); + imagewriter_vbl_count = 0; + } + return; +} diff --git a/src/scc_llap.c b/src/scc_llap.c index cb2915b..6c5ad1a 100644 --- a/src/scc_llap.c +++ b/src/scc_llap.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2013 - 2014 by GSport contributors Originally authored by Peter Neubauer @@ -162,4 +164,4 @@ void scc_llap_fill_readbuf(int port, int space_left, double dcycs) void scc_llap_empty_writebuf(int port, double dcycs) { } -#endif \ No newline at end of file +#endif diff --git a/src/scc_llap.h b/src/scc_llap.h index ced6672..9a33164 100644 --- a/src/scc_llap.h +++ b/src/scc_llap.h @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment +Copyright (C) 2016 - Dagen Brock + Copyright (C) 2013 by GSport contributors Originally authored by Peter Neubauer @@ -23,4 +25,4 @@ void scc_llap_shutdown(); void scc_llap_update(); void scc_llap_fill_readbuf(int port, int space_left, double dcycs); void scc_llap_empty_writebuf(int port, double dcycs); -void scc_llap_set_node(byte val); \ No newline at end of file +void scc_llap_set_node(byte val); diff --git a/src/scc_macdriver.c b/src/scc_macdriver.c index d79a41d..7a5964e 100644 --- a/src/scc_macdriver.c +++ b/src/scc_macdriver.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/scc_socket_driver.c b/src/scc_socket_driver.c index fd91f11..bfb83fc 100644 --- a/src/scc_socket_driver.c +++ b/src/scc_socket_driver.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -27,10 +29,10 @@ #include #ifndef UNDER_CE //OG #include -#endif -#ifdef __CYGWIN__ -#include -#endif +#endif +#ifdef __CYGWIN__ +#include +#endif extern Scc scc_stat[2]; extern int g_serial_modem[]; diff --git a/src/scc_windriver.c b/src/scc_windriver.c index 647ffb7..c8fbdb3 100644 --- a/src/scc_windriver.c +++ b/src/scc_windriver.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it @@ -25,7 +27,7 @@ #include "scc.h" #ifdef __CYGWIN__ -#include +#include #include #endif diff --git a/src/sdlsnd_driver.c b/src/sdlsnd_driver.c index 70b4a85..733eac7 100644 --- a/src/sdlsnd_driver.c +++ b/src/sdlsnd_driver.c @@ -1,6 +1,8 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -34,7 +36,7 @@ void check_wave_error(int res, char *str); #define NUM_WAVE_HEADERS 8 -//HWAVEOUT g_wave_handle = NULL; // OG Default value must be set +//HWAVEOUT g_wave_handle = NULL; // OG Default value must be set //WAVEHDR g_wavehdr[NUM_WAVE_HEADERS]; extern int g_audio_enable; @@ -93,123 +95,123 @@ win32snd_init(word32 *shmaddr) return; } - -void sdl_send_audio(word32 *ptr, int size, int real_samps) { - - /* code */ - //printf(" sdl_s_a %d\t 0x%08x ",size, &ptr); - int i; - for (i=0; ig_sdlsnd_buflen) { - g_sdlsnd_write_idx=0; - } - } - g_playbuf_buffered += size; - -} - -void handle_sdl_snd(void *userdata, Uint8 *stream, int len) { - /* Only play if we have data left */ -/* if ( g_playbuf_buffered == 0) { - return; - } -*/ - for(int i = 0; i < len; ++i) { - if(g_playbuf_buffered <= 0) { - stream[i] = 0; - } else { - stream[i] = bptr[g_sdlsnd_read_idx++]; - if(g_sdlsnd_read_idx == g_sdlsnd_buflen) - g_sdlsnd_read_idx = 0; - g_playbuf_buffered--; - } - } - return; - - - /* Mix as much data as possible */ - len = ( len > g_playbuf_buffered ? g_playbuf_buffered : len ); - //len = ( g_sdlsnd_read_idx+len < g_sdlsnd_buflen ? len : g_sdlsnd_read_idx+len); - SDL_memset(stream, 0, len); - if (g_sdlsnd_read_idx+len < g_sdlsnd_buflen) { - SDL_memcpy (stream, &bptr[g_sdlsnd_read_idx], len); - g_sdlsnd_read_idx += len; - g_playbuf_buffered -= len; - } else { - /* - int top_len = 0; - top_len = g_sdlsnd_buflen - g_sdlsnd_read_idx; - SDL_memcpy (stream, &bptr[g_sdlsnd_read_idx], top_len); - g_sdlsnd_read_idx = 0; - g_playbuf_buffered -= top_len; - // SDL_memcpy (stream+top_len, bptr[g_sdlsnd_read_idx], len-top_len); - g_sdlsnd_read_idx += len-top_len; - g_playbuf_buffered -= len-top_len; - */ - } - - //SDL_MixAudio(stream, pointer, len, SDL_MIX_MAXVOLUME); - -} - - -void -child_sound_init_sdl() -{ - printf("child_sound_init_sdl"); - - SDL_memset(&want, 0, sizeof(want)); // or SDL_zero(want) - want.freq = g_preferred_rate; // 48000 ? - want.format = AUDIO_S16SYS; // AUDIO_F32 - want.channels = NUM_CHANNELS; //2 - want.samples = 512; //4096 - want.callback = handle_sdl_snd; // you wrote this function elsewhere. - - dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE); - if (dev == 0) { - printf("Failed to open audio: %s\n", SDL_GetError()); - } else { - if (have.format != want.format) { // we let this one thing change. - printf("We didn't get Float32 audio format.\n"); - } - - } - - // super experimental unknown - - g_playbuf_buffered = 0; // init buffered state - - int blen; - blen = (SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE * 2); // *2 unnecessary? - g_sdlsnd_buflen = blen; - bptr = (byte*)malloc(blen); - if(bptr == NULL) { - printf("Unabled to allocate sound buffer\n"); - exit(1); - } - memset(bptr, 0, SOUND_SHM_SAMP_SIZE*SAMPLE_CHAN_SIZE *2); // zero out the buffer - - g_sdlsnd_write_idx = 0; // initialize - g_sdlsnd_read_idx = 0; - - SDL_PauseAudioDevice(dev, 0); // start audio playing. - - g_audio_rate = have.freq; - printf("g_audio_rate: %d\n", g_audio_rate); - set_audio_rate(g_audio_rate); // let kegs simulator know the rate -} - - - - -void -sdlsnd_shutdown() { - //SDL_Delay(5000); // let the audio callback play some sound for 5 seconds. - SDL_CloseAudioDevice(dev); - printf("sdlsnd_shutdown"); -} + +void sdl_send_audio(word32 *ptr, int size, int real_samps) { + + /* code */ + //printf(" sdl_s_a %d\t 0x%08x ",size, &ptr); + int i; + for (i=0; ig_sdlsnd_buflen) { + g_sdlsnd_write_idx=0; + } + } + g_playbuf_buffered += size; + +} + +void handle_sdl_snd(void *userdata, Uint8 *stream, int len) { + /* Only play if we have data left */ +/* if ( g_playbuf_buffered == 0) { + return; + } +*/ + for(int i = 0; i < len; ++i) { + if(g_playbuf_buffered <= 0) { + stream[i] = 0; + } else { + stream[i] = bptr[g_sdlsnd_read_idx++]; + if(g_sdlsnd_read_idx == g_sdlsnd_buflen) + g_sdlsnd_read_idx = 0; + g_playbuf_buffered--; + } + } + return; + + + /* Mix as much data as possible */ + len = ( len > g_playbuf_buffered ? g_playbuf_buffered : len ); + //len = ( g_sdlsnd_read_idx+len < g_sdlsnd_buflen ? len : g_sdlsnd_read_idx+len); + SDL_memset(stream, 0, len); + if (g_sdlsnd_read_idx+len < g_sdlsnd_buflen) { + SDL_memcpy (stream, &bptr[g_sdlsnd_read_idx], len); + g_sdlsnd_read_idx += len; + g_playbuf_buffered -= len; + } else { + /* + int top_len = 0; + top_len = g_sdlsnd_buflen - g_sdlsnd_read_idx; + SDL_memcpy (stream, &bptr[g_sdlsnd_read_idx], top_len); + g_sdlsnd_read_idx = 0; + g_playbuf_buffered -= top_len; + // SDL_memcpy (stream+top_len, bptr[g_sdlsnd_read_idx], len-top_len); + g_sdlsnd_read_idx += len-top_len; + g_playbuf_buffered -= len-top_len; + */ + } + + //SDL_MixAudio(stream, pointer, len, SDL_MIX_MAXVOLUME); + +} + + +void +child_sound_init_sdl() +{ + printf("child_sound_init_sdl"); + + SDL_memset(&want, 0, sizeof(want)); // or SDL_zero(want) + want.freq = g_preferred_rate; // 48000 ? + want.format = AUDIO_S16SYS; // AUDIO_F32 + want.channels = NUM_CHANNELS; //2 + want.samples = 512; //4096 + want.callback = handle_sdl_snd; // you wrote this function elsewhere. + + dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE); + if (dev == 0) { + printf("Failed to open audio: %s\n", SDL_GetError()); + } else { + if (have.format != want.format) { // we let this one thing change. + printf("We didn't get Float32 audio format.\n"); + } + + } + + // super experimental unknown + + g_playbuf_buffered = 0; // init buffered state + + int blen; + blen = (SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE * 2); // *2 unnecessary? + g_sdlsnd_buflen = blen; + bptr = (byte*)malloc(blen); + if(bptr == NULL) { + printf("Unabled to allocate sound buffer\n"); + exit(1); + } + memset(bptr, 0, SOUND_SHM_SAMP_SIZE*SAMPLE_CHAN_SIZE *2); // zero out the buffer + + g_sdlsnd_write_idx = 0; // initialize + g_sdlsnd_read_idx = 0; + + SDL_PauseAudioDevice(dev, 0); // start audio playing. + + g_audio_rate = have.freq; + printf("g_audio_rate: %d\n", g_audio_rate); + set_audio_rate(g_audio_rate); // let kegs simulator know the rate +} + + + + +void +sdlsnd_shutdown() { + //SDL_Delay(5000); // let the audio callback play some sound for 5 seconds. + SDL_CloseAudioDevice(dev); + printf("sdlsnd_shutdown"); +} diff --git a/src/sdlsnd_driver2.c b/src/sdlsnd_driver2.c index 1af5f43..b14c80f 100644 --- a/src/sdlsnd_driver2.c +++ b/src/sdlsnd_driver2.c @@ -1,3 +1,22 @@ +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "SDL.h" #include "defc.h" diff --git a/src/sim65816.c b/src/sim65816.c index 68d212f..df3e5cd 100644 --- a/src/sim65816.c +++ b/src/sim65816.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2014 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -27,7 +29,7 @@ #include "tfe/protos_tfe.h" #endif #include "printer.h" - #include "imagewriter.h" + #include "imagewriter.h" #ifdef UNDER_CE #define vsnprintf _vsnprintf @@ -43,9 +45,9 @@ extern void get_cwd(LPTSTR buffer, int size); #define PC_LOG_LEN (8*1024) -int g_speed_fast ; // OG Expose fast parameter -int g_initialized = 0; // OG To know if the emulator has finalized its initialization -int g_accept_events = 0; // OG To know if the emulator is ready to accept external events +int g_speed_fast ; // OG Expose fast parameter +int g_initialized = 0; // OG To know if the emulator has finalized its initialization +int g_accept_events = 0; // OG To know if the emulator is ready to accept external events char g_argv0_path[256] = "./"; @@ -151,10 +153,10 @@ char* g_imagewriter_output = "bmp"; int g_imagewriter_multipage = 0; int g_imagewriter_timeout = 2; char* g_imagewriter_fixed_font = "lib/letgothl.ttf"; -char* g_imagewriter_prop_font = "lib/letgothl.ttf"; +char* g_imagewriter_prop_font = "lib/letgothl.ttf"; int g_imagewriter_paper = 0; -int g_imagewriter_banner = 0; - +int g_imagewriter_banner = 0; + int g_config_iwm_vbl_count = 0; extern const char g_gsport_version_str[] = "0.31"; int g_pause=0; // OG Added pause @@ -214,13 +216,13 @@ byte *g_dummy_memory1_ptr = 0; byte *g_rom_fc_ff_ptr = 0; byte *g_rom_cards_ptr = 0; -// OG Added allocated pointers -byte *g_slow_memory_ptr_allocated = 0; -byte *g_memory_ptr_allocated = 0; -byte *g_dummy_memory1_ptr_allocated = 0; -byte *g_rom_fc_ff_ptr_allocated = 0; -byte *g_rom_cards_ptr_allocated = 0; - +// OG Added allocated pointers +byte *g_slow_memory_ptr_allocated = 0; +byte *g_memory_ptr_allocated = 0; +byte *g_dummy_memory1_ptr_allocated = 0; +byte *g_rom_fc_ff_ptr_allocated = 0; +byte *g_rom_cards_ptr_allocated = 0; + void *g_memory_alloc_ptr = 0; /* for freeing memory area */ Page_info page_info_rd_wr[2*65536 + PAGE_INFO_PAD_SIZE]; @@ -236,69 +238,69 @@ Data_log *g_log_data_ptr = &(g_data_log_array[0]); Data_log *g_log_data_start_ptr = &(g_data_log_array[0]); Data_log *g_log_data_end_ptr = &(g_data_log_array[PC_LOG_LEN]); -// OG Added sim65816_initglobals() -void sim65816_initglobals() -{ +// OG Added sim65816_initglobals() +void sim65816_initglobals() +{ + + g_fcycles_stop = 0.0; + halt_sim = 0; + enter_debug = 0; + g_rom_version = -1; + g_user_halt_bad = 0; + g_halt_on_bad_read = 0; + g_ignore_bad_acc = 1; + g_ignore_halts = 1; + g_code_red = 0; + g_code_yellow = 0; + g_use_alib = 0; + g_iw2_emul = 0; + g_serial_out_masking = 0; + //g_serial_modem[2] = { 0, 1 }; + + g_config_iwm_vbl_count = 0; + + g_pause=0; + + g_last_vbl_dcycs = START_DCYCS; + g_cur_dcycs = START_DCYCS; + + g_last_vbl_dadjcycs = 0.0; + g_dadjcycs = 0.0; + + + g_wait_pending = 0; + g_stp_pending = 0; + + g_num_irq = 0; + g_num_brk = 0; + g_num_cop = 0; + g_num_enter_engine = 0; + g_io_amt = 0; + g_engine_action = 0; + g_engine_halt_event = 0; + g_engine_scan_int = 0; + g_engine_doc_int = 0; + + g_testing = 0; + g_testing_enabled = 0; + + g_debug_file_fd = -1; + g_fatal_log = -1; + + g_25sec_cntr = 0; + g_1sec_cntr = 0; + + g_dnatcycs_1sec = 0.0; + g_natcycs_lastvbl = 0; + + Verbose = 0; + Halt_on = 0; + + g_mem_size_base = 256*1024; /* size of motherboard memory */ + g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ + g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ +} - g_fcycles_stop = 0.0; - halt_sim = 0; - enter_debug = 0; - g_rom_version = -1; - g_user_halt_bad = 0; - g_halt_on_bad_read = 0; - g_ignore_bad_acc = 1; - g_ignore_halts = 1; - g_code_red = 0; - g_code_yellow = 0; - g_use_alib = 0; - g_iw2_emul = 0; - g_serial_out_masking = 0; - //g_serial_modem[2] = { 0, 1 }; - - g_config_iwm_vbl_count = 0; - - g_pause=0; - - g_last_vbl_dcycs = START_DCYCS; - g_cur_dcycs = START_DCYCS; - - g_last_vbl_dadjcycs = 0.0; - g_dadjcycs = 0.0; - - - g_wait_pending = 0; - g_stp_pending = 0; - - g_num_irq = 0; - g_num_brk = 0; - g_num_cop = 0; - g_num_enter_engine = 0; - g_io_amt = 0; - g_engine_action = 0; - g_engine_halt_event = 0; - g_engine_scan_int = 0; - g_engine_doc_int = 0; - - g_testing = 0; - g_testing_enabled = 0; - - g_debug_file_fd = -1; - g_fatal_log = -1; - - g_25sec_cntr = 0; - g_1sec_cntr = 0; - - g_dnatcycs_1sec = 0.0; - g_natcycs_lastvbl = 0; - - Verbose = 0; - Halt_on = 0; - - g_mem_size_base = 256*1024; /* size of motherboard memory */ - g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ - g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ -} - void show_pc_log() { @@ -427,7 +429,7 @@ toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr) pos = g_toolbox_log_pos; stack += 9; - g_toolbox_log_array[pos][0] = (word32)(g_last_vbl_dcycs + *cyc_ptr); + g_toolbox_log_array[pos][0] = (word32)(g_last_vbl_dcycs + *cyc_ptr); g_toolbox_log_array[pos][1] = stack+1; g_toolbox_log_array[pos][2] = xreg; g_toolbox_log_array[pos][3] = toolbox_debug_4byte(stack+1); @@ -718,30 +720,30 @@ show_regs() show_regs_act(&engine); } -//OG for regular exit, use quitEmulator() - -void quitEmulator() +//OG for regular exit, use quitEmulator() + +void quitEmulator() { - printf("set_halt(HALT_WANTTOQUIT)\n"); - set_halt(HALT_WANTTOQUIT); -} - -//OG change exit to fatal_exit() - -#ifndef ACTIVEGS - // use standard exit function - #define fatalExit exit -#else - extern void fatalExit(int); + printf("set_halt(HALT_WANTTOQUIT)\n"); + set_halt(HALT_WANTTOQUIT); +} + +//OG change exit to fatal_exit() + +#ifndef ACTIVEGS + // use standard exit function + #define fatalExit exit +#else + extern void fatalExit(int); #endif - -void my_exit(int ret) -{ - end_screen(); - imagewriter_close(); + +void my_exit(int ret) +{ + end_screen(); + imagewriter_close(); printer_close(); - printf("exiting (ret=%d)\n",ret); - fatalExit(ret); + printf("exiting (ret=%d)\n",ret); + fatalExit(ret); } @@ -786,9 +788,9 @@ do_reset() g_stepping = 0; - if (g_irq_pending) - halt_printf("*** irq remainings...\n"); - + if (g_irq_pending) + halt_printf("*** irq remainings...\n"); + } #define CHECK(start, var, value, var1, var2) \ @@ -851,7 +853,7 @@ memalloc_align(int size, int skip_amt, void **alloc_ptr) word32 offset; skip_amt = MAX(256, skip_amt); - bptr = (byte*)calloc(size + skip_amt + 256, 1); // OG Added cast + bptr = (byte*)calloc(size + skip_amt + 256, 1); // OG Added cast if(alloc_ptr) { /* Save allocation address */ *alloc_ptr = bptr; @@ -876,34 +878,34 @@ memory_ptr_init() /* changes this will be called */ mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); g_mem_size_total = mem_size; - - // OG using memory_ptr_shut() instead - memory_ptr_shut(); - /* + + // OG using memory_ptr_shut() instead + memory_ptr_shut(); + /* if(g_memory_alloc_ptr) { free(g_memory_alloc_ptr); g_memory_alloc_ptr = 0; } - */ + */ g_memory_ptr = memalloc_align(mem_size, 256, &g_memory_alloc_ptr); printf("RAM size is 0 - %06x (%.2fMB)\n", mem_size, (double)mem_size/(1024.0*1024.0)); } -// OG Added memory_ptr_shut -void -memory_ptr_shut() -{ - if(g_memory_alloc_ptr) - { - free(g_memory_alloc_ptr); - g_memory_alloc_ptr = 0; - } - g_memory_ptr = 0; -} - - +// OG Added memory_ptr_shut +void +memory_ptr_shut() +{ + if(g_memory_alloc_ptr) + { + free(g_memory_alloc_ptr); + g_memory_alloc_ptr = 0; + } + g_memory_ptr = 0; +} + + extern int g_screen_redraw_skip_amt; extern int g_use_shmem; extern int g_use_dhr140; @@ -922,16 +924,16 @@ gsportmain(int argc, char **argv) int tmp1; int i; char *final_arg = 0; - - // OG Restoring globals - sim65816_initglobals(); - moremem_init(); - -//OG Disabling argument parsing -#ifndef ACTIVEGS - + + // OG Restoring globals + sim65816_initglobals(); + moremem_init(); + +//OG Disabling argument parsing +#ifndef ACTIVEGS + /* parse args */ - for(i = 1; i < argc; i++) { + for(i = 1; i < argc; i++) { if(!strcmp("-badrd", argv[i])) { printf("Halting on bad reads\n"); g_halt_on_bad_read = 2; @@ -1043,7 +1045,7 @@ gsportmain(int argc, char **argv) exit(3); } } - } + } #endif check_engine_asm_defines(); fixed_memory_ptrs_init(); @@ -1133,33 +1135,33 @@ gsportmain(int argc, char **argv) do_reset(); g_stepping = 0; - - // OG Notify emulator has been initialized and ready to accept external events - g_initialized = 1; - g_accept_events = 1; - + + // OG Notify emulator has been initialized and ready to accept external events + g_initialized = 1; + g_accept_events = 1; + do_go(); /* If we get here, we hit a breakpoint, call debug intfc */ do_debug_intfc(); - // OG Notify emulator is being closed, and cannot accept events anymore - g_accept_events = 0; - - sound_shutdown(); - - - // OG Cleaning up - adb_shut(); - iwm_shut(); - fixed_memory_ptrs_shut(); - load_roms_shut_memory(); - clear_fatal_logs(); - - // OG Not needed anymore : the emulator will quit gently - //my_exit(0); - end_screen(); - + // OG Notify emulator is being closed, and cannot accept events anymore + g_accept_events = 0; + + sound_shutdown(); + + + // OG Cleaning up + adb_shut(); + iwm_shut(); + fixed_memory_ptrs_shut(); + load_roms_shut_memory(); + clear_fatal_logs(); + + // OG Not needed anymore : the emulator will quit gently + //my_exit(0); + end_screen(); + return 0; } @@ -1184,14 +1186,14 @@ load_roms_init_memory() set_memory16_c(0xe115fe, 0, 0); } -// OG Added load_roms_shut_memory -void load_roms_shut_memory() -{ - memory_ptr_shut(); -} - -#ifndef ACTIVEGS - +// OG Added load_roms_shut_memory +void load_roms_shut_memory() +{ + memory_ptr_shut(); +} + +#ifndef ACTIVEGS + void gsport_expand_path(char *out_ptr, const char *in_ptr, int maxlen) { @@ -1341,8 +1343,8 @@ setup_gsport_file(char *outname, int maxlen, int ok_if_missing, my_exit(2); } -#endif - +#endif + Event g_event_list[MAX_EVENTS]; Event g_event_free; Event g_event_start; @@ -1675,13 +1677,13 @@ run_prog() while(1) { fflush(stdout); - -// OG Disabling control panel -#ifndef ACTIVEGS + +// OG Disabling control panel +#ifndef ACTIVEGS if(g_config_control_panel) { config_control_panel(); } -#endif +#endif if(g_irq_pending && !(engine.psr & 0x4)) { irq_printf("taking an irq!\n"); take_irq(0); @@ -1695,8 +1697,8 @@ run_prog() zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; fast = (g_c036_val_speed & 0x80) || (zip_en && !zip_follow_cps); - // OG Make fast parameter public - g_speed_fast = fast; + // OG Make fast parameter public + g_speed_fast = fast; if(zip_speed_0tof_new != zip_speed_0tof) { zip_speed_0tof = zip_speed_0tof_new; setup_zip_speeds(); @@ -1711,11 +1713,11 @@ run_prog() zip_speed = faster_than_28 && ((zip_speed_0tof != 0) || (limit_speed == 3) || (g_zipgs_unlock >= 4) ); - - // OG unlimited speed should not be affected by zip. - // unl_speed = faster_than_28 && !zip_speed; - unl_speed = (limit_speed == 0) && faster_than_28; - + + // OG unlimited speed should not be affected by zip. + // unl_speed = faster_than_28 && !zip_speed; + unl_speed = (limit_speed == 0) && faster_than_28; + if(unl_speed) { /* use unlimited speed */ fspeed_mult = g_projected_pmhz; @@ -2125,13 +2127,13 @@ update_60hz(double dcycs, double dtime_now) default: sp_str = "Unlimited"; break; } -// OG Pass speed info to the control (ActiveX specific) -#ifdef ACTIVEGS - { - extern void updateInfo(const char* target,const char *speed); - updateInfo(sp_str,total_mhz_ptr); - } -#endif +// OG Pass speed info to the control (ActiveX specific) +#ifdef ACTIVEGS + { + extern void updateInfo(const char* target,const char *speed); + updateInfo(sp_str,total_mhz_ptr); + } +#endif sprintf(status_buf, "dcycs:%9.1f sim MHz:%s " "Eff MHz:%s, sec:%1.3f vol:%02x pal:%x, Limit:%s", dcycs/(1000.0*1000.0), sim_mhz_ptr, total_mhz_ptr, @@ -2360,17 +2362,17 @@ update_60hz(double dcycs, double dtime_now) } iwm_vbl_update(doit_3_persec); - -// OG Disabling config update -#ifndef ACTIVEGS + +// OG Disabling config update +#ifndef ACTIVEGS config_vbl_update(doit_3_persec); -#else -// OG Added disk update - { - extern void checkImages(); - checkImages(); - } -#endif +#else +// OG Added disk update + { + extern void checkImages(); + checkImages(); + } +#endif video_update(); sound_update(dcycs); @@ -2384,7 +2386,7 @@ update_60hz(double dcycs, double dtime_now) if (g_imagewriter_timeout) { imagewriter_update(); - } + } paddle_update_buttons(); } @@ -2465,7 +2467,7 @@ check_scan_line_int(double dcycs, int cur_video_line) } if(g_slow_memory_ptr[0x19d00+i] & 0x40) { irq_printf("Adding scan_int for line %d\n", i); - delay = (int)( (DCYCS_IN_16MS/262.0) * ((double)line) ); + delay = (int)( (DCYCS_IN_16MS/262.0) * ((double)line) ); add_event_entry(g_last_vbl_dcycs + delay, EV_SCAN_INT + (line << 8)); g_scan_int_events = 1; @@ -2681,15 +2683,15 @@ gsport_vprintf(const char *fmt, va_list ap) int len; int ret; - bufptr = (char*)malloc(4096); // OG Added Cast + bufptr = (char*)malloc(4096); // OG Added Cast ret = vsnprintf(bufptr, 4090, fmt, ap); - // OG Display warning - printf("Warning:%s",bufptr); - + // OG Display warning + printf("Warning:%s",bufptr); + len = strlen(bufptr); if(g_fatal_log >= 0 && g_fatal_log < MAX_FATAL_LOGS) { - buf2ptr = (char*)malloc(len+1); // OG Added Cast + buf2ptr = (char*)malloc(len+1); // OG Added Cast memcpy(buf2ptr, bufptr, len+1); g_fatal_log_strs[g_fatal_log++] = buf2ptr; } @@ -2740,7 +2742,7 @@ gsport_malloc_str(char *in_str) int len; len = strlen(in_str) + 1; - str = (char*)malloc(len); // OG Added cast + str = (char*)malloc(len); // OG Added cast memcpy(str, in_str, len); return str; diff --git a/src/size_tab.h b/src/size_tab.h index 8989c8b..1ef1998 100644 --- a/src/size_tab.h +++ b/src/size_tab.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/smartport.c b/src/smartport.c index eb43787..cd0223e 100644 --- a/src/smartport.c +++ b/src/smartport.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey diff --git a/src/sound.c b/src/sound.c index 0872d04..e95e33e 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1,2094 +1,2096 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2012 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "defc.h" -#include "sound.h" - -extern int Verbose; -extern int g_use_shmem; -extern int g_preferred_rate; -extern int g_c03ef_doc_ptr; -extern double g_last_vbl_dcycs; -extern word32 g_vbl_count; - -void U_STACK_TRACE(); - -byte doc_ram[0x10000 + 16]; - -word32 doc_sound_ctl = 0; -word32 doc_saved_val = 0; -int g_doc_num_osc_en = 1; -double g_dcycs_per_doc_update = 1.0; -double g_dupd_per_dcyc = 1.0; -double g_drecip_osc_en_plus_2 = 1.0 / (double)(1 + 2); - -int g_doc_saved_ctl = 0; -int g_queued_samps = 0; -int g_queued_nonsamps = 0; -int g_num_osc_interrupting = 0; - -/* Workaround - gcc in cygwin wasn't defining _WIN32, substituted WIN_SOUND instead */ -#if defined(HPUX) || defined(__linux__) || defined(WIN_SOUND) || defined(MAC) || defined(HAVE_SDL) -int g_audio_enable = -1; -#else -# if defined(OSS) -/* default to off for now */ -int g_audio_enable = 0; -# else -/* Default to sound off */ -int g_audio_enable = 0; -# endif -#endif - -Doc_reg g_doc_regs[32]; - -word32 doc_reg_e0 = 0xff; - -/* local function prototypes */ -void doc_write_ctl_reg(int osc, int val, double dsamps); -void sound_write_sdl(int real_samps, int size); - -int g_audio_rate = 0; -double g_daudio_rate = 0.0; -double g_drecip_audio_rate = 0.0; -double g_dsamps_per_dcyc = 0.0; -double g_dcycs_per_samp = 0.0; -float g_fsamps_per_dcyc = 0.0; - -int g_doc_vol = 2; - -#define MAX_C030_TIMES 18000 - -double g_last_sound_play_dsamp = 0.0; - -float c030_fsamps[MAX_C030_TIMES + 1]; -int g_num_c030_fsamps = 0; - -#define DOC_SCAN_RATE (DCYCS_28_MHZ/32.0) - -int g_pipe_fd[2] = { -1, -1 }; -int g_pipe2_fd[2] = { -1, -1 }; -word32 *g_sound_shm_addr = 0; -int g_sound_shm_pos = 0; - -#define LEN_DOC_LOG 128 - -STRUCT(Doc_log) { - char *msg; - int osc; - double dsamps; - double dtmp2; - int etc; - Doc_reg doc_reg; -}; - -Doc_log g_doc_log[LEN_DOC_LOG]; -int g_doc_log_pos = 0; - - -#ifdef DO_DOC_LOG -# define DOC_LOG(a,b,c,d) doc_log_rout(a,b,c,d) -#else -# define DOC_LOG(a,b,c,d) -#endif - -#define UPDATE_G_DCYCS_PER_DOC_UPDATE(osc_en) \ - g_dcycs_per_doc_update = (double)((osc_en + 2) * DCYCS_1_MHZ) / \ - DOC_SCAN_RATE; \ - g_dupd_per_dcyc = 1.0 / g_dcycs_per_doc_update; \ - g_drecip_osc_en_plus_2 = 1.0 / (double)(osc_en + 2); - -#define SND_PTR_SHIFT 14 -#define SND_PTR_SHIFT_DBL ((double)(1 << SND_PTR_SHIFT)) - -void -doc_log_rout(char *msg, int osc, double dsamps, int etc) -{ - int pos; - - pos = g_doc_log_pos; - g_doc_log[pos].msg = msg; - g_doc_log[pos].osc = osc; - g_doc_log[pos].dsamps = dsamps; - g_doc_log[pos].dtmp2 = g_last_sound_play_dsamp; - g_doc_log[pos].etc = etc; - if(osc >= 0 && osc < 32) { - g_doc_log[pos].doc_reg = g_doc_regs[osc]; - } - pos++; - if(pos >= LEN_DOC_LOG) { - pos = 0; - } - - doc_printf("log: %s, osc:%d dsamp:%f, etc:%d\n", msg, osc, dsamps, etc); - - g_doc_log_pos = pos; -} - -extern double g_cur_dcycs; - -void -show_doc_log(void) -{ - FILE *docfile; - Doc_reg *rptr; - double dsamp_start; - int osc, ctl, freq; - int pos; - int i; - - docfile = fopen("doc_log_out", "w"); - if(docfile == 0) { - printf("fopen failed, errno: %d\n", errno); - return; - } - pos = g_doc_log_pos; - fprintf(docfile, "DOC log pos: %d\n", pos); - dsamp_start = g_doc_log[pos].dsamps; - for(i = 0; i < LEN_DOC_LOG; i++) { - rptr = &(g_doc_log[pos].doc_reg); - osc = g_doc_log[pos].osc; - ctl = rptr->ctl; - freq = rptr->freq; - if(osc < 0) { - ctl = 0; - freq = 0; - } - fprintf(docfile, "%03x:%03x: %-11s ds:%11.1f dt2:%10.1f " - "etc:%08x o:%02x c:%02x fq:%04x\n", - i, pos, g_doc_log[pos].msg, - g_doc_log[pos].dsamps - dsamp_start, - g_doc_log[pos].dtmp2, - g_doc_log[pos].etc, osc & 0xff, ctl, freq); - if(osc >= 0) { - fprintf(docfile, " ire:%d,%d,%d ptr4:%08x " - "inc4:%08x comp_ds:%.1f left:%04x, vol:%02x " - "wptr:%02x, wsz:%02x, 4st:%08x, 4end:%08x\n", - rptr->has_irq_pending, rptr->running, - rptr->event, 4*rptr->cur_acc, 4*rptr->cur_inc, - rptr->complete_dsamp - dsamp_start, - rptr->samps_left, rptr->vol, rptr->waveptr, - rptr->wavesize, 4*rptr->cur_start, - 4*rptr->cur_end); - } - pos++; - if(pos >= LEN_DOC_LOG) { - pos = 0; - } - } - - fprintf(docfile, "cur_dcycs: %f\n", g_cur_dcycs); - fprintf(docfile, "dsamps_now: %f\n", - (g_cur_dcycs * g_dsamps_per_dcyc) - dsamp_start); - fprintf(docfile, "g_doc_num_osc_en: %d\n", g_doc_num_osc_en); - fclose(docfile); -} - -void -sound_init() -{ - Doc_reg *rptr; - int i; - - for(i = 0; i < 32; i++) { - rptr = &(g_doc_regs[i]); - rptr->dsamp_ev = 0.0; - rptr->dsamp_ev2 = 0.0; - rptr->complete_dsamp = 0.0; - rptr->samps_left = 0; - rptr->cur_acc = 0; - rptr->cur_inc = 0; - rptr->cur_start = 0; - rptr->cur_end = 0; - rptr->cur_mask = 0; - rptr->size_bytes = 0; - rptr->event = 0; - rptr->running = 0; - rptr->has_irq_pending = 0; - rptr->freq = 0; - rptr->vol = 0; - rptr->waveptr = 0; - rptr->ctl = 1; - rptr->wavesize = 0; - rptr->last_samp_val = 0; - } - - // OG sound globals initialization - g_num_c030_fsamps = 0; - g_sound_shm_pos = 0; - g_queued_samps = 0; - g_queued_nonsamps = 0; - - doc_sound_ctl = 0; - doc_saved_val = 0; - g_doc_num_osc_en = 1; - g_dcycs_per_doc_update = 1.0; - g_dupd_per_dcyc = 1.0; - g_drecip_osc_en_plus_2 = 1.0 / (double)(1 + 2); - - doc_reg_e0 = 0xff; - g_audio_rate = 0; - g_daudio_rate = 0.0; - g_drecip_audio_rate = 0.0; - g_dsamps_per_dcyc = 0.0; - g_dcycs_per_samp = 0.0; - g_fsamps_per_dcyc = 0.0; - - g_doc_vol = 2; - - g_last_sound_play_dsamp = 0.0; - - sound_init_general(); -} - - -void -sound_init_general() -{ - printf("SOUND INIT GENERAL\n"); -/* Workaround - gcc in cygwin wasn't defining _WIN32 */ -#if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) && !defined(HAVE_SDL) - int pid; - int shmid; - int tmp; - int i; -#endif - - word32 *shmaddr; - int size; - int ret; - -/* Workaround - gcc in cygwin wasn't defining _WIN32 */ -#if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) && !defined(HAVE_SDL) - if(!g_use_shmem) { - if(g_audio_enable < 0) { - printf("Defaulting audio off for slow X display\n"); - g_audio_enable = 0; - } - } -#endif - - ret = 0; - - if(g_audio_enable == 0) { - set_audio_rate(g_preferred_rate); - return; - } - - size = SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE; -/* Workaround - gcc in cygwin wasn't defining _WIN32 */ -#if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) && !defined(HAVE_SDL) - shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); - if(shmid < 0) { - printf("sound_init: shmget ret: %d, errno: %d\n", shmid, errno); - exit(2); - } - - shmaddr = (word32*)shmat(shmid, 0, 0); - tmp = (int)PTR2WORD(shmaddr); - if(tmp == -1) { - printf("sound_init: shmat ret: %p, errno: %d\n", shmaddr, - errno); - exit(3); - } - - ret = shmctl(shmid, IPC_RMID, 0); - if(ret < 0) { - printf("sound_init: shmctl ret: %d, errno: %d\n", ret, errno); - exit(4); - } -#else - // windows and mac and sdl - shmaddr = (word32*)malloc(size); //size = 131072 - memset(shmaddr, 0, size); -#endif - - g_sound_shm_addr = shmaddr; - - fflush(stdout); -/* Workaround - gcc in cygwin wasn't defining _WIN32 */ -#if !defined(MAC) && !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(__OS2__) && !defined(HAVE_SDL) - /* prepare pipe so parent can signal child each other */ - /* pipe[0] = read side, pipe[1] = write end */ - ret = pipe(&g_pipe_fd[0]); - if(ret < 0) { - printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno); - exit(5); - } - ret = pipe(&g_pipe2_fd[0]); - if(ret < 0) { - printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno); - exit(5); - } - - - printf("pipes: pipe_fd = %d, %d pipe2_fd: %d,%d\n", - g_pipe_fd[0], g_pipe_fd[1], g_pipe2_fd[0], g_pipe2_fd[1]); - fflush(stdout); - - pid = fork(); - switch(pid) { - case 0: - /* child */ - /* close stdin and write-side of pipe */ - close(0); - /* Close other fds to make sure X window fd is closed */ - for(i = 3; i < 100; i++) { - if((i != g_pipe_fd[0]) && (i != g_pipe2_fd[1])) { - close(i); - } - } - close(g_pipe_fd[1]); /*make sure write pipe closed*/ - close(g_pipe2_fd[0]); /*make sure read pipe closed*/ - child_sound_loop(g_pipe_fd[0], g_pipe2_fd[1], g_sound_shm_addr); - printf("Child sound loop returned\n"); - exit(0); - case -1: - /* error */ - printf("sound_init: fork ret: -1, errno: %d\n", errno); - exit(6); - default: - /* parent */ - /* close read-side of pipe1, and the write side of pipe2 */ - close(g_pipe_fd[0]); - close(g_pipe2_fd[1]); - doc_printf("Child is pid: %d\n", pid); - } - - parent_sound_get_sample_rate(g_pipe2_fd[0]); -#else -# if defined (HAVE_SDL) - sdlsnd_init(shmaddr); -# elif defined (WIN_SOUND) - win32snd_init(shmaddr); -# elif defined (MAC) && !defined(HAVE_SDL) - macsnd_init(shmaddr); -# elif defined (__OS2__) -# endif -#endif - -} - -void -parent_sound_get_sample_rate(int read_fd) -{ -#ifndef __OS2__ - word32 tmp; - int ret; - - ret = read(read_fd, (char*)&tmp, 4); - if(ret != 4) { - printf("parent could not get audio sample rate from child, disabling sound.\n"); - printf("ret: %d, fd: %d errno:%d\n", ret, read_fd, errno); - g_audio_enable = 0; - } - close(read_fd); - - set_audio_rate(tmp); -#endif -} - -void -set_audio_rate(int rate) -{ - g_audio_rate = rate; - g_daudio_rate = (rate)*1.0; - g_drecip_audio_rate = 1.0/(rate); - g_dsamps_per_dcyc = ((rate*1.0) / DCYCS_1_MHZ); - g_dcycs_per_samp = (DCYCS_1_MHZ / (rate*1.0)); - g_fsamps_per_dcyc = (float)((rate*1.0) / DCYCS_1_MHZ); -} - -void -sound_reset(double dcycs) -{ - double dsamps; - int i; - - dsamps = dcycs * g_dsamps_per_dcyc; - for(i = 0; i < 32; i++) { - doc_write_ctl_reg(i, g_doc_regs[i].ctl | 1, dsamps); - doc_reg_e0 = 0xff; - if(g_doc_regs[i].has_irq_pending) { - halt_printf("reset: has_irq[%02x] = %d\n", i, - g_doc_regs[i].has_irq_pending); - } - g_doc_regs[i].has_irq_pending = 0; - } - if(g_num_osc_interrupting) { - halt_printf("reset: num_osc_int:%d\n", g_num_osc_interrupting); - } - g_num_osc_interrupting = 0; - -// OG No reason to reset the number of active oscillo on reset : this should only be done on startup. - /* - g_doc_num_osc_en = 1; - UPDATE_G_DCYCS_PER_DOC_UPDATE(1); - */ -} - -void -sound_shutdown() -{ - // OG stop sound and free memory on sound_shutdown - sound_reset(g_cur_dcycs); - -#ifdef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */ - win32snd_shutdown(); -#elif defined(__OS2__) -#elif defined(HAVE_SDL) - if((g_audio_enable != 0)) { - //sdlsnd_shutdown(); - sound_shutdown_sdl(); - } -#else - if((g_audio_enable != 0) && g_pipe_fd[1] != 0) { - close(g_pipe_fd[1]); - } -#endif - - // OG Free up allocated memory - if (g_sound_shm_addr) - { - free(g_sound_shm_addr); - g_sound_shm_addr = NULL; - } -} - - - -void -sound_update(double dcycs) -{ - double dsamps; - /* Called every VBL time to update sound status */ - - /* "play" sounds for this vbl */ - - dsamps = dcycs * g_dsamps_per_dcyc; - DOC_LOG("do_snd_pl", -1, dsamps, 0); - sound_play(dsamps); -} - -#define MAX_SND_BUF 65536 - -int g_samp_buf[2*MAX_SND_BUF]; -word32 zero_buf[SOUND_SHM_SAMP_SIZE]; - -double g_doc_dsamps_extra = 0.0; - -float g_fvoices = 0.0; - -word32 g_cycs_in_sound1 = 0; -word32 g_cycs_in_sound2 = 0; -word32 g_cycs_in_sound3 = 0; -word32 g_cycs_in_sound4 = 0; -word32 g_cycs_in_start_sound = 0; -word32 g_cycs_in_est_sound = 0; - -int g_num_snd_plays = 0; -int g_num_doc_events = 0; -int g_num_start_sounds = 0; -int g_num_scan_osc = 0; -int g_num_recalc_snd_parms = 0; - -word32 g_last_c030_vbl_count = 0; -int g_c030_state = 0; - -#define VAL_C030_RANGE (32768) -#define VAL_C030_BASE (-16384) - -int g_sound_file_num = 0; -FILE *g_sound_file_fd = 0; -int g_send_sound_to_file = 0; -int g_send_file_bytes = 0; - -void -open_sound_file() -{ - char name[256]; - FILE *fd; - - sprintf(name, "snd.out.%d", g_sound_file_num); - - fd = fopen(name, "wb+"); - if(fd == 0) { - printf("open_sound_file open errno: %d\n", errno); - exit(1); - } - - g_sound_file_fd = fd; - g_sound_file_num++; - g_send_file_bytes = 0; -} - -void -close_sound_file() -{ - if(g_sound_file_fd != 0) { - fclose(g_sound_file_fd); - } - - g_sound_file_fd = 0; -} - -void -check_for_range(word32 *addr, int num_samps, int offset) -{ - short *shortptr; - int i; - int left; - int right; - int max; - - max = -32768; - - if(num_samps > SOUND_SHM_SAMP_SIZE) { - halt_printf("num_samps: %d > %d!\n", num_samps, - SOUND_SHM_SAMP_SIZE); - } - - for(i = 0; i < num_samps; i++) { - shortptr = (short *)&(addr[i]); - left = shortptr[0]; - right = shortptr[1]; - if((left > 0x3000) || (right > 0x3000)) { - halt_printf("Sample %d of %d at snd_buf: %p is: " - "%d/%d\n", i + offset, num_samps, - &addr[i], left, right); - return; - } - - max = MAX(max, left); - max = MAX(max, right); - } - - printf("check4 max: %d over %d\n", max, num_samps); -} - -void -send_sound_to_file(word32 *addr, int shm_pos, int num_samps) -{ - int size; - int ret; - - if(g_sound_file_fd == 0) { - open_sound_file(); - } - - size = 0; - if((num_samps + shm_pos) > SOUND_SHM_SAMP_SIZE) { - size = SOUND_SHM_SAMP_SIZE - shm_pos; - g_send_file_bytes += (size * 4); - - ret = fwrite(&(addr[shm_pos]), 1, 4*size, g_sound_file_fd); - if(ret != 4*size) { - halt_printf("wrote %d not %d\n", ret, 4*size); - } - - if(g_doc_vol < 3) { - check_for_range(&(addr[shm_pos]), size, 0); - } else { - printf("Not checking %d bytes since vol: %d\n", - 4*size, g_doc_vol); - } - shm_pos = 0; - num_samps -= size; - } - - g_send_file_bytes += (num_samps * 4); - - ret = fwrite(&(addr[shm_pos]), 1, 4*num_samps, g_sound_file_fd); - if(ret != 4*num_samps) { - halt_printf("wrote %d not %d\n", ret, 4*num_samps); - } - - if(g_doc_vol < 3) { - check_for_range(&(addr[shm_pos]), num_samps, size); - } else { - printf("Not checking2 %d bytes since vol: %d\n", - 4*num_samps, g_doc_vol); - } - -} - - -// is called with real_samps = 1 to output sound -void -send_sound(int real_samps, int size) -{ - // real_samps = 1, size = 1602 - word32 tmp; - int ret; - - if(g_audio_enable == 0) { - printf("Entered send_sound but audio off!\n"); - exit(2); - } - // really does add this crazy high value. i guess it gets taken off / checked later - // so if size = 1602 (0x0642) it becomes 0xa2000642 - // wtf? - if(real_samps) { - tmp = size + 0xa2000000; - } else { - tmp = size + 0xa1000000; - } - DOC_LOG("send_sound", -1, g_last_sound_play_dsamp, - (real_samps << 30) + size); -// Workaround - gcc in cygwin wasn't defining _WIN32 -#if defined(WIN_SOUND) || defined(MAC) && !defined(HAVE_SDL) - ret = 0; - child_sound_playit(tmp); -#elif defined(HAVE_SDL) - sound_write_sdl( real_samps, size); - //sdl_send_audio(&g_sound_shm_addr[g_sound_shm_pos], size, real_samps); -#elif defined(__OS2__) - -#else - /* Although this looks like a big/little-endian issue, since the */ - /* child is also reading an int, it just works with no byte swap */ - ret = write(g_pipe_fd[1], &tmp, 4); - if(ret != 4) { - halt_printf("send_sound, wr ret: %d, errno: %d\n", ret, errno); - } -#endif -} - -void -show_c030_state() -{ - show_c030_samps(&(g_samp_buf[0]), 100); -} - -void -show_c030_samps(int *outptr, int num) -{ - int i; - - printf("c030_fsamps[]: %d\n", g_num_c030_fsamps); - - for(i = 0; i < g_num_c030_fsamps+2; i++) { - printf("%3d: %5.3f\n", i, c030_fsamps[i]); - } - - printf("Samples[] = %d\n", num); - - for(i = 0; i < num+2; i++) { - printf("%4d: %d %d\n", i, outptr[0], outptr[1]); - outptr += 2; - } -} - -int g_sound_play_depth = 0; - -void -sound_play(double dsamps) -{ - register word32 start_time1, start_time2, start_time3, start_time4; - register word32 end_time1, end_time2, end_time3; - Doc_reg *rptr; - int *outptr; - int *outptr_start; - word32 *sndptr; - double complete_dsamp; - double cur_dsamp; - double last_dsamp; - double dsamp_now; - double dnum_samps; - int val, val2; - int new_val; - float ftmp; - int imul; - int off; - int num; - float fsampnum; - float next_fsampnum; - int c030_lo_val, c030_hi_val; - float fc030_range; - float fc030_base; - int sampnum; - int next_sampnum; - float fpercent; - int c030_state; - int val0, val1; - word32 cur_acc; - word32 cur_pos; - word32 cur_mask; - word32 cur_inc; - word32 cur_end; - int ctl; - int num_osc_en; - int samps_left; - int samps_to_do; - int samps_played; - int samp_offset; - int snd_buf_init; - int pos; - int num_running; - int num_samps; - int osc; - int done; - int i, j; - - - GET_ITIMER(start_time1); - - g_num_snd_plays++; - if(g_sound_play_depth) { - halt_printf("Nested sound_play!\n"); - } - - g_sound_play_depth++; - - /* calc sample num */ - - last_dsamp = g_last_sound_play_dsamp; - num_samps = (int)(dsamps - g_last_sound_play_dsamp); - dnum_samps = (double)num_samps; - - dsamp_now = last_dsamp + dnum_samps; - - if(num_samps < 1) { - /* just say no */ - g_sound_play_depth--; - return; - } - - DOC_LOG("sound_play", -1, dsamp_now, num_samps); - - if(num_samps > MAX_SND_BUF) { - printf("num_samps: %d, too big!\n", num_samps); - g_sound_play_depth--; - return; - } - - - GET_ITIMER(start_time4); - - outptr_start = &(g_samp_buf[0]); - outptr = outptr_start; - - snd_buf_init = 0; - - samps_played = 0; - - num = g_num_c030_fsamps; - - if(num || ((g_vbl_count - g_last_c030_vbl_count) < 240)) { - - if(num) { - g_last_c030_vbl_count = g_vbl_count; - } - - pos = 0; - outptr = outptr_start; - c030_state = g_c030_state; - - c030_hi_val = ((VAL_C030_BASE + VAL_C030_RANGE)*g_doc_vol) >> 4; - c030_lo_val = (VAL_C030_BASE * g_doc_vol) >> 4; - - fc030_range = (float)(((VAL_C030_RANGE) * g_doc_vol) >> 4); - fc030_base = (float)(((VAL_C030_BASE) * g_doc_vol) >> 4); - - val = c030_lo_val; - if(c030_state) { - val = c030_hi_val; - } - - snd_buf_init++; - - c030_fsamps[num] = (float)(num_samps); - c030_fsamps[num+1] = (float)(num_samps+1); - - ftmp = (float)num_samps; - /* ensure that all samps are in range */ - for(i = num - 1; i >= 0; i--) { - if(c030_fsamps[i] > ftmp) { - c030_fsamps[i] = ftmp; - } - } - - num++; - fsampnum = c030_fsamps[0]; - sampnum = (int)fsampnum; - fpercent = (float)0.0; - i = 0; - - while(i < num) { - next_fsampnum = c030_fsamps[i+1]; - next_sampnum = (int)next_fsampnum; - if(sampnum < 0 || sampnum > num_samps) { - halt_printf("play c030: [%d]:%f is %d, > %d\n", - i, fsampnum, sampnum, num_samps); - break; - } - - /* write in samples to all samps < me */ - new_val = c030_lo_val; - if(c030_state) { - new_val = c030_hi_val; - } - for(j = pos; j < sampnum; j++) { - outptr[0] = new_val; - outptr[1] = new_val; - outptr += 2; - pos++; - } - - /* now, calculate me */ - fpercent = (float)0.0; - if(c030_state) { - fpercent = (fsampnum - (float)sampnum); - } - - c030_state = !c030_state; - - while(next_sampnum == sampnum) { - if(c030_state) { - fpercent += (next_fsampnum - fsampnum); - } - i++; - fsampnum = next_fsampnum; - - next_fsampnum = c030_fsamps[i+1]; - next_sampnum = (int)next_fsampnum; - c030_state = !c030_state; - } - - if(c030_state) { - /* add in fractional time */ - ftmp = (float)(int)(fsampnum + 1.0f); //OG added cast - fpercent += (ftmp - fsampnum); - } - - if((fpercent < (float)0.0) || (fpercent > (float)1.0)) { - halt_printf("fpercent: %d = %f\n", i, fpercent); - show_c030_samps(outptr_start, num_samps); - break; - } - - val = (int)((fpercent * fc030_range) + fc030_base); - outptr[0] = val; - outptr[1] = val; - outptr += 2; - pos++; - i++; - - sampnum = next_sampnum; - fsampnum = next_fsampnum; - } - - samps_played += num_samps; - - /* since we pretended to get one extra sample, we will */ - /* have toggled the speaker one time too many. Fix it */ - g_c030_state = !c030_state; - - if(g_send_sound_to_file) { - show_c030_samps(outptr_start, num_samps); - } - } - - g_num_c030_fsamps = 0; - - GET_ITIMER(start_time2); - - num_running = 0; - - num_osc_en = g_doc_num_osc_en; - - done = 0; - while(!done) { - done = 1; - for(j = 0; j < num_osc_en; j++) { - osc = j; - rptr = &(g_doc_regs[osc]); - complete_dsamp = rptr->complete_dsamp; - samps_left = rptr->samps_left; - cur_acc = rptr->cur_acc; - cur_mask = rptr->cur_mask; - cur_inc = rptr->cur_inc; - cur_end = rptr->cur_end; - if(!rptr->running || cur_inc == 0 || - (complete_dsamp >= dsamp_now)) { - continue; - } - - done = 0; - ctl = rptr->ctl; - - samp_offset = 0; - if(complete_dsamp > last_dsamp) { - samp_offset = (int)(complete_dsamp- last_dsamp); - if(samp_offset > num_samps) { - rptr->complete_dsamp = dsamp_now; - continue; - } - } - outptr = outptr_start + 2 * samp_offset; - if(ctl & 0x10) { - /* other channel */ - outptr += 1; - } - - imul = (rptr->vol * g_doc_vol); - off = imul * 128; - - samps_to_do = MIN(samps_left, num_samps - samp_offset); - if(imul == 0 || samps_to_do == 0) { - /* produce no sound */ - samps_left = samps_left - samps_to_do; - cur_acc += cur_inc * samps_to_do; - rptr->samps_left = samps_left; - rptr->cur_acc = cur_acc; - cur_dsamp = last_dsamp + - (double)(samps_to_do + samp_offset); - DOC_LOG("nosnd", osc, cur_dsamp, samps_to_do); - rptr->complete_dsamp = dsamp_now; - cur_pos = rptr->cur_start+(cur_acc & cur_mask); - if(samps_left <= 0) { - doc_sound_end(osc, 1, cur_dsamp, - dsamp_now); - val = 0; - j--; - } else { - val = doc_ram[cur_pos >> SND_PTR_SHIFT]; - } - rptr->last_samp_val = val; - continue; - } - - if(snd_buf_init == 0) { - memset(outptr_start, 0, - 2*sizeof(outptr_start[0])*num_samps); - snd_buf_init++; - } - - val = 0; - rptr->complete_dsamp = dsamp_now; - cur_pos = rptr->cur_start + (cur_acc & cur_mask); - for(i = 0; i < samps_to_do; i++) { - pos = cur_pos >> SND_PTR_SHIFT; - cur_pos += cur_inc; - cur_acc += cur_inc; - val = doc_ram[pos]; - - val2 = (val * imul - off) >> 4; - if((val == 0) || (cur_pos >= cur_end)) { - cur_dsamp = last_dsamp + - (double)(samp_offset + i + 1); - rptr->cur_acc = cur_acc; - rptr->samps_left = 0; - DOC_LOG("end or 0", osc, cur_dsamp, - (pos << 16) + ((i &0xff) << 8) + - val); - doc_sound_end(osc, val, cur_dsamp, - dsamp_now); - val = 0; - break; - } - - val2 = outptr[0] + val2; - - samps_left--; - *outptr = val2; - outptr += 2; - } - - rptr->last_samp_val = val; - - if(val != 0) { - rptr->cur_acc = cur_acc; - rptr->samps_left = samps_left; - rptr->complete_dsamp = dsamp_now; - } - - samps_played += samps_to_do; - DOC_LOG("splayed", osc, dsamp_now, - (samps_to_do << 16) + (pos & 0xffff)); - } - } - - GET_ITIMER(end_time2); - - g_cycs_in_sound2 += (end_time2 - start_time2); - - g_last_sound_play_dsamp = dsamp_now; - - GET_ITIMER(start_time3); - - outptr = outptr_start; - - pos = g_sound_shm_pos; - sndptr = g_sound_shm_addr; - -#if 0 - printf("samps_left: %d, num_samps: %d\n", samps_left, num_samps); -#endif - - if(g_audio_enable != 0) { - - if(snd_buf_init) { - /* convert sound buf */ - - - for(i = 0; i < num_samps; i++) { - val0 = outptr[0]; - val1 = outptr[1]; - val = val0; - if(val0 > 32767) { - val = 32767; - } - if(val0 < -32768) { - val = -32768; - } - - val0 = val; - val = val1; - if(val1 > 32767) { - val = 32767; - } - if(val1 < -32768) { - val = -32768; - } - - - outptr += 2; - -#if defined(__linux__) || defined(OSS) - /* Linux seems to expect little-endian */ - /* samples always, even on PowerPC */ -#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - sndptr[pos] = (val << 16) + (val0 & 0xffff); -# else - sndptr[pos] = ((val & 0xff) << 24) + - ((val & 0xff00) << 8) + - ((val0 & 0xff) << 8) + - ((val0 >> 8) & 0xff); -# endif -#else -#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - sndptr[pos] = (val << 16) + (val0 & 0xffff); -# else - sndptr[pos] = (val0 << 16) + (val & 0xffff); -# endif -#endif - // printf("%08x ", sndptr[pos]); - pos++; - if(pos >= SOUND_SHM_SAMP_SIZE) { - pos = 0; - } - } - - if(g_queued_nonsamps) { - /* force out old 0 samps */ - send_sound(0, g_queued_nonsamps); - g_queued_nonsamps = 0; - } - - if(g_send_sound_to_file) { - send_sound_to_file(g_sound_shm_addr, - g_sound_shm_pos, num_samps); - } - - g_queued_samps += num_samps; - } else { - /* move pos */ - pos += num_samps; - while(pos >= SOUND_SHM_SAMP_SIZE) { - pos -= SOUND_SHM_SAMP_SIZE; - } - - if(g_send_sound_to_file) { - send_sound_to_file(zero_buf, g_sound_shm_pos, - num_samps); - } - - if(g_queued_samps) { - /* force out old non-0 samps */ - send_sound(1, g_queued_samps); - g_queued_samps = 0; - } - - g_queued_nonsamps += num_samps; - } - - } - - g_sound_shm_pos = pos; - - - GET_ITIMER(end_time3); - - g_fvoices += ((float)(samps_played) * (float)(g_drecip_audio_rate)); - - if(g_audio_enable != 0) { - if(g_queued_samps >= (g_audio_rate/32)) { - send_sound(1, g_queued_samps); - g_queued_samps = 0; - } - - if(g_queued_nonsamps >= (g_audio_rate/32)) { - send_sound(0, g_queued_nonsamps); - g_queued_nonsamps = 0; - } - } - - GET_ITIMER(end_time1); - - g_cycs_in_sound1 += (end_time1 - start_time1); - g_cycs_in_sound3 += (end_time3 - start_time3); - g_cycs_in_sound4 += (start_time2 - start_time4); - - g_last_sound_play_dsamp = dsamp_now; - - g_sound_play_depth--; -} - - -void -doc_handle_event(int osc, double dcycs) -{ - double dsamps; - - /* handle osc stopping and maybe interrupting */ - - g_num_doc_events++; - - dsamps = dcycs * g_dsamps_per_dcyc; - - DOC_LOG("doc_ev", osc, dcycs, 0); - - g_doc_regs[osc].event = 0; - - sound_play(dsamps); - -} - -void -doc_sound_end(int osc, int can_repeat, double eff_dsamps, double dsamps) -{ - Doc_reg *rptr, *orptr; - int mode, omode; - int other_osc; - int one_shot_stop; - int ctl; - - /* handle osc stopping and maybe interrupting */ - - if(osc < 0 || osc > 31) { - printf("doc_handle_event: osc: %d!\n", osc); - return; - } - - rptr = &(g_doc_regs[osc]); - ctl = rptr->ctl; - - if(rptr->event) { - remove_event_doc(osc); - } - rptr->event = 0; - - /* check to make sure osc is running */ - if(ctl & 0x01) { - /* Oscillator already stopped. */ - halt_printf("Osc %d interrupt, but it was already stop!\n",osc); -#ifdef HPUX - U_STACK_TRACE(); -#endif - return; - } - - if(ctl & 0x08) { - if(rptr->has_irq_pending == 0) { - add_sound_irq(osc); - } - } - - if(!rptr->running) { - halt_printf("Doc event for osc %d, but ! running\n", osc); - } - - rptr->running = 0; - - mode = (ctl >> 1) & 3; - other_osc = osc ^ 1; - orptr = &(g_doc_regs[other_osc]); - omode = (orptr->ctl >> 1) & 3; - - /* If either this osc or it's partner is in swap mode, treat the */ - /* pair as being in swap mode. This Ensoniq feature pointed out */ - /* by Ian Schmidt */ - if(mode == 0 && can_repeat) { - /* free-running mode with no 0 byte! */ - /* start doing it again */ - - start_sound(osc, eff_dsamps, dsamps); - - return; - } - rptr->cur_acc = 0; /* reset internal accumulator*/ - if((mode == 3) || (omode == 3)) { - /* swap mode (even if we're one_shot and partner is swap)! */ - rptr->ctl |= 1; - if(!orptr->running && - (orptr->ctl & 0x1)) { - orptr->ctl = orptr->ctl & (~1); - start_sound(other_osc, eff_dsamps, dsamps); - } - return; - } else { - /* stop the oscillator */ - rptr->ctl |= 1; - } - - return; -} - -void -add_sound_irq(int osc) -{ - int num_osc_interrupting; - - if(g_doc_regs[osc].has_irq_pending) { - halt_printf("Adding sound_irq for %02x, but irq_p: %d\n", osc, - g_doc_regs[osc].has_irq_pending); - } - - num_osc_interrupting = g_num_osc_interrupting + 1; - g_doc_regs[osc].has_irq_pending = num_osc_interrupting; - g_num_osc_interrupting = num_osc_interrupting; - - add_irq(IRQ_PENDING_DOC); - if(num_osc_interrupting == 1) { - doc_reg_e0 = 0x00 + (osc << 1); - } - - DOC_LOG("add_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); -} - -void -remove_sound_irq(int osc, int must) -{ - Doc_reg *rptr; - int num_osc_interrupt; - int has_irq_pending; - int first; - int i; - - doc_printf("remove irq for osc: %d, has_irq: %d\n", - osc, g_doc_regs[osc].has_irq_pending); - - num_osc_interrupt = g_doc_regs[osc].has_irq_pending; - first = 0; - if(num_osc_interrupt) { - g_num_osc_interrupting--; - g_doc_regs[osc].has_irq_pending = 0; - DOC_LOG("rem_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); - if(g_num_osc_interrupting == 0) { - remove_irq(IRQ_PENDING_DOC); - } - - first = 0x40 | (doc_reg_e0 >> 1); - /* if none found, then def = no ints */ - for(i = 0; i < g_doc_num_osc_en; i++) { - rptr = &(g_doc_regs[i]); - has_irq_pending = rptr->has_irq_pending; - if(has_irq_pending > num_osc_interrupt) { - has_irq_pending--; - rptr->has_irq_pending = has_irq_pending; - } - if(has_irq_pending == 1) { - first = i; - } - } - if(num_osc_interrupt == 1) { - doc_reg_e0 = (first << 1); - } else { -#if 0 - halt_printf("remove_sound_irq[%02x]=%d, first:%d\n", - osc, num_osc_interrupt, first); -#endif - } - } else { -#if 0 - /* make sure no int pending */ - if(doc_reg_e0 != 0xff) { - halt_printf("remove_sound_irq[%02x]=0, but e0: %02x\n", - osc, doc_reg_e0); - } -#endif - if(must) { - halt_printf("REMOVE_sound_irq[%02x]=0, but e0: %02x\n", - osc, doc_reg_e0); - } - } - - if(doc_reg_e0 & 0x80) { - for(i = 0; i < 0x20; i++) { - has_irq_pending = g_doc_regs[i].has_irq_pending; - if(has_irq_pending) { - halt_printf("remove_sound_irq[%02x], but " - "[%02x]=%d!\n", osc,i,has_irq_pending); - printf("num_osc_int: %d, first: %02x\n", - num_osc_interrupt, first); - } - } - } -} - -void -start_sound(int osc, double eff_dsamps, double dsamps) -{ - register word32 start_time1; - register word32 end_time1; - Doc_reg *rptr; - int ctl; - int mode; - word32 sz; - word32 size; - word32 wave_size; - - if(osc < 0 || osc > 31) { - halt_printf("start_sound: osc: %02x!\n", osc); - } - - g_num_start_sounds++; - - rptr = &(g_doc_regs[osc]); - - if(osc >= g_doc_num_osc_en) { - rptr->ctl |= 1; - return; - } - - GET_ITIMER(start_time1); - - ctl = rptr->ctl; - - mode = (ctl >> 1) & 3; - - wave_size = rptr->wavesize; - - sz = ((wave_size >> 3) & 7) + 8; - size = 1 << sz; - - if(size < 0x100) { - halt_printf("size: %08x is too small, sz: %08x!\n", size, sz); - } - - if(rptr->running) { - halt_printf("start_sound osc: %d, already running!\n", osc); - } - - rptr->running = 1; - - rptr->complete_dsamp = eff_dsamps; - - doc_printf("Starting osc %02x, dsamp: %f\n", osc, dsamps); - doc_printf("size: %04x\n", size); - - if((mode == 2) && ((osc & 1) == 0)) { - printf("Sync mode osc %d starting!\n", osc); - /* set_halt(1); */ - - /* see if we should start our odd partner */ - if((rptr[1].ctl & 7) == 5) { - /* odd partner stopped in sync mode--start him */ - rptr[1].ctl &= (~1); - start_sound(osc + 1, eff_dsamps, dsamps); - } else { - printf("Osc %d starting sync, but osc %d ctl: %02x\n", - osc, osc+1, rptr[1].ctl); - } - } - - wave_end_estimate(osc, eff_dsamps, dsamps); - - DOC_LOG("st playing", osc, eff_dsamps, size); -#if 0 - if(rptr->cur_acc != 0) { - halt_printf("Start osc %02x, acc: %08x\n", osc, rptr->cur_acc); - } -#endif - - GET_ITIMER(end_time1); - - g_cycs_in_start_sound += (end_time1 - start_time1); -} - -void -wave_end_estimate(int osc, double eff_dsamps, double dsamps) -{ - register word32 start_time1; - register word32 end_time1; - Doc_reg *rptr; - byte *ptr1; - double event_dsamp; - double event_dcycs; - double dcycs_per_samp; - double dsamps_per_byte; - double num_dsamps; - double dcur_inc; - word32 tmp1; - word32 cur_inc; - word32 save_val; - int save_size; - int pos; - int size; - int estimate; - - GET_ITIMER(start_time1); - - dcycs_per_samp = g_dcycs_per_samp; - - rptr = &(g_doc_regs[osc]); - - cur_inc = rptr->cur_inc; - dcur_inc = (double)cur_inc; - dsamps_per_byte = 0.0; - if(cur_inc) { - dsamps_per_byte = SND_PTR_SHIFT_DBL / (double)dcur_inc; - } - - /* see if there's a zero byte */ - tmp1 = rptr->cur_start + (rptr->cur_acc & rptr->cur_mask); - pos = tmp1 >> SND_PTR_SHIFT; - size = ((rptr->cur_end) >> SND_PTR_SHIFT) - pos; - - ptr1 = &doc_ram[pos]; - - estimate = 0; - if(rptr->ctl & 0x08 || g_doc_regs[osc ^ 1].ctl & 0x08) { - estimate = 1; - } - -#if 0 - estimate = 1; -#endif - if(estimate) { - save_size = size; - save_val = ptr1[size]; - ptr1[size] = 0; - size = strlen((char *)ptr1); - ptr1[save_size] = save_val; - } - - /* calc samples to play */ - num_dsamps = (dsamps_per_byte * (double)size) + 1.0; - - rptr->samps_left = (int)num_dsamps; - - if(rptr->event) { - remove_event_doc(osc); - } - rptr->event = 0; - - event_dsamp = eff_dsamps + num_dsamps; - if(estimate) { - rptr->event = 1; - rptr->dsamp_ev = event_dsamp; - rptr->dsamp_ev2 = dsamps; - event_dcycs = (event_dsamp * dcycs_per_samp) + 1.0; - add_event_doc(event_dcycs, osc); - } - - GET_ITIMER(end_time1); - - g_cycs_in_est_sound += (end_time1 - start_time1); -} - - -void -remove_sound_event(int osc) -{ - if(g_doc_regs[osc].event) { - g_doc_regs[osc].event = 0; - remove_event_doc(osc); - } -} - - -void -doc_write_ctl_reg(int osc, int val, double dsamps) -{ - Doc_reg *rptr; - double eff_dsamps; - word32 old_halt; - word32 new_halt; - int old_val; - int mode; - - if(osc < 0 || osc >= 0x20) { - halt_printf("doc_write_ctl_reg: osc: %02x, val: %02x\n", - osc, val); - return; - } - - eff_dsamps = dsamps; - rptr = &(g_doc_regs[osc]); - old_val = rptr->ctl; - g_doc_saved_ctl = old_val; - - if(old_val == val) { - return; - } - - DOC_LOG("ctl_reg", osc, dsamps, (old_val << 16) + val); - - mode = (val >> 1) & 3; - - old_halt = (old_val & 1); - new_halt = (val & 1); - - /* bits are: 28: old int bit */ - /* 29: old halt bit */ - /* 30: new int bit */ - /* 31: new halt bit */ - -#if 0 - if(osc == 0x10) { - printf("osc %d new_ctl: %02x, old: %02x\n", osc, val, old_val); - } -#endif - - /* no matter what, remove any pending IRQs on this osc */ - remove_sound_irq(osc, 0); - -#if 0 - if(old_halt) { - printf("doc_write_ctl to osc %d, val: %02x, old: %02x\n", - osc, val, old_val); - } -#endif - - if(new_halt != 0) { - /* make sure sound is stopped */ - remove_sound_event(osc); - if(old_halt == 0) { - /* it was playing, finish it up */ -#if 0 - halt_printf("Aborted osc %d at eff_dsamps: %f, ctl: " - "%02x, oldctl: %02x\n", osc, eff_dsamps, - val, old_val); -#endif - sound_play(eff_dsamps); - } - if(((old_val >> 1) & 3) > 0) { - /* don't clear acc if free-running */ - g_doc_regs[osc].cur_acc = 0; - } - - g_doc_regs[osc].ctl = val; - g_doc_regs[osc].running = 0; - } else { - /* new halt == 0 = make sure sound is running */ - if(old_halt != 0) { - /* start sound */ - DOC_LOG("ctl_sound_play", osc, eff_dsamps, val); - - // OG If the sound_play is executed, it may restart a oscillo we thought was stopped at time, - // hence crashing the start_sound function (cf. game Arrgh!) - //sound_play(eff_dsamps); - g_doc_regs[osc].ctl = val; - - start_sound(osc, eff_dsamps, dsamps); - } else { - /* was running, and something changed */ - doc_printf("osc %d old ctl:%02x new:%02x!\n", - osc, old_val, val); -#if 0 - sound_play(eff_dsamps); -/* HACK: fix this??? */ -#endif - g_doc_regs[osc].ctl = val; - if((old_val ^ val) & val & 0x8) { - /* now has ints on */ - wave_end_estimate(osc, dsamps, dsamps); - } - } - } -} - -void -doc_recalc_sound_parms(int osc, double eff_dcycs, double dsamps) -{ - Doc_reg *rptr; - double dfreq; - double dtmp1; - double dacc, dacc_recip; - word32 res; - word32 sz; - word32 size; - word32 wave_size; - word32 cur_start; - word32 shifted_size; - - g_num_recalc_snd_parms++; - - rptr = &(g_doc_regs[osc]); - - wave_size = rptr->wavesize; - - dfreq = (double)rptr->freq; - - sz = ((wave_size >> 3) & 7) + 8; - size = 1 << sz; - rptr->size_bytes = size; - res = wave_size & 7; - - shifted_size = size << SND_PTR_SHIFT; - - cur_start = (rptr->waveptr << (8 + SND_PTR_SHIFT)) & (-(int)shifted_size); // OG - - dtmp1 = dfreq * (DOC_SCAN_RATE * g_drecip_audio_rate); - dacc = (double)(1 << (20 - (17 - sz + res))); - dacc_recip = (SND_PTR_SHIFT_DBL) / ((double)(1 << 20)); - dtmp1 = dtmp1 * g_drecip_osc_en_plus_2 * dacc * dacc_recip; - - rptr->cur_inc = (int)(dtmp1); - rptr->cur_start = cur_start; - rptr->cur_end = cur_start + shifted_size; - rptr->cur_mask = (shifted_size - 1); - - DOC_LOG("recalc", osc, dsamps, (rptr->waveptr << 16) + wave_size); -} - -int -doc_read_c030(double dcycs) -{ - int num; - - num = g_num_c030_fsamps; - if(num >= MAX_C030_TIMES) { - halt_printf("Too many clicks per vbl: %d\n", num); - return 0; - } - - c030_fsamps[num] = (float)(dcycs * g_dsamps_per_dcyc - - g_last_sound_play_dsamp); - g_num_c030_fsamps = num + 1; - - doc_printf("read c030, num this vbl: %04x\n", num); - - return 0; -} - -int -doc_read_c03c(double dcycs) -{ - return doc_sound_ctl; -} - -int -doc_read_c03d(double dcycs) -{ - double dsamps; - Doc_reg *rptr; - int osc; - int type; - int ret; - - ret = doc_saved_val; - dsamps = dcycs * g_dsamps_per_dcyc; - - if(doc_sound_ctl & 0x40) { - /* Read RAM */ - doc_saved_val = doc_ram[g_c03ef_doc_ptr]; - } else { - /* Read DOC */ - doc_saved_val = 0; - - osc = g_c03ef_doc_ptr & 0x1f; - type = (g_c03ef_doc_ptr >> 5) & 0x7; - rptr = &(g_doc_regs[osc]); - - switch(type) { - case 0x0: /* freq lo */ - doc_saved_val = rptr->freq & 0xff; - break; - case 0x1: /* freq hi */ - doc_saved_val = rptr->freq >> 8; - break; - case 0x2: /* vol */ - doc_saved_val = rptr->vol; - break; - case 0x3: /* data register */ - /* HACK: make this call sound_play sometimes */ - doc_saved_val = rptr->last_samp_val; - break; - case 0x4: /* wave ptr register */ - doc_saved_val = rptr->waveptr; - break; - case 0x5: /* control register */ - doc_saved_val = rptr->ctl; - break; - case 0x6: /* control register */ - doc_saved_val = rptr->wavesize; - break; - case 0x7: /* 0xe0-0xff */ - switch(osc) { - case 0x00: /* 0xe0 */ - doc_saved_val = doc_reg_e0; - doc_printf("Reading doc 0xe0, ret: %02x\n", - doc_saved_val); - - /* Clear IRQ on read of e0, if any irq pend */ - if((doc_reg_e0 & 0x80) == 0) { - remove_sound_irq(doc_reg_e0 >> 1, 1); - } - break; - case 0x01: /* 0xe1 */ - doc_saved_val = (g_doc_num_osc_en - 1) << 1; - break; - case 0x02: /* 0xe2 */ - doc_saved_val = 0x80; -#if 0 - halt_printf("Reading doc 0xe2, ret: %02x\n", - doc_saved_val); -#endif - break; - default: - doc_saved_val = 0; - halt_printf("Reading bad doc_reg[%04x]: %02x\n", - g_c03ef_doc_ptr, doc_saved_val); - } - break; - default: - doc_saved_val = 0; - halt_printf("Reading bad doc_reg[%04x]: %02x\n", - g_c03ef_doc_ptr, doc_saved_val); - } - } - - doc_printf("read c03d, doc_ptr: %04x, ret: %02x, saved: %02x\n", - g_c03ef_doc_ptr, ret, doc_saved_val); - - DOC_LOG("read c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + - (doc_saved_val << 8) + ret); - - if(doc_sound_ctl & 0x20) { - g_c03ef_doc_ptr = (g_c03ef_doc_ptr + 1) & 0xffff; - } - - - return ret; -} - -void -doc_write_c03c(int val, double dcycs) -{ - int vol; - - vol = val & 0xf; - if(g_doc_vol != vol) { - /* don't bother playing sound..wait till next update */ - /* sound_play(dcycs); */ - - g_doc_vol = vol; - doc_printf("Setting doc vol to 0x%x at %f\n", - vol, dcycs); - } - DOC_LOG("c03c write", -1, dcycs * g_dsamps_per_dcyc, val); - - doc_sound_ctl = val; -} - -void -doc_write_c03d(int val, double dcycs) -{ - double dsamps; - double eff_dsamps; - Doc_reg *rptr; - int osc; - int type; - int ctl; - int tmp; - int i; - - val = val & 0xff; - - dsamps = dcycs * g_dsamps_per_dcyc; - eff_dsamps = dsamps; - doc_printf("write c03d, doc_ptr: %04x, val: %02x\n", - g_c03ef_doc_ptr, val); - - DOC_LOG("write c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + val); - - if(doc_sound_ctl & 0x40) { - /* RAM */ - doc_ram[g_c03ef_doc_ptr] = val; - } else { - /* DOC */ - osc = g_c03ef_doc_ptr & 0x1f; - type = (g_c03ef_doc_ptr >> 5) & 0x7; - - rptr = &(g_doc_regs[osc]); - ctl = rptr->ctl; -#if 0 - if((ctl & 1) == 0) { - if(type < 2 || type == 4 || type == 6) { - halt_printf("Osc %d is running, old ctl: %02x, " - "but write reg %02x=%02x\n", - osc, ctl, g_c03ef_doc_ptr & 0xff, val); - } - } -#endif - - switch(type) { - case 0x0: /* freq lo */ - if((rptr->freq & 0xff) == (word32)val) { - break; - } - if((ctl & 1) == 0) { - /* play through current status */ - DOC_LOG("flo_sound_play", osc, dsamps, val); - sound_play(dsamps); - } - rptr->freq = (rptr->freq & 0xff00) + val; - doc_recalc_sound_parms(osc, eff_dsamps, dsamps); - break; - case 0x1: /* freq hi */ - if((rptr->freq >> 8) == (word32)val) { - break; - } - if((ctl & 1) == 0) { - /* play through current status */ - DOC_LOG("fhi_sound_play", osc, dsamps, val); - sound_play(dsamps); - } - rptr->freq = (rptr->freq & 0xff) + (val << 8); - doc_recalc_sound_parms(osc, eff_dsamps, dsamps); - break; - case 0x2: /* vol */ - if(rptr->vol == (word32)val) { - break; - } - if((ctl & 1) == 0) { - /* play through current status */ - DOC_LOG("vol_sound_play", osc, dsamps, val); - sound_play(dsamps); -#if 0 - halt_printf("vol_sound_play at %.1f osc:%d " - "val:%d\n", dsamps, osc, val); -#endif - } - rptr->vol = val; - break; - case 0x3: /* data register */ -#if 0 - printf("Writing %02x into doc_data_reg[%02x]!\n", - val, osc); -#endif - break; - case 0x4: /* wave ptr register */ - if(rptr->waveptr == (word32)val) { - break; - } - if((ctl & 1) == 0) { - /* play through current status */ - DOC_LOG("wptr_sound_play", osc, dsamps, val); - sound_play(dsamps); - } - rptr->waveptr = val; - doc_recalc_sound_parms(osc, eff_dsamps, dsamps); - break; - case 0x5: /* control register */ -#if 0 - printf("doc_write ctl osc %d, val: %02x\n", osc, val); -#endif - if(rptr->ctl == (word32)val) { - break; - } - doc_write_ctl_reg(osc, val, dsamps); - break; - case 0x6: /* wavesize register */ - if(rptr->wavesize == (word32)val) { - break; - } - if((ctl & 1) == 0) { - /* play through current status */ - DOC_LOG("wsz_sound_play", osc, dsamps, val); - sound_play(dsamps); - } - rptr->wavesize = val; - doc_recalc_sound_parms(osc, eff_dsamps, dsamps); - break; - case 0x7: /* 0xe0-0xff */ - switch(osc) { - case 0x00: /* 0xe0 */ - doc_printf("writing doc 0xe0 with %02x, " - "was:%02x\n", val, doc_reg_e0); -#if 0 - if(val != doc_reg_e0) { - halt_printf("writing doc 0xe0 with " - "%02x, was:%02x\n", val, - doc_reg_e0); - } -#endif - break; - case 0x01: /* 0xe1 */ - doc_printf("Writing doc 0xe1 with %02x\n", val); - tmp = val & 0x3e; - tmp = (tmp >> 1) + 1; - if(tmp < 1) { - tmp = 1; - } - if(tmp > 32) { - halt_printf("doc 0xe1: %02x!\n", val); - tmp = 32; - } - g_doc_num_osc_en = tmp; - UPDATE_G_DCYCS_PER_DOC_UPDATE(tmp); - - // OG Update any oscs that were running to take care of the new numbers of oscillo - for(i = 0; ictl, rptr->waveptr, rptr->wavesize, rptr->freq, - rptr->vol, rptr->event, rptr->running, - rptr->has_irq_pending, rptr->size_bytes); - printf(" acc:%08x inc:%08x st:%08x end:%08x m:%08x\n", - rptr->cur_acc, rptr->cur_inc, rptr->cur_start, - rptr->cur_end, rptr->cur_mask); - printf(" compl_ds:%f samps_left:%d ev:%f ev2:%f\n", - rptr->complete_dsamp, rptr->samps_left, - rptr->dsamp_ev, rptr->dsamp_ev2); - } - -#if 0 - for(osc = 0; osc < 32; osc++) { - fmax = 0.0; - printf("osc %d has %d samps\n", osc, g_fsamp_num[osc]); - for(i = 0; i < g_fsamp_num[osc]; i++) { - printf("%4d: %f\n", i, g_fsamps[osc][i]); - fmax = MAX(fmax, g_fsamps[osc][i]); - } - printf("osc %d, fmax: %f\n", osc, fmax); - } -#endif -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 - 2012 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "defc.h" +#include "sound.h" + +extern int Verbose; +extern int g_use_shmem; +extern int g_preferred_rate; +extern int g_c03ef_doc_ptr; +extern double g_last_vbl_dcycs; +extern word32 g_vbl_count; + +void U_STACK_TRACE(); + +byte doc_ram[0x10000 + 16]; + +word32 doc_sound_ctl = 0; +word32 doc_saved_val = 0; +int g_doc_num_osc_en = 1; +double g_dcycs_per_doc_update = 1.0; +double g_dupd_per_dcyc = 1.0; +double g_drecip_osc_en_plus_2 = 1.0 / (double)(1 + 2); + +int g_doc_saved_ctl = 0; +int g_queued_samps = 0; +int g_queued_nonsamps = 0; +int g_num_osc_interrupting = 0; + +/* Workaround - gcc in cygwin wasn't defining _WIN32, substituted WIN_SOUND instead */ +#if defined(HPUX) || defined(__linux__) || defined(WIN_SOUND) || defined(MAC) || defined(HAVE_SDL) +int g_audio_enable = -1; +#else +# if defined(OSS) +/* default to off for now */ +int g_audio_enable = 0; +# else +/* Default to sound off */ +int g_audio_enable = 0; +# endif +#endif + +Doc_reg g_doc_regs[32]; + +word32 doc_reg_e0 = 0xff; + +/* local function prototypes */ +void doc_write_ctl_reg(int osc, int val, double dsamps); +void sound_write_sdl(int real_samps, int size); + +int g_audio_rate = 0; +double g_daudio_rate = 0.0; +double g_drecip_audio_rate = 0.0; +double g_dsamps_per_dcyc = 0.0; +double g_dcycs_per_samp = 0.0; +float g_fsamps_per_dcyc = 0.0; + +int g_doc_vol = 2; + +#define MAX_C030_TIMES 18000 + +double g_last_sound_play_dsamp = 0.0; + +float c030_fsamps[MAX_C030_TIMES + 1]; +int g_num_c030_fsamps = 0; + +#define DOC_SCAN_RATE (DCYCS_28_MHZ/32.0) + +int g_pipe_fd[2] = { -1, -1 }; +int g_pipe2_fd[2] = { -1, -1 }; +word32 *g_sound_shm_addr = 0; +int g_sound_shm_pos = 0; + +#define LEN_DOC_LOG 128 + +STRUCT(Doc_log) { + char *msg; + int osc; + double dsamps; + double dtmp2; + int etc; + Doc_reg doc_reg; +}; + +Doc_log g_doc_log[LEN_DOC_LOG]; +int g_doc_log_pos = 0; + + +#ifdef DO_DOC_LOG +# define DOC_LOG(a,b,c,d) doc_log_rout(a,b,c,d) +#else +# define DOC_LOG(a,b,c,d) +#endif + +#define UPDATE_G_DCYCS_PER_DOC_UPDATE(osc_en) \ + g_dcycs_per_doc_update = (double)((osc_en + 2) * DCYCS_1_MHZ) / \ + DOC_SCAN_RATE; \ + g_dupd_per_dcyc = 1.0 / g_dcycs_per_doc_update; \ + g_drecip_osc_en_plus_2 = 1.0 / (double)(osc_en + 2); + +#define SND_PTR_SHIFT 14 +#define SND_PTR_SHIFT_DBL ((double)(1 << SND_PTR_SHIFT)) + +void +doc_log_rout(char *msg, int osc, double dsamps, int etc) +{ + int pos; + + pos = g_doc_log_pos; + g_doc_log[pos].msg = msg; + g_doc_log[pos].osc = osc; + g_doc_log[pos].dsamps = dsamps; + g_doc_log[pos].dtmp2 = g_last_sound_play_dsamp; + g_doc_log[pos].etc = etc; + if(osc >= 0 && osc < 32) { + g_doc_log[pos].doc_reg = g_doc_regs[osc]; + } + pos++; + if(pos >= LEN_DOC_LOG) { + pos = 0; + } + + doc_printf("log: %s, osc:%d dsamp:%f, etc:%d\n", msg, osc, dsamps, etc); + + g_doc_log_pos = pos; +} + +extern double g_cur_dcycs; + +void +show_doc_log(void) +{ + FILE *docfile; + Doc_reg *rptr; + double dsamp_start; + int osc, ctl, freq; + int pos; + int i; + + docfile = fopen("doc_log_out", "w"); + if(docfile == 0) { + printf("fopen failed, errno: %d\n", errno); + return; + } + pos = g_doc_log_pos; + fprintf(docfile, "DOC log pos: %d\n", pos); + dsamp_start = g_doc_log[pos].dsamps; + for(i = 0; i < LEN_DOC_LOG; i++) { + rptr = &(g_doc_log[pos].doc_reg); + osc = g_doc_log[pos].osc; + ctl = rptr->ctl; + freq = rptr->freq; + if(osc < 0) { + ctl = 0; + freq = 0; + } + fprintf(docfile, "%03x:%03x: %-11s ds:%11.1f dt2:%10.1f " + "etc:%08x o:%02x c:%02x fq:%04x\n", + i, pos, g_doc_log[pos].msg, + g_doc_log[pos].dsamps - dsamp_start, + g_doc_log[pos].dtmp2, + g_doc_log[pos].etc, osc & 0xff, ctl, freq); + if(osc >= 0) { + fprintf(docfile, " ire:%d,%d,%d ptr4:%08x " + "inc4:%08x comp_ds:%.1f left:%04x, vol:%02x " + "wptr:%02x, wsz:%02x, 4st:%08x, 4end:%08x\n", + rptr->has_irq_pending, rptr->running, + rptr->event, 4*rptr->cur_acc, 4*rptr->cur_inc, + rptr->complete_dsamp - dsamp_start, + rptr->samps_left, rptr->vol, rptr->waveptr, + rptr->wavesize, 4*rptr->cur_start, + 4*rptr->cur_end); + } + pos++; + if(pos >= LEN_DOC_LOG) { + pos = 0; + } + } + + fprintf(docfile, "cur_dcycs: %f\n", g_cur_dcycs); + fprintf(docfile, "dsamps_now: %f\n", + (g_cur_dcycs * g_dsamps_per_dcyc) - dsamp_start); + fprintf(docfile, "g_doc_num_osc_en: %d\n", g_doc_num_osc_en); + fclose(docfile); +} + +void +sound_init() +{ + Doc_reg *rptr; + int i; + + for(i = 0; i < 32; i++) { + rptr = &(g_doc_regs[i]); + rptr->dsamp_ev = 0.0; + rptr->dsamp_ev2 = 0.0; + rptr->complete_dsamp = 0.0; + rptr->samps_left = 0; + rptr->cur_acc = 0; + rptr->cur_inc = 0; + rptr->cur_start = 0; + rptr->cur_end = 0; + rptr->cur_mask = 0; + rptr->size_bytes = 0; + rptr->event = 0; + rptr->running = 0; + rptr->has_irq_pending = 0; + rptr->freq = 0; + rptr->vol = 0; + rptr->waveptr = 0; + rptr->ctl = 1; + rptr->wavesize = 0; + rptr->last_samp_val = 0; + } + + // OG sound globals initialization + g_num_c030_fsamps = 0; + g_sound_shm_pos = 0; + g_queued_samps = 0; + g_queued_nonsamps = 0; + + doc_sound_ctl = 0; + doc_saved_val = 0; + g_doc_num_osc_en = 1; + g_dcycs_per_doc_update = 1.0; + g_dupd_per_dcyc = 1.0; + g_drecip_osc_en_plus_2 = 1.0 / (double)(1 + 2); + + doc_reg_e0 = 0xff; + g_audio_rate = 0; + g_daudio_rate = 0.0; + g_drecip_audio_rate = 0.0; + g_dsamps_per_dcyc = 0.0; + g_dcycs_per_samp = 0.0; + g_fsamps_per_dcyc = 0.0; + + g_doc_vol = 2; + + g_last_sound_play_dsamp = 0.0; + + sound_init_general(); +} + + +void +sound_init_general() +{ + printf("SOUND INIT GENERAL\n"); +/* Workaround - gcc in cygwin wasn't defining _WIN32 */ +#if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) && !defined(HAVE_SDL) + int pid; + int shmid; + int tmp; + int i; +#endif + + word32 *shmaddr; + int size; + int ret; + +/* Workaround - gcc in cygwin wasn't defining _WIN32 */ +#if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) && !defined(HAVE_SDL) + if(!g_use_shmem) { + if(g_audio_enable < 0) { + printf("Defaulting audio off for slow X display\n"); + g_audio_enable = 0; + } + } +#endif + + ret = 0; + + if(g_audio_enable == 0) { + set_audio_rate(g_preferred_rate); + return; + } + + size = SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE; +/* Workaround - gcc in cygwin wasn't defining _WIN32 */ +#if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) && !defined(HAVE_SDL) + shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); + if(shmid < 0) { + printf("sound_init: shmget ret: %d, errno: %d\n", shmid, errno); + exit(2); + } + + shmaddr = (word32*)shmat(shmid, 0, 0); + tmp = (int)PTR2WORD(shmaddr); + if(tmp == -1) { + printf("sound_init: shmat ret: %p, errno: %d\n", shmaddr, + errno); + exit(3); + } + + ret = shmctl(shmid, IPC_RMID, 0); + if(ret < 0) { + printf("sound_init: shmctl ret: %d, errno: %d\n", ret, errno); + exit(4); + } +#else + // windows and mac and sdl + shmaddr = (word32*)malloc(size); //size = 131072 + memset(shmaddr, 0, size); +#endif + + g_sound_shm_addr = shmaddr; + + fflush(stdout); +/* Workaround - gcc in cygwin wasn't defining _WIN32 */ +#if !defined(MAC) && !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(__OS2__) && !defined(HAVE_SDL) + /* prepare pipe so parent can signal child each other */ + /* pipe[0] = read side, pipe[1] = write end */ + ret = pipe(&g_pipe_fd[0]); + if(ret < 0) { + printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno); + exit(5); + } + ret = pipe(&g_pipe2_fd[0]); + if(ret < 0) { + printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno); + exit(5); + } + + + printf("pipes: pipe_fd = %d, %d pipe2_fd: %d,%d\n", + g_pipe_fd[0], g_pipe_fd[1], g_pipe2_fd[0], g_pipe2_fd[1]); + fflush(stdout); + + pid = fork(); + switch(pid) { + case 0: + /* child */ + /* close stdin and write-side of pipe */ + close(0); + /* Close other fds to make sure X window fd is closed */ + for(i = 3; i < 100; i++) { + if((i != g_pipe_fd[0]) && (i != g_pipe2_fd[1])) { + close(i); + } + } + close(g_pipe_fd[1]); /*make sure write pipe closed*/ + close(g_pipe2_fd[0]); /*make sure read pipe closed*/ + child_sound_loop(g_pipe_fd[0], g_pipe2_fd[1], g_sound_shm_addr); + printf("Child sound loop returned\n"); + exit(0); + case -1: + /* error */ + printf("sound_init: fork ret: -1, errno: %d\n", errno); + exit(6); + default: + /* parent */ + /* close read-side of pipe1, and the write side of pipe2 */ + close(g_pipe_fd[0]); + close(g_pipe2_fd[1]); + doc_printf("Child is pid: %d\n", pid); + } + + parent_sound_get_sample_rate(g_pipe2_fd[0]); +#else +# if defined (HAVE_SDL) + sdlsnd_init(shmaddr); +# elif defined (WIN_SOUND) + win32snd_init(shmaddr); +# elif defined (MAC) && !defined(HAVE_SDL) + macsnd_init(shmaddr); +# elif defined (__OS2__) +# endif +#endif + +} + +void +parent_sound_get_sample_rate(int read_fd) +{ +#ifndef __OS2__ + word32 tmp; + int ret; + + ret = read(read_fd, (char*)&tmp, 4); + if(ret != 4) { + printf("parent could not get audio sample rate from child, disabling sound.\n"); + printf("ret: %d, fd: %d errno:%d\n", ret, read_fd, errno); + g_audio_enable = 0; + } + close(read_fd); + + set_audio_rate(tmp); +#endif +} + +void +set_audio_rate(int rate) +{ + g_audio_rate = rate; + g_daudio_rate = (rate)*1.0; + g_drecip_audio_rate = 1.0/(rate); + g_dsamps_per_dcyc = ((rate*1.0) / DCYCS_1_MHZ); + g_dcycs_per_samp = (DCYCS_1_MHZ / (rate*1.0)); + g_fsamps_per_dcyc = (float)((rate*1.0) / DCYCS_1_MHZ); +} + +void +sound_reset(double dcycs) +{ + double dsamps; + int i; + + dsamps = dcycs * g_dsamps_per_dcyc; + for(i = 0; i < 32; i++) { + doc_write_ctl_reg(i, g_doc_regs[i].ctl | 1, dsamps); + doc_reg_e0 = 0xff; + if(g_doc_regs[i].has_irq_pending) { + halt_printf("reset: has_irq[%02x] = %d\n", i, + g_doc_regs[i].has_irq_pending); + } + g_doc_regs[i].has_irq_pending = 0; + } + if(g_num_osc_interrupting) { + halt_printf("reset: num_osc_int:%d\n", g_num_osc_interrupting); + } + g_num_osc_interrupting = 0; + +// OG No reason to reset the number of active oscillo on reset : this should only be done on startup. + /* + g_doc_num_osc_en = 1; + UPDATE_G_DCYCS_PER_DOC_UPDATE(1); + */ +} + +void +sound_shutdown() +{ + // OG stop sound and free memory on sound_shutdown + sound_reset(g_cur_dcycs); + +#ifdef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */ + win32snd_shutdown(); +#elif defined(__OS2__) +#elif defined(HAVE_SDL) + if((g_audio_enable != 0)) { + //sdlsnd_shutdown(); + sound_shutdown_sdl(); + } +#else + if((g_audio_enable != 0) && g_pipe_fd[1] != 0) { + close(g_pipe_fd[1]); + } +#endif + + // OG Free up allocated memory + if (g_sound_shm_addr) + { + free(g_sound_shm_addr); + g_sound_shm_addr = NULL; + } +} + + + +void +sound_update(double dcycs) +{ + double dsamps; + /* Called every VBL time to update sound status */ + + /* "play" sounds for this vbl */ + + dsamps = dcycs * g_dsamps_per_dcyc; + DOC_LOG("do_snd_pl", -1, dsamps, 0); + sound_play(dsamps); +} + +#define MAX_SND_BUF 65536 + +int g_samp_buf[2*MAX_SND_BUF]; +word32 zero_buf[SOUND_SHM_SAMP_SIZE]; + +double g_doc_dsamps_extra = 0.0; + +float g_fvoices = 0.0; + +word32 g_cycs_in_sound1 = 0; +word32 g_cycs_in_sound2 = 0; +word32 g_cycs_in_sound3 = 0; +word32 g_cycs_in_sound4 = 0; +word32 g_cycs_in_start_sound = 0; +word32 g_cycs_in_est_sound = 0; + +int g_num_snd_plays = 0; +int g_num_doc_events = 0; +int g_num_start_sounds = 0; +int g_num_scan_osc = 0; +int g_num_recalc_snd_parms = 0; + +word32 g_last_c030_vbl_count = 0; +int g_c030_state = 0; + +#define VAL_C030_RANGE (32768) +#define VAL_C030_BASE (-16384) + +int g_sound_file_num = 0; +FILE *g_sound_file_fd = 0; +int g_send_sound_to_file = 0; +int g_send_file_bytes = 0; + +void +open_sound_file() +{ + char name[256]; + FILE *fd; + + sprintf(name, "snd.out.%d", g_sound_file_num); + + fd = fopen(name, "wb+"); + if(fd == 0) { + printf("open_sound_file open errno: %d\n", errno); + exit(1); + } + + g_sound_file_fd = fd; + g_sound_file_num++; + g_send_file_bytes = 0; +} + +void +close_sound_file() +{ + if(g_sound_file_fd != 0) { + fclose(g_sound_file_fd); + } + + g_sound_file_fd = 0; +} + +void +check_for_range(word32 *addr, int num_samps, int offset) +{ + short *shortptr; + int i; + int left; + int right; + int max; + + max = -32768; + + if(num_samps > SOUND_SHM_SAMP_SIZE) { + halt_printf("num_samps: %d > %d!\n", num_samps, + SOUND_SHM_SAMP_SIZE); + } + + for(i = 0; i < num_samps; i++) { + shortptr = (short *)&(addr[i]); + left = shortptr[0]; + right = shortptr[1]; + if((left > 0x3000) || (right > 0x3000)) { + halt_printf("Sample %d of %d at snd_buf: %p is: " + "%d/%d\n", i + offset, num_samps, + &addr[i], left, right); + return; + } + + max = MAX(max, left); + max = MAX(max, right); + } + + printf("check4 max: %d over %d\n", max, num_samps); +} + +void +send_sound_to_file(word32 *addr, int shm_pos, int num_samps) +{ + int size; + int ret; + + if(g_sound_file_fd == 0) { + open_sound_file(); + } + + size = 0; + if((num_samps + shm_pos) > SOUND_SHM_SAMP_SIZE) { + size = SOUND_SHM_SAMP_SIZE - shm_pos; + g_send_file_bytes += (size * 4); + + ret = fwrite(&(addr[shm_pos]), 1, 4*size, g_sound_file_fd); + if(ret != 4*size) { + halt_printf("wrote %d not %d\n", ret, 4*size); + } + + if(g_doc_vol < 3) { + check_for_range(&(addr[shm_pos]), size, 0); + } else { + printf("Not checking %d bytes since vol: %d\n", + 4*size, g_doc_vol); + } + shm_pos = 0; + num_samps -= size; + } + + g_send_file_bytes += (num_samps * 4); + + ret = fwrite(&(addr[shm_pos]), 1, 4*num_samps, g_sound_file_fd); + if(ret != 4*num_samps) { + halt_printf("wrote %d not %d\n", ret, 4*num_samps); + } + + if(g_doc_vol < 3) { + check_for_range(&(addr[shm_pos]), num_samps, size); + } else { + printf("Not checking2 %d bytes since vol: %d\n", + 4*num_samps, g_doc_vol); + } + +} + + +// is called with real_samps = 1 to output sound +void +send_sound(int real_samps, int size) +{ + // real_samps = 1, size = 1602 + word32 tmp; + int ret; + + if(g_audio_enable == 0) { + printf("Entered send_sound but audio off!\n"); + exit(2); + } + // really does add this crazy high value. i guess it gets taken off / checked later + // so if size = 1602 (0x0642) it becomes 0xa2000642 + // wtf? + if(real_samps) { + tmp = size + 0xa2000000; + } else { + tmp = size + 0xa1000000; + } + DOC_LOG("send_sound", -1, g_last_sound_play_dsamp, + (real_samps << 30) + size); +// Workaround - gcc in cygwin wasn't defining _WIN32 +#if defined(WIN_SOUND) || defined(MAC) && !defined(HAVE_SDL) + ret = 0; + child_sound_playit(tmp); +#elif defined(HAVE_SDL) + sound_write_sdl( real_samps, size); + //sdl_send_audio(&g_sound_shm_addr[g_sound_shm_pos], size, real_samps); +#elif defined(__OS2__) + +#else + /* Although this looks like a big/little-endian issue, since the */ + /* child is also reading an int, it just works with no byte swap */ + ret = write(g_pipe_fd[1], &tmp, 4); + if(ret != 4) { + halt_printf("send_sound, wr ret: %d, errno: %d\n", ret, errno); + } +#endif +} + +void +show_c030_state() +{ + show_c030_samps(&(g_samp_buf[0]), 100); +} + +void +show_c030_samps(int *outptr, int num) +{ + int i; + + printf("c030_fsamps[]: %d\n", g_num_c030_fsamps); + + for(i = 0; i < g_num_c030_fsamps+2; i++) { + printf("%3d: %5.3f\n", i, c030_fsamps[i]); + } + + printf("Samples[] = %d\n", num); + + for(i = 0; i < num+2; i++) { + printf("%4d: %d %d\n", i, outptr[0], outptr[1]); + outptr += 2; + } +} + +int g_sound_play_depth = 0; + +void +sound_play(double dsamps) +{ + register word32 start_time1, start_time2, start_time3, start_time4; + register word32 end_time1, end_time2, end_time3; + Doc_reg *rptr; + int *outptr; + int *outptr_start; + word32 *sndptr; + double complete_dsamp; + double cur_dsamp; + double last_dsamp; + double dsamp_now; + double dnum_samps; + int val, val2; + int new_val; + float ftmp; + int imul; + int off; + int num; + float fsampnum; + float next_fsampnum; + int c030_lo_val, c030_hi_val; + float fc030_range; + float fc030_base; + int sampnum; + int next_sampnum; + float fpercent; + int c030_state; + int val0, val1; + word32 cur_acc; + word32 cur_pos; + word32 cur_mask; + word32 cur_inc; + word32 cur_end; + int ctl; + int num_osc_en; + int samps_left; + int samps_to_do; + int samps_played; + int samp_offset; + int snd_buf_init; + int pos; + int num_running; + int num_samps; + int osc; + int done; + int i, j; + + + GET_ITIMER(start_time1); + + g_num_snd_plays++; + if(g_sound_play_depth) { + halt_printf("Nested sound_play!\n"); + } + + g_sound_play_depth++; + + /* calc sample num */ + + last_dsamp = g_last_sound_play_dsamp; + num_samps = (int)(dsamps - g_last_sound_play_dsamp); + dnum_samps = (double)num_samps; + + dsamp_now = last_dsamp + dnum_samps; + + if(num_samps < 1) { + /* just say no */ + g_sound_play_depth--; + return; + } + + DOC_LOG("sound_play", -1, dsamp_now, num_samps); + + if(num_samps > MAX_SND_BUF) { + printf("num_samps: %d, too big!\n", num_samps); + g_sound_play_depth--; + return; + } + + + GET_ITIMER(start_time4); + + outptr_start = &(g_samp_buf[0]); + outptr = outptr_start; + + snd_buf_init = 0; + + samps_played = 0; + + num = g_num_c030_fsamps; + + if(num || ((g_vbl_count - g_last_c030_vbl_count) < 240)) { + + if(num) { + g_last_c030_vbl_count = g_vbl_count; + } + + pos = 0; + outptr = outptr_start; + c030_state = g_c030_state; + + c030_hi_val = ((VAL_C030_BASE + VAL_C030_RANGE)*g_doc_vol) >> 4; + c030_lo_val = (VAL_C030_BASE * g_doc_vol) >> 4; + + fc030_range = (float)(((VAL_C030_RANGE) * g_doc_vol) >> 4); + fc030_base = (float)(((VAL_C030_BASE) * g_doc_vol) >> 4); + + val = c030_lo_val; + if(c030_state) { + val = c030_hi_val; + } + + snd_buf_init++; + + c030_fsamps[num] = (float)(num_samps); + c030_fsamps[num+1] = (float)(num_samps+1); + + ftmp = (float)num_samps; + /* ensure that all samps are in range */ + for(i = num - 1; i >= 0; i--) { + if(c030_fsamps[i] > ftmp) { + c030_fsamps[i] = ftmp; + } + } + + num++; + fsampnum = c030_fsamps[0]; + sampnum = (int)fsampnum; + fpercent = (float)0.0; + i = 0; + + while(i < num) { + next_fsampnum = c030_fsamps[i+1]; + next_sampnum = (int)next_fsampnum; + if(sampnum < 0 || sampnum > num_samps) { + halt_printf("play c030: [%d]:%f is %d, > %d\n", + i, fsampnum, sampnum, num_samps); + break; + } + + /* write in samples to all samps < me */ + new_val = c030_lo_val; + if(c030_state) { + new_val = c030_hi_val; + } + for(j = pos; j < sampnum; j++) { + outptr[0] = new_val; + outptr[1] = new_val; + outptr += 2; + pos++; + } + + /* now, calculate me */ + fpercent = (float)0.0; + if(c030_state) { + fpercent = (fsampnum - (float)sampnum); + } + + c030_state = !c030_state; + + while(next_sampnum == sampnum) { + if(c030_state) { + fpercent += (next_fsampnum - fsampnum); + } + i++; + fsampnum = next_fsampnum; + + next_fsampnum = c030_fsamps[i+1]; + next_sampnum = (int)next_fsampnum; + c030_state = !c030_state; + } + + if(c030_state) { + /* add in fractional time */ + ftmp = (float)(int)(fsampnum + 1.0f); //OG added cast + fpercent += (ftmp - fsampnum); + } + + if((fpercent < (float)0.0) || (fpercent > (float)1.0)) { + halt_printf("fpercent: %d = %f\n", i, fpercent); + show_c030_samps(outptr_start, num_samps); + break; + } + + val = (int)((fpercent * fc030_range) + fc030_base); + outptr[0] = val; + outptr[1] = val; + outptr += 2; + pos++; + i++; + + sampnum = next_sampnum; + fsampnum = next_fsampnum; + } + + samps_played += num_samps; + + /* since we pretended to get one extra sample, we will */ + /* have toggled the speaker one time too many. Fix it */ + g_c030_state = !c030_state; + + if(g_send_sound_to_file) { + show_c030_samps(outptr_start, num_samps); + } + } + + g_num_c030_fsamps = 0; + + GET_ITIMER(start_time2); + + num_running = 0; + + num_osc_en = g_doc_num_osc_en; + + done = 0; + while(!done) { + done = 1; + for(j = 0; j < num_osc_en; j++) { + osc = j; + rptr = &(g_doc_regs[osc]); + complete_dsamp = rptr->complete_dsamp; + samps_left = rptr->samps_left; + cur_acc = rptr->cur_acc; + cur_mask = rptr->cur_mask; + cur_inc = rptr->cur_inc; + cur_end = rptr->cur_end; + if(!rptr->running || cur_inc == 0 || + (complete_dsamp >= dsamp_now)) { + continue; + } + + done = 0; + ctl = rptr->ctl; + + samp_offset = 0; + if(complete_dsamp > last_dsamp) { + samp_offset = (int)(complete_dsamp- last_dsamp); + if(samp_offset > num_samps) { + rptr->complete_dsamp = dsamp_now; + continue; + } + } + outptr = outptr_start + 2 * samp_offset; + if(ctl & 0x10) { + /* other channel */ + outptr += 1; + } + + imul = (rptr->vol * g_doc_vol); + off = imul * 128; + + samps_to_do = MIN(samps_left, num_samps - samp_offset); + if(imul == 0 || samps_to_do == 0) { + /* produce no sound */ + samps_left = samps_left - samps_to_do; + cur_acc += cur_inc * samps_to_do; + rptr->samps_left = samps_left; + rptr->cur_acc = cur_acc; + cur_dsamp = last_dsamp + + (double)(samps_to_do + samp_offset); + DOC_LOG("nosnd", osc, cur_dsamp, samps_to_do); + rptr->complete_dsamp = dsamp_now; + cur_pos = rptr->cur_start+(cur_acc & cur_mask); + if(samps_left <= 0) { + doc_sound_end(osc, 1, cur_dsamp, + dsamp_now); + val = 0; + j--; + } else { + val = doc_ram[cur_pos >> SND_PTR_SHIFT]; + } + rptr->last_samp_val = val; + continue; + } + + if(snd_buf_init == 0) { + memset(outptr_start, 0, + 2*sizeof(outptr_start[0])*num_samps); + snd_buf_init++; + } + + val = 0; + rptr->complete_dsamp = dsamp_now; + cur_pos = rptr->cur_start + (cur_acc & cur_mask); + for(i = 0; i < samps_to_do; i++) { + pos = cur_pos >> SND_PTR_SHIFT; + cur_pos += cur_inc; + cur_acc += cur_inc; + val = doc_ram[pos]; + + val2 = (val * imul - off) >> 4; + if((val == 0) || (cur_pos >= cur_end)) { + cur_dsamp = last_dsamp + + (double)(samp_offset + i + 1); + rptr->cur_acc = cur_acc; + rptr->samps_left = 0; + DOC_LOG("end or 0", osc, cur_dsamp, + (pos << 16) + ((i &0xff) << 8) + + val); + doc_sound_end(osc, val, cur_dsamp, + dsamp_now); + val = 0; + break; + } + + val2 = outptr[0] + val2; + + samps_left--; + *outptr = val2; + outptr += 2; + } + + rptr->last_samp_val = val; + + if(val != 0) { + rptr->cur_acc = cur_acc; + rptr->samps_left = samps_left; + rptr->complete_dsamp = dsamp_now; + } + + samps_played += samps_to_do; + DOC_LOG("splayed", osc, dsamp_now, + (samps_to_do << 16) + (pos & 0xffff)); + } + } + + GET_ITIMER(end_time2); + + g_cycs_in_sound2 += (end_time2 - start_time2); + + g_last_sound_play_dsamp = dsamp_now; + + GET_ITIMER(start_time3); + + outptr = outptr_start; + + pos = g_sound_shm_pos; + sndptr = g_sound_shm_addr; + +#if 0 + printf("samps_left: %d, num_samps: %d\n", samps_left, num_samps); +#endif + + if(g_audio_enable != 0) { + + if(snd_buf_init) { + /* convert sound buf */ + + + for(i = 0; i < num_samps; i++) { + val0 = outptr[0]; + val1 = outptr[1]; + val = val0; + if(val0 > 32767) { + val = 32767; + } + if(val0 < -32768) { + val = -32768; + } + + val0 = val; + val = val1; + if(val1 > 32767) { + val = 32767; + } + if(val1 < -32768) { + val = -32768; + } + + + outptr += 2; + +#if defined(__linux__) || defined(OSS) + /* Linux seems to expect little-endian */ + /* samples always, even on PowerPC */ +#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command + sndptr[pos] = (val << 16) + (val0 & 0xffff); +# else + sndptr[pos] = ((val & 0xff) << 24) + + ((val & 0xff00) << 8) + + ((val0 & 0xff) << 8) + + ((val0 >> 8) & 0xff); +# endif +#else +#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command + sndptr[pos] = (val << 16) + (val0 & 0xffff); +# else + sndptr[pos] = (val0 << 16) + (val & 0xffff); +# endif +#endif + // printf("%08x ", sndptr[pos]); + pos++; + if(pos >= SOUND_SHM_SAMP_SIZE) { + pos = 0; + } + } + + if(g_queued_nonsamps) { + /* force out old 0 samps */ + send_sound(0, g_queued_nonsamps); + g_queued_nonsamps = 0; + } + + if(g_send_sound_to_file) { + send_sound_to_file(g_sound_shm_addr, + g_sound_shm_pos, num_samps); + } + + g_queued_samps += num_samps; + } else { + /* move pos */ + pos += num_samps; + while(pos >= SOUND_SHM_SAMP_SIZE) { + pos -= SOUND_SHM_SAMP_SIZE; + } + + if(g_send_sound_to_file) { + send_sound_to_file(zero_buf, g_sound_shm_pos, + num_samps); + } + + if(g_queued_samps) { + /* force out old non-0 samps */ + send_sound(1, g_queued_samps); + g_queued_samps = 0; + } + + g_queued_nonsamps += num_samps; + } + + } + + g_sound_shm_pos = pos; + + + GET_ITIMER(end_time3); + + g_fvoices += ((float)(samps_played) * (float)(g_drecip_audio_rate)); + + if(g_audio_enable != 0) { + if(g_queued_samps >= (g_audio_rate/32)) { + send_sound(1, g_queued_samps); + g_queued_samps = 0; + } + + if(g_queued_nonsamps >= (g_audio_rate/32)) { + send_sound(0, g_queued_nonsamps); + g_queued_nonsamps = 0; + } + } + + GET_ITIMER(end_time1); + + g_cycs_in_sound1 += (end_time1 - start_time1); + g_cycs_in_sound3 += (end_time3 - start_time3); + g_cycs_in_sound4 += (start_time2 - start_time4); + + g_last_sound_play_dsamp = dsamp_now; + + g_sound_play_depth--; +} + + +void +doc_handle_event(int osc, double dcycs) +{ + double dsamps; + + /* handle osc stopping and maybe interrupting */ + + g_num_doc_events++; + + dsamps = dcycs * g_dsamps_per_dcyc; + + DOC_LOG("doc_ev", osc, dcycs, 0); + + g_doc_regs[osc].event = 0; + + sound_play(dsamps); + +} + +void +doc_sound_end(int osc, int can_repeat, double eff_dsamps, double dsamps) +{ + Doc_reg *rptr, *orptr; + int mode, omode; + int other_osc; + int one_shot_stop; + int ctl; + + /* handle osc stopping and maybe interrupting */ + + if(osc < 0 || osc > 31) { + printf("doc_handle_event: osc: %d!\n", osc); + return; + } + + rptr = &(g_doc_regs[osc]); + ctl = rptr->ctl; + + if(rptr->event) { + remove_event_doc(osc); + } + rptr->event = 0; + + /* check to make sure osc is running */ + if(ctl & 0x01) { + /* Oscillator already stopped. */ + halt_printf("Osc %d interrupt, but it was already stop!\n",osc); +#ifdef HPUX + U_STACK_TRACE(); +#endif + return; + } + + if(ctl & 0x08) { + if(rptr->has_irq_pending == 0) { + add_sound_irq(osc); + } + } + + if(!rptr->running) { + halt_printf("Doc event for osc %d, but ! running\n", osc); + } + + rptr->running = 0; + + mode = (ctl >> 1) & 3; + other_osc = osc ^ 1; + orptr = &(g_doc_regs[other_osc]); + omode = (orptr->ctl >> 1) & 3; + + /* If either this osc or it's partner is in swap mode, treat the */ + /* pair as being in swap mode. This Ensoniq feature pointed out */ + /* by Ian Schmidt */ + if(mode == 0 && can_repeat) { + /* free-running mode with no 0 byte! */ + /* start doing it again */ + + start_sound(osc, eff_dsamps, dsamps); + + return; + } + rptr->cur_acc = 0; /* reset internal accumulator*/ + if((mode == 3) || (omode == 3)) { + /* swap mode (even if we're one_shot and partner is swap)! */ + rptr->ctl |= 1; + if(!orptr->running && + (orptr->ctl & 0x1)) { + orptr->ctl = orptr->ctl & (~1); + start_sound(other_osc, eff_dsamps, dsamps); + } + return; + } else { + /* stop the oscillator */ + rptr->ctl |= 1; + } + + return; +} + +void +add_sound_irq(int osc) +{ + int num_osc_interrupting; + + if(g_doc_regs[osc].has_irq_pending) { + halt_printf("Adding sound_irq for %02x, but irq_p: %d\n", osc, + g_doc_regs[osc].has_irq_pending); + } + + num_osc_interrupting = g_num_osc_interrupting + 1; + g_doc_regs[osc].has_irq_pending = num_osc_interrupting; + g_num_osc_interrupting = num_osc_interrupting; + + add_irq(IRQ_PENDING_DOC); + if(num_osc_interrupting == 1) { + doc_reg_e0 = 0x00 + (osc << 1); + } + + DOC_LOG("add_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); +} + +void +remove_sound_irq(int osc, int must) +{ + Doc_reg *rptr; + int num_osc_interrupt; + int has_irq_pending; + int first; + int i; + + doc_printf("remove irq for osc: %d, has_irq: %d\n", + osc, g_doc_regs[osc].has_irq_pending); + + num_osc_interrupt = g_doc_regs[osc].has_irq_pending; + first = 0; + if(num_osc_interrupt) { + g_num_osc_interrupting--; + g_doc_regs[osc].has_irq_pending = 0; + DOC_LOG("rem_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); + if(g_num_osc_interrupting == 0) { + remove_irq(IRQ_PENDING_DOC); + } + + first = 0x40 | (doc_reg_e0 >> 1); + /* if none found, then def = no ints */ + for(i = 0; i < g_doc_num_osc_en; i++) { + rptr = &(g_doc_regs[i]); + has_irq_pending = rptr->has_irq_pending; + if(has_irq_pending > num_osc_interrupt) { + has_irq_pending--; + rptr->has_irq_pending = has_irq_pending; + } + if(has_irq_pending == 1) { + first = i; + } + } + if(num_osc_interrupt == 1) { + doc_reg_e0 = (first << 1); + } else { +#if 0 + halt_printf("remove_sound_irq[%02x]=%d, first:%d\n", + osc, num_osc_interrupt, first); +#endif + } + } else { +#if 0 + /* make sure no int pending */ + if(doc_reg_e0 != 0xff) { + halt_printf("remove_sound_irq[%02x]=0, but e0: %02x\n", + osc, doc_reg_e0); + } +#endif + if(must) { + halt_printf("REMOVE_sound_irq[%02x]=0, but e0: %02x\n", + osc, doc_reg_e0); + } + } + + if(doc_reg_e0 & 0x80) { + for(i = 0; i < 0x20; i++) { + has_irq_pending = g_doc_regs[i].has_irq_pending; + if(has_irq_pending) { + halt_printf("remove_sound_irq[%02x], but " + "[%02x]=%d!\n", osc,i,has_irq_pending); + printf("num_osc_int: %d, first: %02x\n", + num_osc_interrupt, first); + } + } + } +} + +void +start_sound(int osc, double eff_dsamps, double dsamps) +{ + register word32 start_time1; + register word32 end_time1; + Doc_reg *rptr; + int ctl; + int mode; + word32 sz; + word32 size; + word32 wave_size; + + if(osc < 0 || osc > 31) { + halt_printf("start_sound: osc: %02x!\n", osc); + } + + g_num_start_sounds++; + + rptr = &(g_doc_regs[osc]); + + if(osc >= g_doc_num_osc_en) { + rptr->ctl |= 1; + return; + } + + GET_ITIMER(start_time1); + + ctl = rptr->ctl; + + mode = (ctl >> 1) & 3; + + wave_size = rptr->wavesize; + + sz = ((wave_size >> 3) & 7) + 8; + size = 1 << sz; + + if(size < 0x100) { + halt_printf("size: %08x is too small, sz: %08x!\n", size, sz); + } + + if(rptr->running) { + halt_printf("start_sound osc: %d, already running!\n", osc); + } + + rptr->running = 1; + + rptr->complete_dsamp = eff_dsamps; + + doc_printf("Starting osc %02x, dsamp: %f\n", osc, dsamps); + doc_printf("size: %04x\n", size); + + if((mode == 2) && ((osc & 1) == 0)) { + printf("Sync mode osc %d starting!\n", osc); + /* set_halt(1); */ + + /* see if we should start our odd partner */ + if((rptr[1].ctl & 7) == 5) { + /* odd partner stopped in sync mode--start him */ + rptr[1].ctl &= (~1); + start_sound(osc + 1, eff_dsamps, dsamps); + } else { + printf("Osc %d starting sync, but osc %d ctl: %02x\n", + osc, osc+1, rptr[1].ctl); + } + } + + wave_end_estimate(osc, eff_dsamps, dsamps); + + DOC_LOG("st playing", osc, eff_dsamps, size); +#if 0 + if(rptr->cur_acc != 0) { + halt_printf("Start osc %02x, acc: %08x\n", osc, rptr->cur_acc); + } +#endif + + GET_ITIMER(end_time1); + + g_cycs_in_start_sound += (end_time1 - start_time1); +} + +void +wave_end_estimate(int osc, double eff_dsamps, double dsamps) +{ + register word32 start_time1; + register word32 end_time1; + Doc_reg *rptr; + byte *ptr1; + double event_dsamp; + double event_dcycs; + double dcycs_per_samp; + double dsamps_per_byte; + double num_dsamps; + double dcur_inc; + word32 tmp1; + word32 cur_inc; + word32 save_val; + int save_size; + int pos; + int size; + int estimate; + + GET_ITIMER(start_time1); + + dcycs_per_samp = g_dcycs_per_samp; + + rptr = &(g_doc_regs[osc]); + + cur_inc = rptr->cur_inc; + dcur_inc = (double)cur_inc; + dsamps_per_byte = 0.0; + if(cur_inc) { + dsamps_per_byte = SND_PTR_SHIFT_DBL / (double)dcur_inc; + } + + /* see if there's a zero byte */ + tmp1 = rptr->cur_start + (rptr->cur_acc & rptr->cur_mask); + pos = tmp1 >> SND_PTR_SHIFT; + size = ((rptr->cur_end) >> SND_PTR_SHIFT) - pos; + + ptr1 = &doc_ram[pos]; + + estimate = 0; + if(rptr->ctl & 0x08 || g_doc_regs[osc ^ 1].ctl & 0x08) { + estimate = 1; + } + +#if 0 + estimate = 1; +#endif + if(estimate) { + save_size = size; + save_val = ptr1[size]; + ptr1[size] = 0; + size = strlen((char *)ptr1); + ptr1[save_size] = save_val; + } + + /* calc samples to play */ + num_dsamps = (dsamps_per_byte * (double)size) + 1.0; + + rptr->samps_left = (int)num_dsamps; + + if(rptr->event) { + remove_event_doc(osc); + } + rptr->event = 0; + + event_dsamp = eff_dsamps + num_dsamps; + if(estimate) { + rptr->event = 1; + rptr->dsamp_ev = event_dsamp; + rptr->dsamp_ev2 = dsamps; + event_dcycs = (event_dsamp * dcycs_per_samp) + 1.0; + add_event_doc(event_dcycs, osc); + } + + GET_ITIMER(end_time1); + + g_cycs_in_est_sound += (end_time1 - start_time1); +} + + +void +remove_sound_event(int osc) +{ + if(g_doc_regs[osc].event) { + g_doc_regs[osc].event = 0; + remove_event_doc(osc); + } +} + + +void +doc_write_ctl_reg(int osc, int val, double dsamps) +{ + Doc_reg *rptr; + double eff_dsamps; + word32 old_halt; + word32 new_halt; + int old_val; + int mode; + + if(osc < 0 || osc >= 0x20) { + halt_printf("doc_write_ctl_reg: osc: %02x, val: %02x\n", + osc, val); + return; + } + + eff_dsamps = dsamps; + rptr = &(g_doc_regs[osc]); + old_val = rptr->ctl; + g_doc_saved_ctl = old_val; + + if(old_val == val) { + return; + } + + DOC_LOG("ctl_reg", osc, dsamps, (old_val << 16) + val); + + mode = (val >> 1) & 3; + + old_halt = (old_val & 1); + new_halt = (val & 1); + + /* bits are: 28: old int bit */ + /* 29: old halt bit */ + /* 30: new int bit */ + /* 31: new halt bit */ + +#if 0 + if(osc == 0x10) { + printf("osc %d new_ctl: %02x, old: %02x\n", osc, val, old_val); + } +#endif + + /* no matter what, remove any pending IRQs on this osc */ + remove_sound_irq(osc, 0); + +#if 0 + if(old_halt) { + printf("doc_write_ctl to osc %d, val: %02x, old: %02x\n", + osc, val, old_val); + } +#endif + + if(new_halt != 0) { + /* make sure sound is stopped */ + remove_sound_event(osc); + if(old_halt == 0) { + /* it was playing, finish it up */ +#if 0 + halt_printf("Aborted osc %d at eff_dsamps: %f, ctl: " + "%02x, oldctl: %02x\n", osc, eff_dsamps, + val, old_val); +#endif + sound_play(eff_dsamps); + } + if(((old_val >> 1) & 3) > 0) { + /* don't clear acc if free-running */ + g_doc_regs[osc].cur_acc = 0; + } + + g_doc_regs[osc].ctl = val; + g_doc_regs[osc].running = 0; + } else { + /* new halt == 0 = make sure sound is running */ + if(old_halt != 0) { + /* start sound */ + DOC_LOG("ctl_sound_play", osc, eff_dsamps, val); + + // OG If the sound_play is executed, it may restart a oscillo we thought was stopped at time, + // hence crashing the start_sound function (cf. game Arrgh!) + //sound_play(eff_dsamps); + g_doc_regs[osc].ctl = val; + + start_sound(osc, eff_dsamps, dsamps); + } else { + /* was running, and something changed */ + doc_printf("osc %d old ctl:%02x new:%02x!\n", + osc, old_val, val); +#if 0 + sound_play(eff_dsamps); +/* HACK: fix this??? */ +#endif + g_doc_regs[osc].ctl = val; + if((old_val ^ val) & val & 0x8) { + /* now has ints on */ + wave_end_estimate(osc, dsamps, dsamps); + } + } + } +} + +void +doc_recalc_sound_parms(int osc, double eff_dcycs, double dsamps) +{ + Doc_reg *rptr; + double dfreq; + double dtmp1; + double dacc, dacc_recip; + word32 res; + word32 sz; + word32 size; + word32 wave_size; + word32 cur_start; + word32 shifted_size; + + g_num_recalc_snd_parms++; + + rptr = &(g_doc_regs[osc]); + + wave_size = rptr->wavesize; + + dfreq = (double)rptr->freq; + + sz = ((wave_size >> 3) & 7) + 8; + size = 1 << sz; + rptr->size_bytes = size; + res = wave_size & 7; + + shifted_size = size << SND_PTR_SHIFT; + + cur_start = (rptr->waveptr << (8 + SND_PTR_SHIFT)) & (-(int)shifted_size); // OG + + dtmp1 = dfreq * (DOC_SCAN_RATE * g_drecip_audio_rate); + dacc = (double)(1 << (20 - (17 - sz + res))); + dacc_recip = (SND_PTR_SHIFT_DBL) / ((double)(1 << 20)); + dtmp1 = dtmp1 * g_drecip_osc_en_plus_2 * dacc * dacc_recip; + + rptr->cur_inc = (int)(dtmp1); + rptr->cur_start = cur_start; + rptr->cur_end = cur_start + shifted_size; + rptr->cur_mask = (shifted_size - 1); + + DOC_LOG("recalc", osc, dsamps, (rptr->waveptr << 16) + wave_size); +} + +int +doc_read_c030(double dcycs) +{ + int num; + + num = g_num_c030_fsamps; + if(num >= MAX_C030_TIMES) { + halt_printf("Too many clicks per vbl: %d\n", num); + return 0; + } + + c030_fsamps[num] = (float)(dcycs * g_dsamps_per_dcyc - + g_last_sound_play_dsamp); + g_num_c030_fsamps = num + 1; + + doc_printf("read c030, num this vbl: %04x\n", num); + + return 0; +} + +int +doc_read_c03c(double dcycs) +{ + return doc_sound_ctl; +} + +int +doc_read_c03d(double dcycs) +{ + double dsamps; + Doc_reg *rptr; + int osc; + int type; + int ret; + + ret = doc_saved_val; + dsamps = dcycs * g_dsamps_per_dcyc; + + if(doc_sound_ctl & 0x40) { + /* Read RAM */ + doc_saved_val = doc_ram[g_c03ef_doc_ptr]; + } else { + /* Read DOC */ + doc_saved_val = 0; + + osc = g_c03ef_doc_ptr & 0x1f; + type = (g_c03ef_doc_ptr >> 5) & 0x7; + rptr = &(g_doc_regs[osc]); + + switch(type) { + case 0x0: /* freq lo */ + doc_saved_val = rptr->freq & 0xff; + break; + case 0x1: /* freq hi */ + doc_saved_val = rptr->freq >> 8; + break; + case 0x2: /* vol */ + doc_saved_val = rptr->vol; + break; + case 0x3: /* data register */ + /* HACK: make this call sound_play sometimes */ + doc_saved_val = rptr->last_samp_val; + break; + case 0x4: /* wave ptr register */ + doc_saved_val = rptr->waveptr; + break; + case 0x5: /* control register */ + doc_saved_val = rptr->ctl; + break; + case 0x6: /* control register */ + doc_saved_val = rptr->wavesize; + break; + case 0x7: /* 0xe0-0xff */ + switch(osc) { + case 0x00: /* 0xe0 */ + doc_saved_val = doc_reg_e0; + doc_printf("Reading doc 0xe0, ret: %02x\n", + doc_saved_val); + + /* Clear IRQ on read of e0, if any irq pend */ + if((doc_reg_e0 & 0x80) == 0) { + remove_sound_irq(doc_reg_e0 >> 1, 1); + } + break; + case 0x01: /* 0xe1 */ + doc_saved_val = (g_doc_num_osc_en - 1) << 1; + break; + case 0x02: /* 0xe2 */ + doc_saved_val = 0x80; +#if 0 + halt_printf("Reading doc 0xe2, ret: %02x\n", + doc_saved_val); +#endif + break; + default: + doc_saved_val = 0; + halt_printf("Reading bad doc_reg[%04x]: %02x\n", + g_c03ef_doc_ptr, doc_saved_val); + } + break; + default: + doc_saved_val = 0; + halt_printf("Reading bad doc_reg[%04x]: %02x\n", + g_c03ef_doc_ptr, doc_saved_val); + } + } + + doc_printf("read c03d, doc_ptr: %04x, ret: %02x, saved: %02x\n", + g_c03ef_doc_ptr, ret, doc_saved_val); + + DOC_LOG("read c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + + (doc_saved_val << 8) + ret); + + if(doc_sound_ctl & 0x20) { + g_c03ef_doc_ptr = (g_c03ef_doc_ptr + 1) & 0xffff; + } + + + return ret; +} + +void +doc_write_c03c(int val, double dcycs) +{ + int vol; + + vol = val & 0xf; + if(g_doc_vol != vol) { + /* don't bother playing sound..wait till next update */ + /* sound_play(dcycs); */ + + g_doc_vol = vol; + doc_printf("Setting doc vol to 0x%x at %f\n", + vol, dcycs); + } + DOC_LOG("c03c write", -1, dcycs * g_dsamps_per_dcyc, val); + + doc_sound_ctl = val; +} + +void +doc_write_c03d(int val, double dcycs) +{ + double dsamps; + double eff_dsamps; + Doc_reg *rptr; + int osc; + int type; + int ctl; + int tmp; + int i; + + val = val & 0xff; + + dsamps = dcycs * g_dsamps_per_dcyc; + eff_dsamps = dsamps; + doc_printf("write c03d, doc_ptr: %04x, val: %02x\n", + g_c03ef_doc_ptr, val); + + DOC_LOG("write c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + val); + + if(doc_sound_ctl & 0x40) { + /* RAM */ + doc_ram[g_c03ef_doc_ptr] = val; + } else { + /* DOC */ + osc = g_c03ef_doc_ptr & 0x1f; + type = (g_c03ef_doc_ptr >> 5) & 0x7; + + rptr = &(g_doc_regs[osc]); + ctl = rptr->ctl; +#if 0 + if((ctl & 1) == 0) { + if(type < 2 || type == 4 || type == 6) { + halt_printf("Osc %d is running, old ctl: %02x, " + "but write reg %02x=%02x\n", + osc, ctl, g_c03ef_doc_ptr & 0xff, val); + } + } +#endif + + switch(type) { + case 0x0: /* freq lo */ + if((rptr->freq & 0xff) == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("flo_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->freq = (rptr->freq & 0xff00) + val; + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x1: /* freq hi */ + if((rptr->freq >> 8) == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("fhi_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->freq = (rptr->freq & 0xff) + (val << 8); + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x2: /* vol */ + if(rptr->vol == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("vol_sound_play", osc, dsamps, val); + sound_play(dsamps); +#if 0 + halt_printf("vol_sound_play at %.1f osc:%d " + "val:%d\n", dsamps, osc, val); +#endif + } + rptr->vol = val; + break; + case 0x3: /* data register */ +#if 0 + printf("Writing %02x into doc_data_reg[%02x]!\n", + val, osc); +#endif + break; + case 0x4: /* wave ptr register */ + if(rptr->waveptr == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("wptr_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->waveptr = val; + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x5: /* control register */ +#if 0 + printf("doc_write ctl osc %d, val: %02x\n", osc, val); +#endif + if(rptr->ctl == (word32)val) { + break; + } + doc_write_ctl_reg(osc, val, dsamps); + break; + case 0x6: /* wavesize register */ + if(rptr->wavesize == (word32)val) { + break; + } + if((ctl & 1) == 0) { + /* play through current status */ + DOC_LOG("wsz_sound_play", osc, dsamps, val); + sound_play(dsamps); + } + rptr->wavesize = val; + doc_recalc_sound_parms(osc, eff_dsamps, dsamps); + break; + case 0x7: /* 0xe0-0xff */ + switch(osc) { + case 0x00: /* 0xe0 */ + doc_printf("writing doc 0xe0 with %02x, " + "was:%02x\n", val, doc_reg_e0); +#if 0 + if(val != doc_reg_e0) { + halt_printf("writing doc 0xe0 with " + "%02x, was:%02x\n", val, + doc_reg_e0); + } +#endif + break; + case 0x01: /* 0xe1 */ + doc_printf("Writing doc 0xe1 with %02x\n", val); + tmp = val & 0x3e; + tmp = (tmp >> 1) + 1; + if(tmp < 1) { + tmp = 1; + } + if(tmp > 32) { + halt_printf("doc 0xe1: %02x!\n", val); + tmp = 32; + } + g_doc_num_osc_en = tmp; + UPDATE_G_DCYCS_PER_DOC_UPDATE(tmp); + + // OG Update any oscs that were running to take care of the new numbers of oscillo + for(i = 0; ictl, rptr->waveptr, rptr->wavesize, rptr->freq, + rptr->vol, rptr->event, rptr->running, + rptr->has_irq_pending, rptr->size_bytes); + printf(" acc:%08x inc:%08x st:%08x end:%08x m:%08x\n", + rptr->cur_acc, rptr->cur_inc, rptr->cur_start, + rptr->cur_end, rptr->cur_mask); + printf(" compl_ds:%f samps_left:%d ev:%f ev2:%f\n", + rptr->complete_dsamp, rptr->samps_left, + rptr->dsamp_ev, rptr->dsamp_ev2); + } + +#if 0 + for(osc = 0; osc < 32; osc++) { + fmax = 0.0; + printf("osc %d has %d samps\n", osc, g_fsamp_num[osc]); + for(i = 0; i < g_fsamp_num[osc]; i++) { + printf("%4d: %f\n", i, g_fsamps[osc][i]); + fmax = MAX(fmax, g_fsamps[osc][i]); + } + printf("osc %d, fmax: %f\n", osc, fmax); + } +#endif +} diff --git a/src/sound.h b/src/sound.h index 45c0439..5024e16 100644 --- a/src/sound.h +++ b/src/sound.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/sound_driver.c b/src/sound_driver.c index a709d2e..44f7d01 100644 --- a/src/sound_driver.c +++ b/src/sound_driver.c @@ -1,435 +1,437 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2012 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "defc.h" -#include "sound.h" - -#ifdef HPUX -# include -#endif -#ifdef HAVE_SDL -# include "SDL.h" -long sound_init_device_sdl(); -#endif - -#if defined(__linux__) || defined(OSS) -# include -#endif - -#ifndef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */ -# include -# include -#endif -#ifndef UNDER_CE -#include -#endif - - -extern int Verbose; - -extern int g_audio_rate; - -int g_preferred_rate = 48000; -int g_audio_socket = -1; -int g_bytes_written = 0; - -#define ZERO_BUF_SIZE 2048 - -word32 g_snd_zero_buf[ZERO_BUF_SIZE]; - -#define ZERO_PAUSE_SAFETY_SAMPS (g_audio_rate >> 5) -#define ZERO_PAUSE_NUM_SAMPS (4*g_audio_rate) - -int g_zeroes_buffered = 0; -int g_zeroes_seen = 0; -int g_sound_paused = 0; -int g_childsnd_vbl = 0; -int g_childsnd_pos = 0; -word32 *g_childsnd_shm_addr = 0; - -void child_sound_init_linux(); -void child_sound_init_hpdev(); -void child_sound_initWIN_SOUND(); -void child_sound_init_mac(); -void child_sound_init_sdl(); -long sound_init_device_sdl(); - -void -reliable_buf_write(word32 *shm_addr, int pos, int size) -{ - byte *ptr; - int ret; - - if(size < 1 || pos < 0 || pos > SOUND_SHM_SAMP_SIZE || - size > SOUND_SHM_SAMP_SIZE || - (pos + size) > SOUND_SHM_SAMP_SIZE) { - printf("reliable_buf_write: pos: %04x, size: %04x\n", pos, size); - exit(1); - } - - ptr = (byte *)&(shm_addr[pos]); - size = size * 4; - - while(size > 0) { -#if defined(HAVE_SDL) - //ret = sdl_send_audio(ptr, size); - -#elif defined(WIN_SOUND) - ret = win32_send_audio(ptr, size); -#elif defined(MAC) && !defined(HAVE_SDL) - ret = mac_send_audio(ptr, size); -#else - ret = write(g_audio_socket, ptr, size); -#endif - - if(ret < 0) { - printf("audio write, errno: %d\n", errno); - exit(1); - } - size = size - ret; - ptr += ret; - g_bytes_written += ret; - } - -} - -void -reliable_zero_write(int amt) -{ - int len; - - while(amt > 0) { - len = MIN(amt, ZERO_BUF_SIZE); - reliable_buf_write(g_snd_zero_buf, 0, len); - amt -= len; - } -} - - -void -child_sound_loop(int read_fd, int write_fd, word32 *shm_addr) -{ - word32 tmp; - int ret; - - g_audio_rate = g_preferred_rate; - - g_zeroes_buffered = 0; - g_zeroes_seen = 0; - g_sound_paused = 0; - - g_childsnd_pos = 0; - g_childsnd_vbl = 0; - g_childsnd_shm_addr = shm_addr; - -#if defined(HAVE_SDL) - //child_sound_init_sdl(); - long rate = sound_init_device_sdl(); - return; -#elif defined(__linux__) || defined(OSS) - child_sound_init_linux(); -#elif HPUX - child_sound_init_hpdev(); -#elif WIN_SOUND - child_sound_init_win32(); - return; -#elif defined(MAC) && !defined(HAVE_SDL) - child_sound_init_mac(); - return; -#endif - - doc_printf("Child pipe fd: %d\n", read_fd); - - tmp = g_audio_rate; - ret = write(write_fd, &tmp, 4); - if(ret != 4) { - printf("Unable to send back audio rate to parent\n"); - printf("ret: %d fd: %d, errno: %d\n", ret, write_fd, errno); - exit(1); - } - printf("Wrote to fd %d the audio rate\n", write_fd); - - close(write_fd); - - while(1) { - errno = 0; - ret = read(read_fd, (char*)&tmp, 4); - if(ret <= 0) { - printf("child dying from ret: %d, errno: %d\n", - ret, errno); - break; - } - - child_sound_playit(tmp); - } - -#ifdef HPUX - ioctl(g_audio_socket, AUDIO_DRAIN, 0); -#endif - close(g_audio_socket); - - exit(0); -} - -// called by sound.c:send_sound() -void -child_sound_playit(word32 tmp) -{ - int size; - - size = tmp & 0xffffff; - printf("SIze: %d ",size); - if((tmp >> 24) == 0xa2) { - /* play sound here */ - - -#if 0 - g_childsnd_pos += g_zeroes_buffered; - while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { - g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; - } -#endif - - if(g_zeroes_buffered) { - reliable_zero_write(g_zeroes_buffered); - } - - g_zeroes_buffered = 0; - g_zeroes_seen = 0; - - // only write up to end of buffer - if((size + g_childsnd_pos) > SOUND_SHM_SAMP_SIZE) { - reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, - SOUND_SHM_SAMP_SIZE - g_childsnd_pos); - size = (g_childsnd_pos + size) - SOUND_SHM_SAMP_SIZE; - g_childsnd_pos = 0; - } - - reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, size); - - if(g_sound_paused) { - printf("Unpausing sound, zb: %d\n", g_zeroes_buffered); - g_sound_paused = 0; - } - - } else if((tmp >> 24) == 0xa1) { - if(g_sound_paused) { - if(g_zeroes_buffered < ZERO_PAUSE_SAFETY_SAMPS) { - g_zeroes_buffered += size; - } - } else { - /* not paused, send it through */ - g_zeroes_seen += size; - - reliable_zero_write(size); - - if(g_zeroes_seen >= ZERO_PAUSE_NUM_SAMPS) { - printf("Pausing sound\n"); - g_sound_paused = 1; - } - } - } else { - printf("tmp received bad: %08x\n", tmp); - exit(3); - } - - g_childsnd_pos += size; - while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { - g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; - } - - g_childsnd_vbl++; - if(g_childsnd_vbl >= 60) { - g_childsnd_vbl = 0; - g_bytes_written = 0; - } -} - - -#ifdef HPUX -void -child_sound_init_hpdev() -{ - struct audio_describe audio_descr; - int output_channel; - char *str; - int speaker; - int ret; - int i; - - g_audio_socket = open("/dev/audio", O_WRONLY, 0); - if(g_audio_socket < 0) { - printf("open /dev/audio failed, ret: %d, errno:%d\n", - g_audio_socket, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_DESCRIBE, &audio_descr); - if(ret < 0) { - printf("ioctl AUDIO_DESCRIBE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - for(i = 0; i < audio_descr.nrates; i++) { - printf("Audio rate[%d] = %d\n", i, - audio_descr.sample_rate[i]); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_DATA_FORMAT, - AUDIO_FORMAT_LINEAR16BIT); - if(ret < 0) { - printf("ioctl AUDIO_SET_DATA_FORMAT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_CHANNELS, NUM_CHANNELS); - if(ret < 0) { - printf("ioctl AUDIO_SET_CHANNELS failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_TXBUFSIZE, 16*1024); - if(ret < 0) { - printf("ioctl AUDIO_SET_TXBUFSIZE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_SET_SAMPLE_RATE, g_audio_rate); - if(ret < 0) { - printf("ioctl AUDIO_SET_SAMPLE_RATE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_GET_OUTPUT, &output_channel); - if(ret < 0) { - printf("ioctl AUDIO_GET_OUTPUT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - - speaker = 1; - str = getenv("SPEAKER"); - if(str) { - if(str[0] != 'i' && str[0] != 'I') { - speaker = 0; - } - } - - if(speaker) { - printf("Sending sound to internal speaker\n"); - output_channel |= AUDIO_OUT_SPEAKER; - } else { - printf("Sending sound to external jack\n"); - output_channel &= (~AUDIO_OUT_SPEAKER); - output_channel |= AUDIO_OUT_HEADPHONE; - } - - ret = ioctl(g_audio_socket, AUDIO_SET_OUTPUT, output_channel); - if(ret < 0) { - printf("ioctl AUDIO_SET_OUTPUT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } -} -#endif /* HPUX */ - -#if defined(__linux__) || defined(OSS) -void -child_sound_init_linux() -{ - int stereo; - int sample_size; - int rate; - int fragment; - int fmt; - int ret; - - g_audio_socket = open("/dev/dsp", O_WRONLY, 0); - if(g_audio_socket < 0) { - printf("open /dev/dsp failed, ret: %d, errno:%d\n", - g_audio_socket, errno); - exit(1); - } - - fragment = 0x00200009; -#if 0 - ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFRAGMENT, &fragment); - if(ret < 0) { - printf("ioctl SETFRAGEMNT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } -#endif - - sample_size = 16; - ret = ioctl(g_audio_socket, SNDCTL_DSP_SAMPLESIZE, &sample_size); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_SAMPLESIZE failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - -#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - fmt = AFMT_S16_LE; -#else - fmt = AFMT_S16_BE; -#endif - ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFMT, &fmt); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_SETFMT failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - stereo = 1; - ret = ioctl(g_audio_socket, SNDCTL_DSP_STEREO, &stereo); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_STEREO failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - - rate = g_audio_rate; - ret = ioctl(g_audio_socket, SNDCTL_DSP_SPEED, &rate); - if(ret < 0) { - printf("ioctl SNDCTL_DSP_SPEED failed, ret:%d, errno:%d\n", - ret, errno); - exit(1); - } - if(ret > 0) { - rate = ret; /* rate is returned value */ - } - if(rate < 8000) { - printf("Audio rate of %d which is < 8000!\n", rate); - exit(1); - } - - g_audio_rate = rate; - - printf("Sound initialized\n"); -} -#endif +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 - 2012 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "defc.h" +#include "sound.h" + +#ifdef HPUX +# include +#endif +#ifdef HAVE_SDL +# include "SDL.h" +long sound_init_device_sdl(); +#endif + +#if defined(__linux__) || defined(OSS) +# include +#endif + +#ifndef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */ +# include +# include +#endif +#ifndef UNDER_CE +#include +#endif + + +extern int Verbose; + +extern int g_audio_rate; + +int g_preferred_rate = 48000; +int g_audio_socket = -1; +int g_bytes_written = 0; + +#define ZERO_BUF_SIZE 2048 + +word32 g_snd_zero_buf[ZERO_BUF_SIZE]; + +#define ZERO_PAUSE_SAFETY_SAMPS (g_audio_rate >> 5) +#define ZERO_PAUSE_NUM_SAMPS (4*g_audio_rate) + +int g_zeroes_buffered = 0; +int g_zeroes_seen = 0; +int g_sound_paused = 0; +int g_childsnd_vbl = 0; +int g_childsnd_pos = 0; +word32 *g_childsnd_shm_addr = 0; + +void child_sound_init_linux(); +void child_sound_init_hpdev(); +void child_sound_initWIN_SOUND(); +void child_sound_init_mac(); +void child_sound_init_sdl(); +long sound_init_device_sdl(); + +void +reliable_buf_write(word32 *shm_addr, int pos, int size) +{ + byte *ptr; + int ret; + + if(size < 1 || pos < 0 || pos > SOUND_SHM_SAMP_SIZE || + size > SOUND_SHM_SAMP_SIZE || + (pos + size) > SOUND_SHM_SAMP_SIZE) { + printf("reliable_buf_write: pos: %04x, size: %04x\n", pos, size); + exit(1); + } + + ptr = (byte *)&(shm_addr[pos]); + size = size * 4; + + while(size > 0) { +#if defined(HAVE_SDL) + //ret = sdl_send_audio(ptr, size); + +#elif defined(WIN_SOUND) + ret = win32_send_audio(ptr, size); +#elif defined(MAC) && !defined(HAVE_SDL) + ret = mac_send_audio(ptr, size); +#else + ret = write(g_audio_socket, ptr, size); +#endif + + if(ret < 0) { + printf("audio write, errno: %d\n", errno); + exit(1); + } + size = size - ret; + ptr += ret; + g_bytes_written += ret; + } + +} + +void +reliable_zero_write(int amt) +{ + int len; + + while(amt > 0) { + len = MIN(amt, ZERO_BUF_SIZE); + reliable_buf_write(g_snd_zero_buf, 0, len); + amt -= len; + } +} + + +void +child_sound_loop(int read_fd, int write_fd, word32 *shm_addr) +{ + word32 tmp; + int ret; + + g_audio_rate = g_preferred_rate; + + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + g_sound_paused = 0; + + g_childsnd_pos = 0; + g_childsnd_vbl = 0; + g_childsnd_shm_addr = shm_addr; + +#if defined(HAVE_SDL) + //child_sound_init_sdl(); + long rate = sound_init_device_sdl(); + return; +#elif defined(__linux__) || defined(OSS) + child_sound_init_linux(); +#elif HPUX + child_sound_init_hpdev(); +#elif WIN_SOUND + child_sound_init_win32(); + return; +#elif defined(MAC) && !defined(HAVE_SDL) + child_sound_init_mac(); + return; +#endif + + doc_printf("Child pipe fd: %d\n", read_fd); + + tmp = g_audio_rate; + ret = write(write_fd, &tmp, 4); + if(ret != 4) { + printf("Unable to send back audio rate to parent\n"); + printf("ret: %d fd: %d, errno: %d\n", ret, write_fd, errno); + exit(1); + } + printf("Wrote to fd %d the audio rate\n", write_fd); + + close(write_fd); + + while(1) { + errno = 0; + ret = read(read_fd, (char*)&tmp, 4); + if(ret <= 0) { + printf("child dying from ret: %d, errno: %d\n", + ret, errno); + break; + } + + child_sound_playit(tmp); + } + +#ifdef HPUX + ioctl(g_audio_socket, AUDIO_DRAIN, 0); +#endif + close(g_audio_socket); + + exit(0); +} + +// called by sound.c:send_sound() +void +child_sound_playit(word32 tmp) +{ + int size; + + size = tmp & 0xffffff; + printf("SIze: %d ",size); + if((tmp >> 24) == 0xa2) { + /* play sound here */ + + +#if 0 + g_childsnd_pos += g_zeroes_buffered; + while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { + g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; + } +#endif + + if(g_zeroes_buffered) { + reliable_zero_write(g_zeroes_buffered); + } + + g_zeroes_buffered = 0; + g_zeroes_seen = 0; + + // only write up to end of buffer + if((size + g_childsnd_pos) > SOUND_SHM_SAMP_SIZE) { + reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, + SOUND_SHM_SAMP_SIZE - g_childsnd_pos); + size = (g_childsnd_pos + size) - SOUND_SHM_SAMP_SIZE; + g_childsnd_pos = 0; + } + + reliable_buf_write(g_childsnd_shm_addr, g_childsnd_pos, size); + + if(g_sound_paused) { + printf("Unpausing sound, zb: %d\n", g_zeroes_buffered); + g_sound_paused = 0; + } + + } else if((tmp >> 24) == 0xa1) { + if(g_sound_paused) { + if(g_zeroes_buffered < ZERO_PAUSE_SAFETY_SAMPS) { + g_zeroes_buffered += size; + } + } else { + /* not paused, send it through */ + g_zeroes_seen += size; + + reliable_zero_write(size); + + if(g_zeroes_seen >= ZERO_PAUSE_NUM_SAMPS) { + printf("Pausing sound\n"); + g_sound_paused = 1; + } + } + } else { + printf("tmp received bad: %08x\n", tmp); + exit(3); + } + + g_childsnd_pos += size; + while(g_childsnd_pos >= SOUND_SHM_SAMP_SIZE) { + g_childsnd_pos -= SOUND_SHM_SAMP_SIZE; + } + + g_childsnd_vbl++; + if(g_childsnd_vbl >= 60) { + g_childsnd_vbl = 0; + g_bytes_written = 0; + } +} + + +#ifdef HPUX +void +child_sound_init_hpdev() +{ + struct audio_describe audio_descr; + int output_channel; + char *str; + int speaker; + int ret; + int i; + + g_audio_socket = open("/dev/audio", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/audio failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_DESCRIBE, &audio_descr); + if(ret < 0) { + printf("ioctl AUDIO_DESCRIBE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + for(i = 0; i < audio_descr.nrates; i++) { + printf("Audio rate[%d] = %d\n", i, + audio_descr.sample_rate[i]); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_DATA_FORMAT, + AUDIO_FORMAT_LINEAR16BIT); + if(ret < 0) { + printf("ioctl AUDIO_SET_DATA_FORMAT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_CHANNELS, NUM_CHANNELS); + if(ret < 0) { + printf("ioctl AUDIO_SET_CHANNELS failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_TXBUFSIZE, 16*1024); + if(ret < 0) { + printf("ioctl AUDIO_SET_TXBUFSIZE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_SET_SAMPLE_RATE, g_audio_rate); + if(ret < 0) { + printf("ioctl AUDIO_SET_SAMPLE_RATE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + ret = ioctl(g_audio_socket, AUDIO_GET_OUTPUT, &output_channel); + if(ret < 0) { + printf("ioctl AUDIO_GET_OUTPUT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + + speaker = 1; + str = getenv("SPEAKER"); + if(str) { + if(str[0] != 'i' && str[0] != 'I') { + speaker = 0; + } + } + + if(speaker) { + printf("Sending sound to internal speaker\n"); + output_channel |= AUDIO_OUT_SPEAKER; + } else { + printf("Sending sound to external jack\n"); + output_channel &= (~AUDIO_OUT_SPEAKER); + output_channel |= AUDIO_OUT_HEADPHONE; + } + + ret = ioctl(g_audio_socket, AUDIO_SET_OUTPUT, output_channel); + if(ret < 0) { + printf("ioctl AUDIO_SET_OUTPUT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } +} +#endif /* HPUX */ + +#if defined(__linux__) || defined(OSS) +void +child_sound_init_linux() +{ + int stereo; + int sample_size; + int rate; + int fragment; + int fmt; + int ret; + + g_audio_socket = open("/dev/dsp", O_WRONLY, 0); + if(g_audio_socket < 0) { + printf("open /dev/dsp failed, ret: %d, errno:%d\n", + g_audio_socket, errno); + exit(1); + } + + fragment = 0x00200009; +#if 0 + ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFRAGMENT, &fragment); + if(ret < 0) { + printf("ioctl SETFRAGEMNT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } +#endif + + sample_size = 16; + ret = ioctl(g_audio_socket, SNDCTL_DSP_SAMPLESIZE, &sample_size); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SAMPLESIZE failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + +#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command + fmt = AFMT_S16_LE; +#else + fmt = AFMT_S16_BE; +#endif + ret = ioctl(g_audio_socket, SNDCTL_DSP_SETFMT, &fmt); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SETFMT failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + stereo = 1; + ret = ioctl(g_audio_socket, SNDCTL_DSP_STEREO, &stereo); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_STEREO failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + + rate = g_audio_rate; + ret = ioctl(g_audio_socket, SNDCTL_DSP_SPEED, &rate); + if(ret < 0) { + printf("ioctl SNDCTL_DSP_SPEED failed, ret:%d, errno:%d\n", + ret, errno); + exit(1); + } + if(ret > 0) { + rate = ret; /* rate is returned value */ + } + if(rate < 8000) { + printf("Audio rate of %d which is < 8000!\n", rate); + exit(1); + } + + g_audio_rate = rate; + + printf("Sound initialized\n"); +} +#endif diff --git a/src/superhires.h b/src/superhires.h index cff10bf..5a3baeb 100644 --- a/src/superhires.h +++ b/src/superhires.h @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/tfe/tfe.vcxproj b/src/tfe/tfe.vcxproj index ea326ee..55aa273 100644 --- a/src/tfe/tfe.vcxproj +++ b/src/tfe/tfe.vcxproj @@ -1,108 +1,108 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {E810477A-E004-4308-A58A-21393213EF89} - Win32Proj - tfe - - - - StaticLibrary - true - MultiByte - v120 - - - StaticLibrary - false - true - MultiByte - v120 - - - - - - - - - - - - - true - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) - Speed - false - ProgramDatabase - Default - CompileAsC - true - true - false - - - Windows - true - - - - - Level3 - NotUsing - Full - true - true - WIN32;NDEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) - Speed - CompileAsC - false - StreamingSIMDExtensions - AnySuitable - true - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + Debug + Win32 + + + Release + Win32 + + + + {E810477A-E004-4308-A58A-21393213EF89} + Win32Proj + tfe + + + + StaticLibrary + true + MultiByte + v120 + + + StaticLibrary + false + true + MultiByte + v120 + + + + + + + + + + + + + true + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) + Speed + false + ProgramDatabase + Default + CompileAsC + true + true + false + + + Windows + true + + + + + Level3 + NotUsing + Full + true + true + WIN32;NDEBUG;_WINDOWS;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;TFE_EXPORTS;%(PreprocessorDefinitions) + Speed + CompileAsC + false + StreamingSIMDExtensions + AnySuitable + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tfe/tfe.vcxproj.filters b/src/tfe/tfe.vcxproj.filters index 1157911..78f75f4 100644 --- a/src/tfe/tfe.vcxproj.filters +++ b/src/tfe/tfe.vcxproj.filters @@ -1,54 +1,54 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/src/to_pro.c b/src/to_pro.c index 70d748b..8366e7c 100755 --- a/src/to_pro.c +++ b/src/to_pro.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it diff --git a/src/vars_fbrpilinux b/src/vars_fbrpilinux index aa58b4b..8c8c036 100644 --- a/src/vars_fbrpilinux +++ b/src/vars_fbrpilinux @@ -1,18 +1,18 @@ -TARGET = gsportfb -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) fbdriver.o -CC = gcc -CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -march=armv6 -OPTS = -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DHAVE_ATBRIDGE -SUFFIX = -NAME = gsportfb -LDFLAGS = -LDOPTS = -LD = g++ -EXTRA_LIBS = -ldl -EXTRA_SPECIALS = - -AS = cc -PERL = perl - -XOPTS = -I/usr/X11R6/include - +TARGET = gsportfb +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) fbdriver.o +CC = gcc +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -march=armv6 +OPTS = -DGSPORT_LITTLE_ENDIAN -DHAVE_TFE -DHAVE_ATBRIDGE +SUFFIX = +NAME = gsportfb +LDFLAGS = +LDOPTS = +LD = g++ +EXTRA_LIBS = -ldl +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X11R6/include + diff --git a/src/vars_osx_sdl2 b/src/vars_osx_sdl2 index c8de112..ce4170c 100644 --- a/src/vars_osx_sdl2 +++ b/src/vars_osx_sdl2 @@ -1,31 +1,31 @@ -TARGET = gsplus -NAME = gsplus -PERL = perl -CC = clang -LD = clang++ -AS = cc - -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) osxdriver.o sdlsnd_driver2.o -ARCHS = ppc, i386, ppc64, x86_64 - -# OPTIONS FOR COMPILING C SOURCE -CCOPTS = $(MACSUX) -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/SDL2 -# OPTIONS FOR COMPILING C++ SOURCE -CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/freetype2 -I/usr/local/include/SDL2 $(MACSUX) - -#SDK = -isysroot /Developer/SDKs/MacOSX10.5.sdk -isysroot /Developer/SDKs/MacOSX10.6.sdk -isysroot /Developer/SDKs/MacOSX10.7.sdk -isysroot /Developer/SDKs/MacOSX10.9.sdk -isysroot /Developer/SDKs/MacOSX10.10.sdk -isysroot /Developer/SDKs/MacOSX10.11.sdk -#INCLUDE = -I/Developer/SDKs/MacOSX10.5.sdk/usr/include -I/Developer/SDKs/MacOSX10.6.sdk/usr/include -I/Developer/SDKs/MacOSX10.7.sdk/usr/include -I/Developer/SDKs/MacOSX10.8.sdk/usr/include -I/Developer/SDKs/MacOSX10.9.sdk/usr/include -I/Developer/SDKs/MacOSX10.10.sdk/usr/include -I/Developer/SDKs/MacOSX10.11.sdk/usr/include - - -#SDK = -isysroot /Developer/SDKs/MacOSX10.11.sdk -#INCLUDE = -I/Developer/SDKs/MacOSX10.11.sdk/usr/include - - - -MACSUX = $(SDK) $(INCLUDE) -mmacosx-version-min=10.11 -EXTRA_LIBS = -lSDL2 -lfreetype -OPTS = -DGSPORT_LITTLE_ENDIAN -SUFFIX = -LDFLAGS = -LDOPTS = -I. -EXTRA_SPECIALS = +TARGET = gsplus +NAME = gsplus +PERL = perl +CC = clang +LD = clang++ +AS = cc + +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) osxdriver.o sdlsnd_driver2.o +ARCHS = ppc, i386, ppc64, x86_64 + +# OPTIONS FOR COMPILING C SOURCE +CCOPTS = $(MACSUX) -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/SDL2 +# OPTIONS FOR COMPILING C++ SOURCE +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/freetype2 -I/usr/local/include/SDL2 $(MACSUX) + +#SDK = -isysroot /Developer/SDKs/MacOSX10.5.sdk -isysroot /Developer/SDKs/MacOSX10.6.sdk -isysroot /Developer/SDKs/MacOSX10.7.sdk -isysroot /Developer/SDKs/MacOSX10.9.sdk -isysroot /Developer/SDKs/MacOSX10.10.sdk -isysroot /Developer/SDKs/MacOSX10.11.sdk +#INCLUDE = -I/Developer/SDKs/MacOSX10.5.sdk/usr/include -I/Developer/SDKs/MacOSX10.6.sdk/usr/include -I/Developer/SDKs/MacOSX10.7.sdk/usr/include -I/Developer/SDKs/MacOSX10.8.sdk/usr/include -I/Developer/SDKs/MacOSX10.9.sdk/usr/include -I/Developer/SDKs/MacOSX10.10.sdk/usr/include -I/Developer/SDKs/MacOSX10.11.sdk/usr/include + + +#SDK = -isysroot /Developer/SDKs/MacOSX10.11.sdk +#INCLUDE = -I/Developer/SDKs/MacOSX10.11.sdk/usr/include + + + +MACSUX = $(SDK) $(INCLUDE) -mmacosx-version-min=10.11 +EXTRA_LIBS = -lSDL2 -lfreetype +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +LDFLAGS = +LDOPTS = -I. +EXTRA_SPECIALS = diff --git a/src/vars_osx_x11 b/src/vars_osx_x11 index 0df134c..c64d100 100644 --- a/src/vars_osx_x11 +++ b/src/vars_osx_x11 @@ -1,21 +1,21 @@ -TARGET = gsportx -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) xdriver.o -CC = clang -#CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -arch=i686 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL -I/usr/include/freetype2 -#CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL2 - -CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/SDL2 -I/usr/local/include/freetype2 -L/usr/X11/lib -CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/freetype2 -I/usr/local/include/SDL2 -OPTS = -DGSPORT_LITTLE_ENDIAN -SUFFIX = -NAME = gsportx -LDFLAGS = -LDOPTS = -LD = g++ -EXTRA_LIBS = -lX11 -lfreetype -lSDL2 -lpcap -lXext -EXTRA_SPECIALS = - -AS = cc -PERL = perl - -XOPTS = -I/usr/X11/include +TARGET = gsportx +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) xdriver.o +CC = clang +#CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -arch=i686 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL -I/usr/include/freetype2 +#CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL2 + +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/SDL2 -I/usr/local/include/freetype2 -L/usr/X11/lib +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -I/usr/local/include/freetype2 -I/usr/local/include/SDL2 +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +NAME = gsportx +LDFLAGS = +LDOPTS = +LD = g++ +EXTRA_LIBS = -lX11 -lfreetype -lSDL2 -lpcap -lXext +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X11/include diff --git a/src/vars_x86linux_sdl b/src/vars_x86linux_sdl index cb94a84..9adad7e 100644 --- a/src/vars_x86linux_sdl +++ b/src/vars_x86linux_sdl @@ -1,18 +1,18 @@ -TARGET = gsportx -OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) xdriver.o sdlsnd_driver2.o -CC = gcc -CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL2 -I/usr/include/freetype2 -CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL2 -OPTS = -DGSPORT_LITTLE_ENDIAN -SUFFIX = -NAME = gsportx -LDFLAGS = -LDOPTS = -LD = g++ -EXTRA_LIBS = -lXext -lfreetype -lSDL2 -ldl -EXTRA_SPECIALS = - -AS = cc -PERL = perl - -XOPTS = -I/usr/X11R6/include +TARGET = gsportx +OBJECTS = $(OBJECTS1) $(TFEOBJ) $(ATOBJ) $(PCAPOBJ) xdriver.o sdlsnd_driver2.o +CC = gcc +CCOPTS = -O2 -Wall -fomit-frame-pointer -std=gnu99 -DHAVE_SDL -DHAVE_TFE -DHAVE_ATBRIDGE -DTOGGLE_STATUS -I/usr/include/SDL2 -I/usr/include/freetype2 +CPPOPTS = -O2 -DHAVE_TFE -DHAVE_SDL -DTOGGLE_STATUS -DHAVE_ATBRIDGE -I/usr/include/freetype2 -I/usr/include/SDL2 +OPTS = -DGSPORT_LITTLE_ENDIAN +SUFFIX = +NAME = gsportx +LDFLAGS = +LDOPTS = +LD = g++ +EXTRA_LIBS = -lXext -lfreetype -lSDL2 -ldl +EXTRA_SPECIALS = + +AS = cc +PERL = perl + +XOPTS = -I/usr/X11R6/include diff --git a/src/video.c b/src/video.c index 4db3e5d..2d06e8b 100644 --- a/src/video.c +++ b/src/video.c @@ -1,5 +1,7 @@ /* GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 - 2012 by GSport contributors Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey @@ -81,7 +83,7 @@ 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; // OG Not recommended to use it (or apps might miss mouse changes) +int g_video_extra_check_inputs = 0; // OG Not recommended to use it (or apps might miss mouse changes) 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; @@ -209,7 +211,7 @@ const byte g_dhires_colors_16[] = { 0x0f // 0xf white }; -int g_lores_colors[] = { +int g_lores_colors[] = { BLACK_RGB, // 0x0 black DEEP_RED_RGB, // 0x1 deep red DARK_BLUE_RGB, // 0x2 dark blue @@ -327,7 +329,7 @@ const word32 g_hires_convert[64] = { BIGEND(0x0f0f0f0f), /* 11,1111 = white ,white, white, white */ }; - int g_screen_index[] = { + 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 @@ -350,89 +352,89 @@ video_init() int i, j; /* Initialize video system */ -// OG Reinit globals - g_a2_screen_buffer_changed = (word32)-1; - g_full_refresh_needed = (word32)-1; - g_cycs_in_40col = 0; - g_cycs_in_xredraw = 0; - g_refresh_bytes_xfer = 0; +// OG Reinit globals + g_a2_screen_buffer_changed = (word32)-1; + g_full_refresh_needed = (word32)-1; + g_cycs_in_40col = 0; + g_cycs_in_xredraw = 0; + g_refresh_bytes_xfer = 0; - g_video_dcycs_check_input = 0.0; - //g_video_extra_check_inputs = 0; - g_video_act_margin_left = BASE_MARGIN_LEFT; - g_video_act_margin_right = BASE_MARGIN_RIGHT; - g_video_act_margin_top = BASE_MARGIN_TOP; - g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; - g_video_act_width = X_A2_WINDOW_WIDTH; - g_video_act_height = X_A2_WINDOW_HEIGHT; - - g_need_redraw = 1; - g_palette_change_summary = 0; - - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_border_line24_refresh_needed = 1; - g_status_refresh_needed = 1; - - g_vbl_border_color = 0; - g_border_last_vbl_changes = 0; - - g_use_dhr140 = 0; - g_use_bw_hires = 0; - - g_new_a2_stat_cur_line = 0; - g_vid_update_last_line = 0; - - g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 |(0xf << BIT_ALL_STAT_TEXT_COLOR); - - - g_a2vid_palette = 0xe; - g_installed_full_superhires_colormap = 0; - - Max_color_size = 256; - - g_saved_a2vid_palette = -1; - - g_cycs_in_refresh_line = 0; - g_cycs_in_refresh_ximage = 0; - - g_num_lines_superhires = 0; - g_num_lines_superhires640 = 0; - g_num_lines_prev_superhires = 0; - g_num_lines_prev_superhires640 = 0; - - /* - g_red_mask = 0xff; - g_green_mask = 0xff; - g_blue_mask = 0xff; - g_red_left_shift = 16; - g_green_left_shift = 8; - g_blue_left_shift = 0; - g_red_right_shift = 0; - g_green_right_shift = 0; - g_blue_right_shift = 0; -*/ - -/* Initialize video system */ - - for(i = 0; i < 200; i++) { - g_a2_line_kimage[i] = (Kimage *)0; // OG Changed from void* to kimage* - 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; + g_video_dcycs_check_input = 0.0; + //g_video_extra_check_inputs = 0; + g_video_act_margin_left = BASE_MARGIN_LEFT; + g_video_act_margin_right = BASE_MARGIN_RIGHT; + g_video_act_margin_top = BASE_MARGIN_TOP; + g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; + g_video_act_width = X_A2_WINDOW_WIDTH; + g_video_act_height = X_A2_WINDOW_HEIGHT; + + g_need_redraw = 1; + g_palette_change_summary = 0; + + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_border_line24_refresh_needed = 1; + g_status_refresh_needed = 1; + + g_vbl_border_color = 0; + g_border_last_vbl_changes = 0; + + g_use_dhr140 = 0; + g_use_bw_hires = 0; + + g_new_a2_stat_cur_line = 0; + g_vid_update_last_line = 0; + + g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 |(0xf << BIT_ALL_STAT_TEXT_COLOR); + + + g_a2vid_palette = 0xe; + g_installed_full_superhires_colormap = 0; + + Max_color_size = 256; + + g_saved_a2vid_palette = -1; + + g_cycs_in_refresh_line = 0; + g_cycs_in_refresh_ximage = 0; + + g_num_lines_superhires = 0; + g_num_lines_superhires640 = 0; + g_num_lines_prev_superhires = 0; + g_num_lines_prev_superhires640 = 0; + + /* + g_red_mask = 0xff; + g_green_mask = 0xff; + g_blue_mask = 0xff; + g_red_left_shift = 16; + g_green_left_shift = 8; + g_blue_left_shift = 0; + g_red_right_shift = 0; + g_green_right_shift = 0; + g_blue_right_shift = 0; +*/ + +/* Initialize video system */ + + for(i = 0; i < 200; i++) { + g_a2_line_kimage[i] = (Kimage *)0; // OG Changed from void* to kimage* + 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(); @@ -604,24 +606,24 @@ int g_screen_redraw_skip_amt = -1; word32 g_cycs_in_check_input = 0; -int g_needfullrefreshfornextframe = 1 ; - -void video_update() +int g_needfullrefreshfornextframe = 1 ; + +void video_update() { int did_video; - // OG g_needfullrefreshfornextframe - if (g_needfullrefreshfornextframe) - { - g_full_refresh_needed = -1; - g_a2_screen_buffer_changed = -1; - g_status_refresh_needed = 1; - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_needfullrefreshfornextframe = 0; - } - - + // OG g_needfullrefreshfornextframe + if (g_needfullrefreshfornextframe) + { + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + g_status_refresh_needed = 1; + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_needfullrefreshfornextframe = 0; + } + + update_border_info(); video_check_input_events(); @@ -648,19 +650,19 @@ void video_update() 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); - } - - -// OG Notify host that video has been uodated -#if defined(ACTIVEGSPLUGIN) && defined(MAC) - { - extern void x_need2refresh(); - x_need2refresh(); + g_a2_new_all_stat[0] = g_cur_a2_stat; + g_vid_update_last_line = 0; + video_update_through_line(0); } -#endif + + +// OG Notify host that video has been uodated +#if defined(ACTIVEGSPLUGIN) && defined(MAC) + { + extern void x_need2refresh(); + x_need2refresh(); + } +#endif } @@ -892,8 +894,8 @@ STRUCT(Border_changes) { int val; }; -int g_border_color = 0; // OG Expose border color - +int g_border_color = 0; // OG Expose border color + Border_changes g_border_changes[MAX_BORDER_CHANGES]; int g_num_border_changes = 0; @@ -902,10 +904,10 @@ change_border_color(double dcycs, int val) { int pos; - g_border_color = val; // OG Expose border color - + g_border_color = val; // OG Expose border color + pos = g_num_border_changes; - g_border_changes[pos].fcycs = (float)(dcycs - g_last_vbl_dcycs); + g_border_changes[pos].fcycs = (float)(dcycs - g_last_vbl_dcycs); g_border_changes[pos].val = val; pos++; @@ -917,8 +919,8 @@ change_border_color(double dcycs, int val) } } -extern int first; - +extern int first; + void update_border_info() { @@ -3004,16 +3006,16 @@ refresh_border() /**ZZZZ***/ } -// OG Added video_release_kimages proto -void video_release_kimages(); - +// OG Added video_release_kimages proto +void video_release_kimages(); + void end_screen() { printf("In end_screen\n"); - - // OG Free up allocated images - video_release_kimages(); + + // OG Free up allocated images + video_release_kimages(); xdriver_end(); } @@ -3131,21 +3133,21 @@ video_get_kimages() g_screen_mdepth); } -// OG Added video_release_kimages (to match video_get_kimages) -void video_release_kimages() -{ - extern void x_release_kimage(Kimage *kimage_ptr); - - x_release_kimage(&g_kimage_text[0]); - x_release_kimage(&g_kimage_text[1]); - x_release_kimage(&g_kimage_hires[0]); - x_release_kimage(&g_kimage_hires[1]); - x_release_kimage(&g_kimage_superhires); - x_release_kimage(&g_kimage_border_special); - x_release_kimage(&g_kimage_border_sides); -} - - +// OG Added video_release_kimages (to match video_get_kimages) +void video_release_kimages() +{ + extern void x_release_kimage(Kimage *kimage_ptr); + + x_release_kimage(&g_kimage_text[0]); + x_release_kimage(&g_kimage_text[1]); + x_release_kimage(&g_kimage_hires[0]); + x_release_kimage(&g_kimage_hires[1]); + x_release_kimage(&g_kimage_superhires); + x_release_kimage(&g_kimage_border_special); + x_release_kimage(&g_kimage_border_sides); +} + + void video_convert_kimage_depth(Kimage *kim_in, Kimage *kim_out, int startx, int starty, int width, int height) @@ -3207,14 +3209,14 @@ video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, { int mdepth_mismatch; int srcy; - int center = 0; // OG added variable to center screen - - //OG add null pointer check when emulator is restarted - if (!kimage_ptr) - { - printf("warning : video_push_lines(kimage_ptr=null)\n"); - return ; - } + int center = 0; // OG added variable to center screen + + //OG add null pointer check when emulator is restarted + if (!kimage_ptr) + { + printf("warning : video_push_lines(kimage_ptr=null)\n"); + return ; + } 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", @@ -3236,14 +3238,14 @@ video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, g_refresh_bytes_xfer += 2*(end_line - start_line) * (right_pix - left_pix); - // OG Calculating new center - if (g_cur_a2_stat & ALL_STAT_SUPER_HIRES) - center=0; - else - center=EFF_BORDER_WIDTH - BORDER_WIDTH; - - // OG shifting image to the center - x_push_kimage(kimage_ptr, g_video_act_margin_left + left_pix + center, + // OG Calculating new center + if (g_cur_a2_stat & ALL_STAT_SUPER_HIRES) + center=0; + else + center=EFF_BORDER_WIDTH - BORDER_WIDTH; + + // OG shifting image to the center + x_push_kimage(kimage_ptr, g_video_act_margin_left + left_pix + center, g_video_act_margin_top + srcy, left_pix, srcy, (right_pix - left_pix), 2*(end_line - start_line)); } @@ -3307,28 +3309,28 @@ video_push_border_sides() #endif /* redraw left sides */ - // OG Left side can alos be "jagged" as a2 screen is now being centered - - //video_push_border_sides_lines(0, 0, BORDER_WIDTH, 0, 200); - - 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, - 0, old_width, - prev_line, i); - prev_line = i; - old_width = width; - } - } - video_push_border_sides_lines(0/*BORDER_WIDTH*/, - 0, old_width, prev_line, 200); + // OG Left side can alos be "jagged" as a2 screen is now being centered + + //video_push_border_sides_lines(0, 0, BORDER_WIDTH, 0, 200); + + 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, + 0, old_width, + prev_line, i); + prev_line = i; + old_width = width; + } + } + video_push_border_sides_lines(0/*BORDER_WIDTH*/, + 0, old_width, prev_line, 200); /* right side--can be "jagged" */ prev_line = -1; @@ -3348,7 +3350,7 @@ video_push_border_sides() } } - video_push_border_sides_lines(0/*BORDER_WIDTH*/, + video_push_border_sides_lines(0/*BORDER_WIDTH*/, X_A2_WINDOW_WIDTH - old_width, old_width, prev_line, 200); } @@ -3392,9 +3394,9 @@ video_push_border_special() } } -// OG Added window ratio support -extern int x_calc_ratio(float ratiox,float ratioy); - +// OG Added window ratio support +extern int x_calc_ratio(float ratiox,float ratioy); + void video_push_kimages() { @@ -3424,26 +3426,26 @@ video_push_kimages() GET_ITIMER(start_time); - if (x_calc_ratio(ratiox,ratioy)) - { - line = 0; - while (1) - { - start = line; - cur_kim = g_a2_line_kimage[line]; - while(line < 200 && g_a2_line_kimage[line] == cur_kim) line++; - if (cur_kim == &g_kimage_superhires) - right = 640; - else - right = 560; - - video_push_lines(cur_kim, start, line,0,right); - if (line==200) break; - } - - } - else - { + if (x_calc_ratio(ratiox,ratioy)) + { + line = 0; + while (1) + { + start = line; + cur_kim = g_a2_line_kimage[line]; + while(line < 200 && g_a2_line_kimage[line] == cur_kim) line++; + if (cur_kim == &g_kimage_superhires) + right = 640; + else + right = 560; + + video_push_lines(cur_kim, start, line,0,right); + if (line==200) break; + } + + } + else + { start = -1; last_kim = (Kimage *)-1; cur_kim = (Kimage *)0; @@ -3499,7 +3501,7 @@ video_push_kimages() 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; diff --git a/src/win32.rc b/src/win32.rc index 1c71181..8dcfba7 100644 --- a/src/win32.rc +++ b/src/win32.rc @@ -1,180 +1,180 @@ -#include -#include "winresource.h" - -// $Id: $ - -#ifndef IDC_STATIC -#define IDC_STATIC (-1) -#endif - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDC_GSPORT32 MENU DISCARDABLE -BEGIN - POPUP "&Emulator" - BEGIN - MENUITEM "&Set Disk Configuration", ID_FILE_DISK - MENUITEM "Send CTRL Reset\tCTRL-BREAK", ID_FILE_SENDRESET - MENUITEM "Reboot\tCTRL-ALT-BREAK", ID_FILE_SENDREBOOT - MENUITEM SEPARATOR - MENUITEM "Toggle &Joystick", ID_FILE_JOYSTICK - MENUITEM "Toggle Debug Statistics", ID_FILE_DEBUGSTAT - MENUITEM SEPARATOR - MENUITEM "E&xit", ID_FILE_EXIT - END - POPUP "&Help" - BEGIN - MENUITEM "Key Commands", ID_HELP_KEY - MENUITEM SEPARATOR - MENUITEM "&About", ID_HELP_ABOUT - END -END - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -// CREATEPROCESS_MANIFEST RT_MANIFEST "gsport.manifest" - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDC_GSPORT32 BITMAP DISCARDABLE "wintoolbar.bmp" - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDR_ACCEL ACCELERATORS DISCARDABLE -BEGIN - VK_F1, ID_FILE_DISK, VIRTKEY, ALT, NOINVERT - VK_F4, ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT -END - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDC_GSPORT32 ICON DISCARDABLE "win32.ico" -GSPORT32_ICON ICON DISCARDABLE "win32.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUT_DIALOG DIALOG DISCARDABLE 0, 0, 207, 82 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "About" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",IDOK,78,61,50,14 - LTEXT "GSport: GS Emulator.\nBased on KEGS by Kent Dickey\nWindows Port by Chea Chee Keong\n\nThis software is licensed under GNU GPL.", - IDC_STATIC,38,7,162,45,NOT WS_GROUP - ICON "GSPORT32_ICON",IDC_STATIC,7,7,21,20,0 -END - -IDD_DLG_DISKCONF DIALOGEX 0, 0, 268, 182 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Disk Configuration" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,150,161,50,14 - PUSHBUTTON "Cancel",IDCANCEL,203,161,50,14 - LTEXT "S5D1",IDC_STATIC,19,46,19,8 - EDITTEXT IDC_EDIT_S5D1,43,42,156,14,ES_AUTOHSCROLL, - WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S5D1,203,42,50,14 - LTEXT "S5D2",IDC_STATIC,19,62,19,8 - EDITTEXT IDC_EDIT_S5D2,43,60,155,14,ES_AUTOHSCROLL, - WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S5D2,203,60,50,14 - LTEXT "S6D1",IDC_STATIC,19,80,19,8 - EDITTEXT IDC_EDIT_S6D1,43,77,156,14,ES_AUTOHSCROLL, - WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S6D1,203,77,50,14 - LTEXT "S6D2",IDC_STATIC,19,98,19,8 - EDITTEXT IDC_EDIT_S6D2,43,95,156,14,ES_AUTOHSCROLL, - WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S6D2,203,96,50,14 - LTEXT "S7D1",IDC_STATIC,19,118,19,8 - EDITTEXT IDC_EDIT_S7D1,43,115,155,14,ES_AUTOHSCROLL, - WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S7D1,203,115,50,14 - LTEXT "S7D2",IDC_STATIC,19,137,19,8 - EDITTEXT IDC_EDIT_S7D2,43,135,155,14,ES_AUTOHSCROLL, - WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BTN_S7D2,203,135,50,14 - GROUPBOX "Disk settings",IDC_STATIC,7,7,254,148 - LTEXT "Configure your disk images for each drive. Disk image formats supported\nare *.2MG,*.PO and *.DSK. ", - IDC_STATIC,19,20,234,16 -END - -IDD_SPEEDDIALOG DIALOG 0, 0, 240, 129 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Speed Control" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "1 MHz",IDC_SLOW,"Button",BS_AUTORADIOBUTTON | - WS_TABSTOP,45,41,51,13 - CONTROL "2.5 MHz",IDC_NORMAL,"Button",BS_AUTORADIOBUTTON | - WS_TABSTOP,45,55,43,13 - CONTROL "As fast as possible",IDC_FASTEST,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,45,69,74,13 - CONTROL "Custom (MHz)",IDC_CUSTOM,"Button",BS_AUTORADIOBUTTON | - WS_TABSTOP,45,83,69,13 - EDITTEXT IDC_EDITCUSTOM,117,83,79,13,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,133,107,50,15 - PUSHBUTTON "Cancel",IDCANCEL,183,107,50,15 - GROUPBOX "Speed Control",IDC_STATIC,7,7,226,96,WS_GROUP - LTEXT "Adjust the speed of your emulator by selecting the appropriate speed control", - IDC_STATIC,46,19,181,19,NOT WS_GROUP - ICON IDC_GSPORT32,IDC_STATIC,14,19,21,20 -END - -IDD_GSPORT32_KEY DIALOG 0, 0, 186, 172 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Help About Key Commands" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",IDOK,65,151,50,14 - LTEXT "GSport Key Commands",IDC_STATIC,7,7,82,10 - LTEXT "Alt/F1\t\tOpen-Apple\nF2\t\tClose-Apple\nF7\t\tToggle Fast Disk Emulation\nF8\t\tToggle Mouse Pointer\n\t\tDisplay\n", - IDC_STATIC,21,25,151,42 - LTEXT "F11\t\tToggle Fullscreen Display\nF12\t\tReset\nCtrl-Alt-Break\tReboot Emulator\nCtrl-Alt-Esc\tControl-Panel\nCtrl-Break\tReset Emulator", - IDC_STATIC,21,66,141,50 - CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | WS_DISABLED | - WS_BORDER,7,17,172,1 - LTEXT "Please visit http://gsport.sourceforge.net", - IDC_STATIC,21,124,144,19 -END - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - ID_FILE_DISK "Disk Configuration" -END - -STRINGTABLE -BEGIN - ID_SPEED_1MHZ "Set Speed to 1 Mhz" - ID_SPEED_2MHZ "Set Speed to 2.5 Mhz" - ID_SPEED_FMHZ "Set Speed to as fast as possible" -END - - - +#include +#include "winresource.h" + +// $Id: $ + +#ifndef IDC_STATIC +#define IDC_STATIC (-1) +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_GSPORT32 MENU DISCARDABLE +BEGIN + POPUP "&Emulator" + BEGIN + MENUITEM "&Set Disk Configuration", ID_FILE_DISK + MENUITEM "Send CTRL Reset\tCTRL-BREAK", ID_FILE_SENDRESET + MENUITEM "Reboot\tCTRL-ALT-BREAK", ID_FILE_SENDREBOOT + MENUITEM SEPARATOR + MENUITEM "Toggle &Joystick", ID_FILE_JOYSTICK + MENUITEM "Toggle Debug Statistics", ID_FILE_DEBUGSTAT + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "Key Commands", ID_HELP_KEY + MENUITEM SEPARATOR + MENUITEM "&About", ID_HELP_ABOUT + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// RT_MANIFEST +// + +// CREATEPROCESS_MANIFEST RT_MANIFEST "gsport.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDC_GSPORT32 BITMAP DISCARDABLE "wintoolbar.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCEL ACCELERATORS DISCARDABLE +BEGIN + VK_F1, ID_FILE_DISK, VIRTKEY, ALT, NOINVERT + VK_F4, ID_FILE_EXIT, VIRTKEY, ALT, NOINVERT +END + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDC_GSPORT32 ICON DISCARDABLE "win32.ico" +GSPORT32_ICON ICON DISCARDABLE "win32.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT_DIALOG DIALOG DISCARDABLE 0, 0, 207, 82 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,78,61,50,14 + LTEXT "GSport: GS Emulator.\nBased on KEGS by Kent Dickey\nWindows Port by Chea Chee Keong\n\nThis software is licensed under GNU GPL.", + IDC_STATIC,38,7,162,45,NOT WS_GROUP + ICON "GSPORT32_ICON",IDC_STATIC,7,7,21,20,0 +END + +IDD_DLG_DISKCONF DIALOGEX 0, 0, 268, 182 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disk Configuration" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,150,161,50,14 + PUSHBUTTON "Cancel",IDCANCEL,203,161,50,14 + LTEXT "S5D1",IDC_STATIC,19,46,19,8 + EDITTEXT IDC_EDIT_S5D1,43,42,156,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S5D1,203,42,50,14 + LTEXT "S5D2",IDC_STATIC,19,62,19,8 + EDITTEXT IDC_EDIT_S5D2,43,60,155,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S5D2,203,60,50,14 + LTEXT "S6D1",IDC_STATIC,19,80,19,8 + EDITTEXT IDC_EDIT_S6D1,43,77,156,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S6D1,203,77,50,14 + LTEXT "S6D2",IDC_STATIC,19,98,19,8 + EDITTEXT IDC_EDIT_S6D2,43,95,156,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S6D2,203,96,50,14 + LTEXT "S7D1",IDC_STATIC,19,118,19,8 + EDITTEXT IDC_EDIT_S7D1,43,115,155,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S7D1,203,115,50,14 + LTEXT "S7D2",IDC_STATIC,19,137,19,8 + EDITTEXT IDC_EDIT_S7D2,43,135,155,14,ES_AUTOHSCROLL, + WS_EX_ACCEPTFILES + PUSHBUTTON "Browse",IDC_BTN_S7D2,203,135,50,14 + GROUPBOX "Disk settings",IDC_STATIC,7,7,254,148 + LTEXT "Configure your disk images for each drive. Disk image formats supported\nare *.2MG,*.PO and *.DSK. ", + IDC_STATIC,19,20,234,16 +END + +IDD_SPEEDDIALOG DIALOG 0, 0, 240, 129 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Speed Control" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "1 MHz",IDC_SLOW,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,45,41,51,13 + CONTROL "2.5 MHz",IDC_NORMAL,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,45,55,43,13 + CONTROL "As fast as possible",IDC_FASTEST,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,45,69,74,13 + CONTROL "Custom (MHz)",IDC_CUSTOM,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,45,83,69,13 + EDITTEXT IDC_EDITCUSTOM,117,83,79,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,133,107,50,15 + PUSHBUTTON "Cancel",IDCANCEL,183,107,50,15 + GROUPBOX "Speed Control",IDC_STATIC,7,7,226,96,WS_GROUP + LTEXT "Adjust the speed of your emulator by selecting the appropriate speed control", + IDC_STATIC,46,19,181,19,NOT WS_GROUP + ICON IDC_GSPORT32,IDC_STATIC,14,19,21,20 +END + +IDD_GSPORT32_KEY DIALOG 0, 0, 186, 172 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Help About Key Commands" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,151,50,14 + LTEXT "GSport Key Commands",IDC_STATIC,7,7,82,10 + LTEXT "Alt/F1\t\tOpen-Apple\nF2\t\tClose-Apple\nF7\t\tToggle Fast Disk Emulation\nF8\t\tToggle Mouse Pointer\n\t\tDisplay\n", + IDC_STATIC,21,25,151,42 + LTEXT "F11\t\tToggle Fullscreen Display\nF12\t\tReset\nCtrl-Alt-Break\tReboot Emulator\nCtrl-Alt-Esc\tControl-Panel\nCtrl-Break\tReset Emulator", + IDC_STATIC,21,66,141,50 + CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | WS_DISABLED | + WS_BORDER,7,17,172,1 + LTEXT "Please visit http://gsport.sourceforge.net", + IDC_STATIC,21,124,144,19 +END + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + ID_FILE_DISK "Disk Configuration" +END + +STRINGTABLE +BEGIN + ID_SPEED_1MHZ "Set Speed to 1 Mhz" + ID_SPEED_2MHZ "Set Speed to 2.5 Mhz" + ID_SPEED_FMHZ "Set Speed to as fast as possible" +END + + + diff --git a/src/win32snd_driver.c b/src/win32snd_driver.c index 11e7af7..392686d 100644 --- a/src/win32snd_driver.c +++ b/src/win32snd_driver.c @@ -2,6 +2,8 @@ GSPLUS - Advanced Apple IIGS Emulator Environment Copyright (C) 2016 - Dagen Brock + Copyright (C) 2010 by GSport contributors + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey This program is free software; you can redistribute it and/or modify it @@ -34,7 +36,7 @@ void check_wave_error(int res, char *str); #define NUM_WAVE_HEADERS 8 -HWAVEOUT g_wave_handle = NULL; // OG Default value must be set +HWAVEOUT g_wave_handle = NULL; // OG Default value must be set WAVEHDR g_wavehdr[NUM_WAVE_HEADERS]; extern int g_audio_enable; @@ -52,39 +54,39 @@ win32snd_init(word32 *shmaddr) return; } - -// OG Added global to free the dedicated win32 sound memory -byte *bptr = NULL; - -// OG shut win32 sound resources + +// OG Added global to free the dedicated win32 sound memory +byte *bptr = NULL; + +// OG shut win32 sound resources void win32snd_shutdown() { - if (g_wave_handle) - { - MMRESULT res = waveOutReset(g_wave_handle); - if (res!=MMSYSERR_NOERROR ) - printf("waveOutReset Failed"); - - res = waveOutClose(g_wave_handle); - if (res!=MMSYSERR_NOERROR ) - printf("waveOutClose Failed"); - g_wave_handle=NULL; -} - // OG Free dedicated sound memory - if (bptr) - { - free(bptr); - bptr = NULL; - } + if (g_wave_handle) + { + MMRESULT res = waveOutReset(g_wave_handle); + if (res!=MMSYSERR_NOERROR ) + printf("waveOutReset Failed"); + + res = waveOutClose(g_wave_handle); + if (res!=MMSYSERR_NOERROR ) + printf("waveOutClose Failed"); + g_wave_handle=NULL; +} + // OG Free dedicated sound memory + if (bptr) + { + free(bptr); + bptr = NULL; + } + +} -} - void CALLBACK -handle_wav_snd(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, - DWORD dwParam2) +handle_wav_snd(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, + DWORD dwParam2) { LPWAVEHDR lpwavehdr; @@ -101,7 +103,7 @@ handle_wav_snd(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, void check_wave_error(int res, char *str) { - TCHAR buf[256]; + TCHAR buf[256]; if(res == MMSYSERR_NOERROR) { return; @@ -117,9 +119,9 @@ child_sound_init_win32() { WAVEFORMATEX wavefmt; WAVEOUTCAPS caps; - -// OG Moved as global variable (to rename) -// byte *bptr; + +// OG Moved as global variable (to rename) +// byte *bptr; int bits_per_sample, channels, block_align; int blen; int res; @@ -128,14 +130,14 @@ child_sound_init_win32() memset(&wavefmt, 0, sizeof(WAVEFORMATEX)); wavefmt.wFormatTag = WAVE_FORMAT_PCM; -#ifndef UNDER_CE +#ifndef UNDER_CE bits_per_sample = 16; - wavefmt.nSamplesPerSec = g_audio_rate; -#else - bits_per_sample = 16; - wavefmt.nSamplesPerSec = 12000; -#endif - + wavefmt.nSamplesPerSec = g_audio_rate; +#else + bits_per_sample = 16; + wavefmt.nSamplesPerSec = 12000; +#endif + channels = 2; wavefmt.wBitsPerSample = bits_per_sample; wavefmt.nChannels = channels; @@ -153,7 +155,7 @@ child_sound_init_win32() } res = waveOutOpen(&g_wave_handle, WAVE_MAPPER, &wavefmt, - (DWORD)handle_wav_snd, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC); + (DWORD)handle_wav_snd, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC); if(res != MMSYSERR_NOERROR) { printf("Cannot register audio\n"); @@ -165,7 +167,7 @@ child_sound_init_win32() blen = (SOUND_SHM_SAMP_SIZE * 4 * 2) / NUM_WAVE_HEADERS; g_win32snd_buflen = blen; - bptr = (byte*)malloc(blen * NUM_WAVE_HEADERS); // OG Added cast + bptr = (byte*)malloc(blen * NUM_WAVE_HEADERS); // OG Added cast if(bptr == NULL) { printf("Unabled to allocate sound buffer\n"); exit(1); @@ -174,7 +176,7 @@ child_sound_init_win32() for(i = 0; i < NUM_WAVE_HEADERS; i++) { memset(&g_wavehdr[i], 0, sizeof(WAVEHDR)); g_wavehdr[i].dwUser = FALSE; - g_wavehdr[i].lpData = (LPSTR)&(bptr[i*blen]); // OG Added cast + g_wavehdr[i].lpData = (LPSTR)&(bptr[i*blen]); // OG Added cast g_wavehdr[i].dwBufferLength = blen; g_wavehdr[i].dwFlags = 0; g_wavehdr[i].dwLoops = 0; diff --git a/src/win_console.c b/src/win_console.c index 957d454..28310e0 100644 --- a/src/win_console.c +++ b/src/win_console.c @@ -1,240 +1,242 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ -#define STRICT /* Tell Windows we want compile type checks */ - -#include -#include - -#include "winresource.h" -#include "defc.h" -#include "protos_windriver.h" - - -extern void gsportinit(HWND _hwnd); -extern void gsportshut(); -extern HWND g_hwnd_main; - -extern char *g_status_ptrs[MAX_STATUS_LINES]; -extern int g_win_status_debug; -extern int g_win_status_debug_request; -extern int g_win_fullscreen_state; - -int -win_nonblock_read_stdin(int fd, char *bufptr, int len) -{ - DWORD charsRead = 0; - ReadConsole(GetStdHandle(STD_INPUT_HANDLE), bufptr, len, &charsRead, NULL); - - if (charsRead == 0) - { - errno = EAGAIN; - return -1; - } - else - { - DWORD charsWritten = 0; - WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), bufptr, charsRead, &charsWritten, NULL); - return charsRead; - } -} - -void get_cwd(LPTSTR buffer, int size) -{ - HMODULE hSelf; - hSelf = GetModuleHandle(NULL); - GetModuleFileName(hSelf,buffer,size); - PathRemoveFileSpec(buffer); - printf("Local directory: [%s]\n",buffer); -} - -void -x_dialog_create_gsport_conf(const char *str) -{ - // Just write the config file already... - config_write_config_gsport_file(); -} - -int -x_show_alert(int is_fatal, const char *str) -{ - return 0; -} - -void get_default_window_size(LPSIZE size) -{ - // Calculate the window client dimensions. - RECT rect; - rect.left = 0; - rect.top = 0; - rect.bottom = X_A2_WINDOW_HEIGHT; - if (g_win_status_debug) - rect.bottom += (MAX_STATUS_LINES * 16); - rect.right = X_A2_WINDOW_WIDTH; - - // Calculate the window rectangle, which is the client area plus non-client area (e.g. frame and caption). - AdjustWindowRect(&rect, WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE); - - // Return the window size. - size->cx = rect.right - rect.left; - size->cy = rect.bottom - rect.top; -} - -void x_toggle_status_lines() -{ - SIZE size; - - if (!g_win_fullscreen_state) - { - g_win_status_debug = !g_win_status_debug; - g_win_status_debug_request = g_win_status_debug; - - get_default_window_size(&size); - SetWindowPos(g_hwnd_main, NULL, 0, 0, size.cx, size.cy, SWP_NOMOVE | SWP_NOZORDER); - x_redraw_status_lines(); - } -} - -void x_show_console(int show) -{ - HWND hWnd = GetConsoleWindow(); - if (hWnd) - ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); - - if (g_hwnd_main) - SetFocus(g_hwnd_main); -} - -int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) -{ - return main(0,0); -} - -int -main(int argc, char **argv) -{ - // Hide the console initially to reduce window flashing. We'll show the console later if needed. - x_show_console(0); - - // Register the window class. - WNDCLASS wndclass; - SIZE size; - RECT rect; - - wndclass.style = 0; - wndclass.lpfnWndProc = (WNDPROC)win_event_handler; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = GetModuleHandle(NULL); - wndclass.hIcon = LoadIcon(wndclass.hInstance, MAKEINTRESOURCE(IDC_GSPORT32)); - wndclass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); - wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = "gsport"; - - if(!RegisterClass(&wndclass)) { - printf("Registering window failed\n"); - exit(1); - } - - // Create the window. - get_default_window_size(&size); - - HWND hwnd = CreateWindowEx(WS_EX_ACCEPTFILES, "gsport", "GSport - Apple //gs Emulator", - WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, - CW_USEDEFAULT, CW_USEDEFAULT, - size.cx, size.cy, - NULL, NULL, GetModuleHandle(NULL), NULL); - - printf("g_hwnd_main = %p, height = %d\n", hwnd, size.cx); - GetWindowRect(hwnd, &rect); - printf("...rect is: %ld, %ld, %ld, %ld\n", rect.left, rect.top, - rect.right, rect.bottom); - - // Enable non-blocking, character-at-a-time console I/O. - // win_nonblock_read_stdin() expects this behavior. - DWORD mode; - GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode); - mode &= ~ENABLE_LINE_INPUT; - SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode); - - - gsportinit(hwnd); - int ret = gsportmain(argc, argv); - - UnregisterClass(wndclass.lpszClassName,GetModuleHandle(NULL)); - - gsportshut(); - return ret; -} - -void x_check_input_events() -{ - MSG msg; - - while(PeekMessage(&msg, g_hwnd_main, 0, 0, PM_NOREMOVE)) { - if(GetMessage(&msg, g_hwnd_main, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - printf("GetMessage returned <= 0\n"); - my_exit(2); - } - } -} - -void -x_redraw_status_lines() -{ - COLORREF oldtextcolor, oldbkcolor; - char *buf; - int line; - int len; - int height; - int margin; - - height = 16; - margin = 0; - if (g_win_status_debug) - { - HDC localdc = GetDC(g_hwnd_main); - oldtextcolor = SetTextColor(localdc, RGB(255, 255, 255)); - oldbkcolor = SetBkColor(localdc, RGB(0, 0, 0)); - for(line = 0; line < MAX_STATUS_LINES; line++) { - buf = g_status_ptrs[line]; - if(buf != 0) { - len = strlen(buf); - TextOut(localdc, 10, X_A2_WINDOW_HEIGHT + - height*line + margin, buf, len); - } - } - SetTextColor(localdc, oldtextcolor); - SetBkColor(localdc, oldbkcolor); - ReleaseDC(g_hwnd_main,localdc); - } -} - -int -x_calc_ratio(float ratiox,float ratioy) -{ - return 0; // not stretched -} \ No newline at end of file +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ +#define STRICT /* Tell Windows we want compile type checks */ + +#include +#include + +#include "winresource.h" +#include "defc.h" +#include "protos_windriver.h" + + +extern void gsportinit(HWND _hwnd); +extern void gsportshut(); +extern HWND g_hwnd_main; + +extern char *g_status_ptrs[MAX_STATUS_LINES]; +extern int g_win_status_debug; +extern int g_win_status_debug_request; +extern int g_win_fullscreen_state; + +int +win_nonblock_read_stdin(int fd, char *bufptr, int len) +{ + DWORD charsRead = 0; + ReadConsole(GetStdHandle(STD_INPUT_HANDLE), bufptr, len, &charsRead, NULL); + + if (charsRead == 0) + { + errno = EAGAIN; + return -1; + } + else + { + DWORD charsWritten = 0; + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), bufptr, charsRead, &charsWritten, NULL); + return charsRead; + } +} + +void get_cwd(LPTSTR buffer, int size) +{ + HMODULE hSelf; + hSelf = GetModuleHandle(NULL); + GetModuleFileName(hSelf,buffer,size); + PathRemoveFileSpec(buffer); + printf("Local directory: [%s]\n",buffer); +} + +void +x_dialog_create_gsport_conf(const char *str) +{ + // Just write the config file already... + config_write_config_gsport_file(); +} + +int +x_show_alert(int is_fatal, const char *str) +{ + return 0; +} + +void get_default_window_size(LPSIZE size) +{ + // Calculate the window client dimensions. + RECT rect; + rect.left = 0; + rect.top = 0; + rect.bottom = X_A2_WINDOW_HEIGHT; + if (g_win_status_debug) + rect.bottom += (MAX_STATUS_LINES * 16); + rect.right = X_A2_WINDOW_WIDTH; + + // Calculate the window rectangle, which is the client area plus non-client area (e.g. frame and caption). + AdjustWindowRect(&rect, WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE); + + // Return the window size. + size->cx = rect.right - rect.left; + size->cy = rect.bottom - rect.top; +} + +void x_toggle_status_lines() +{ + SIZE size; + + if (!g_win_fullscreen_state) + { + g_win_status_debug = !g_win_status_debug; + g_win_status_debug_request = g_win_status_debug; + + get_default_window_size(&size); + SetWindowPos(g_hwnd_main, NULL, 0, 0, size.cx, size.cy, SWP_NOMOVE | SWP_NOZORDER); + x_redraw_status_lines(); + } +} + +void x_show_console(int show) +{ + HWND hWnd = GetConsoleWindow(); + if (hWnd) + ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); + + if (g_hwnd_main) + SetFocus(g_hwnd_main); +} + +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + return main(0,0); +} + +int +main(int argc, char **argv) +{ + // Hide the console initially to reduce window flashing. We'll show the console later if needed. + x_show_console(0); + + // Register the window class. + WNDCLASS wndclass; + SIZE size; + RECT rect; + + wndclass.style = 0; + wndclass.lpfnWndProc = (WNDPROC)win_event_handler; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = GetModuleHandle(NULL); + wndclass.hIcon = LoadIcon(wndclass.hInstance, MAKEINTRESOURCE(IDC_GSPORT32)); + wndclass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = "gsport"; + + if(!RegisterClass(&wndclass)) { + printf("Registering window failed\n"); + exit(1); + } + + // Create the window. + get_default_window_size(&size); + + HWND hwnd = CreateWindowEx(WS_EX_ACCEPTFILES, "gsport", "GSport - Apple //gs Emulator", + WS_TILED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, + size.cx, size.cy, + NULL, NULL, GetModuleHandle(NULL), NULL); + + printf("g_hwnd_main = %p, height = %d\n", hwnd, size.cx); + GetWindowRect(hwnd, &rect); + printf("...rect is: %ld, %ld, %ld, %ld\n", rect.left, rect.top, + rect.right, rect.bottom); + + // Enable non-blocking, character-at-a-time console I/O. + // win_nonblock_read_stdin() expects this behavior. + DWORD mode; + GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode); + mode &= ~ENABLE_LINE_INPUT; + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode); + + + gsportinit(hwnd); + int ret = gsportmain(argc, argv); + + UnregisterClass(wndclass.lpszClassName,GetModuleHandle(NULL)); + + gsportshut(); + return ret; +} + +void x_check_input_events() +{ + MSG msg; + + while(PeekMessage(&msg, g_hwnd_main, 0, 0, PM_NOREMOVE)) { + if(GetMessage(&msg, g_hwnd_main, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + printf("GetMessage returned <= 0\n"); + my_exit(2); + } + } +} + +void +x_redraw_status_lines() +{ + COLORREF oldtextcolor, oldbkcolor; + char *buf; + int line; + int len; + int height; + int margin; + + height = 16; + margin = 0; + if (g_win_status_debug) + { + HDC localdc = GetDC(g_hwnd_main); + oldtextcolor = SetTextColor(localdc, RGB(255, 255, 255)); + oldbkcolor = SetBkColor(localdc, RGB(0, 0, 0)); + for(line = 0; line < MAX_STATUS_LINES; line++) { + buf = g_status_ptrs[line]; + if(buf != 0) { + len = strlen(buf); + TextOut(localdc, 10, X_A2_WINDOW_HEIGHT + + height*line + margin, buf, len); + } + } + SetTextColor(localdc, oldtextcolor); + SetBkColor(localdc, oldbkcolor); + ReleaseDC(g_hwnd_main,localdc); + } +} + +int +x_calc_ratio(float ratiox,float ratioy) +{ + return 0; // not stretched +} diff --git a/src/win_generic.c b/src/win_generic.c index fdc3d1a..149c8fd 100644 --- a/src/win_generic.c +++ b/src/win_generic.c @@ -1,734 +1,736 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2016 - Dagen Brock - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ -#define STRICT /* Tell Windows we want compile type checks */ - -#include -#include -#include - -#include "defc.h" -#include "protos.h" -#include "protos_windriver.h" -#include "win_keymap.h" - -extern int Verbose; -extern int g_pause; -extern int g_warp_pointer; -extern int g_screen_depth; -extern Kimage g_mainwin_kimage; -extern word32 g_palette_8to1624[256]; -extern word32 g_a2palette_8to1624[256]; -extern int g_lores_colors[]; -extern int g_installed_full_superhires_colormap; -extern int g_config_control_panel; - -extern void quitEmulator(); -extern void x_toggle_status_lines(); -extern void x_show_console(int show); -extern void x_check_input_events(); - -int g_win_capslock_down = 0; -int g_screen_mdepth = 0; -int g_num_a2_keycodes = 0; -int g_win_button_states = 0; -int g_use_shmem = 1; - -HDC g_main_cdc; -HWND g_hwnd_main; -BITMAPINFO *g_bmapinfo_ptr = 0; -volatile BITMAPINFOHEADER *g_bmaphdr_ptr = 0; - -// KEGS32 specific customisations -int g_win_status_debug = 1; // Current visibility of status lines. -int g_win_status_debug_request = 1; // Desired visibility of status lines. -int g_win_show_console = 0; // Current visibility of console. -int g_win_show_console_request = 1; // Desired visibility of console. -RECT g_main_window_saved_rect; -int g_main_window_saved_style; -int g_main_window_saved_exstyle; -int g_win_fullscreen_state = 0; -#if 0 // enable non-integral full-screen scaling - #define FULLSCREEN_SCALE_TYPE float -#else - #define FULLSCREEN_SCALE_TYPE int -#endif -FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale = 1; -int g_win_fullscreen_offsetx = 0; -int g_win_fullscreen_offsety = 0; - -LPSTR g_clipboard; -size_t g_clipboard_pos; - -int x_calc_ratio(float ratiox, float ratioy); - - -int -win_update_mouse(int x, int y, int button_states, int buttons_valid) -{ - int buttons_changed; - -#ifdef ACTIVEGS - if (g_config_control_panel) // OG ignore input events while in debugger - return 0; - - buttons_valid &= 1; // filter out middle & right button - -#endif - - buttons_changed = ((g_win_button_states & buttons_valid) != - button_states); - g_win_button_states = (g_win_button_states & ~buttons_valid) | - (button_states & buttons_valid); - if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && - (y == A2_WINDOW_HEIGHT/2) && (!buttons_changed) ) { - /* tell adb routs to recenter but ignore this motion */ - update_mouse(x, y, 0, -1); - return 0; - } - return update_mouse(x, y, button_states, buttons_valid & 7); -} - - -// OG Added asynchronous key & mouse handler -#define ASYNCEVENT - -#ifndef ASYNCEVENT -#define WIN_EVENT_MOUSE win_event_mouse -#define WIN_EVENT_KEY win_event_key -#else -extern void add_event_mouse(int umsg,WPARAM wParam, LPARAM lParam); -extern void add_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags); -#define WIN_EVENT_MOUSE add_event_mouse -#define WIN_EVENT_KEY add_event_key -#endif - -struct win32_mouse -{ - int umsg; - int wparam; - int lparam; -}; - -struct win32_key -{ - UINT raw_vk; - BOOL down; - int repeat; - UINT flags; -}; - -int last_win32_mouse=0; -int next_win32_mouse=0; - -int nb_win32_key=0; - -#define MAX_EVENT 1024 -struct win32_mouse win32_mouses[MAX_EVENT]; -struct win32_key win32_keys[MAX_EVENT]; - -// OG Push Mouse Event - -void add_event_mouse(int umsg,WPARAM wParam, LPARAM lParam) -{ - -#ifdef ACTIVEGS - if (g_config_control_panel) // OG ignore input events while in debugger - return; -#endif - - win32_mouses[next_win32_mouse].umsg = umsg; - win32_mouses[next_win32_mouse].wparam = wParam; - win32_mouses[next_win32_mouse].lparam = lParam; - next_win32_mouse = (next_win32_mouse+1)%MAX_EVENT; - -// ASSERT (next_win32_mouse==last_win32_mouse) -} - -// OG Push Key Event - -void -add_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags) -{ -#ifdef ACTIVEGS - if (g_config_control_panel) // OG ignore input events while in debugger - return; -#endif - - if (nb_win32_key>=MAX_EVENT) - return; - - win32_keys[nb_win32_key].raw_vk = raw_vk; - win32_keys[nb_win32_key].down = down; - win32_keys[nb_win32_key].repeat = repeat; - win32_keys[nb_win32_key].flags = flags; - - nb_win32_key++; -} - -void -win_event_mouse(int umsg,WPARAM wParam, LPARAM lParam) -{ - POINT pt; - word32 flags; - int buttons; - int x, y; - int motion; - - x = LOWORD(lParam); - y = HIWORD(lParam); - - - // OG Reformat the mouse coordinates - float ratiox = 0.0, ratioy = 0.0; - if (!g_warp_pointer && x_calc_ratio(ratiox,ratioy)) - { - x = (int)((float)(x)/ratiox); - y = (int)((float)(y)/ratioy); - } - - flags = wParam; - x -= BASE_MARGIN_LEFT; - y -= BASE_MARGIN_TOP; - - buttons = (flags & 1) + - (((flags >> 1) & 1) << 2) + - (((flags >> 4) & 1) << 1); -#if 0 - if (umsg!=WM_MOUSEMOVE) - printf("Mouse at %d, %d fl: %08x, but: %d\n", x, y, flags, buttons); -#endif - motion = win_update_mouse(x, y, buttons, 7); - - if(motion && g_warp_pointer) { - /* move mouse to center of screen */ - pt.x = BASE_MARGIN_LEFT + A2_WINDOW_WIDTH/2; - pt.y = BASE_MARGIN_TOP + A2_WINDOW_HEIGHT/2; - ClientToScreen(g_hwnd_main, &pt); - SetCursorPos(pt.x, pt.y); - } -} - -void -win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags) -{ - word32 vk; - int a2code; - int is_up; - int capslock_down; - int i; - - if((flags & 0x4000) && down) { - /* auto-repeating, just ignore it */ - return; - } - - vk = raw_vk + (flags & 0x100); -#if 0 - printf("Key event, vk=%04x, down:%d, repeat: %d, flags: %08x\n", - vk, down, repeat, flags); -#endif - - /* remap a few keys here.. sigh */ - if((vk & 0xff) == VK_APPS) { - /* remap to command */ - vk = VK_MENU; - } - - if((vk & 0xff) == VK_CAPITAL) { - // Windows gives us up-and-down events of the actual key - // Use GetKeyState to get the true toggle state, and pass - // that on to the adb interface - capslock_down = GetKeyState(VK_CAPITAL) & 0x01; - if(capslock_down != g_win_capslock_down) { - g_win_capslock_down = capslock_down; - adb_physical_key_update(0x39, !capslock_down); - } - - return; // Do no more processing! - } - - /* search a2key_to_wsym to find wsym in col 1 or 2 */ - i = 0; - is_up = !down; - for(i = g_num_a2_keycodes-1; i >= 0; i--) { - a2code = g_a2_key_to_wsym[i][0]; - if((vk == g_a2_key_to_wsym[i][1]) || - (vk == g_a2_key_to_wsym[i][2])) { - vid_printf("Found vk:%04x = %02x\n", vk, a2code); - adb_physical_key_update(a2code, is_up); - return; - } - } - printf("VK: %04x unknown\n", vk); -} - -void -win_event_quit(HWND hwnd) -{ - quitEmulator(); -} - -extern int g_needfullrefreshfornextframe ; - -void -win_event_redraw() -{ - g_needfullrefreshfornextframe = 1; -} - -LRESULT CALLBACK -win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) -{ - int i; - int numDraggedFiles; - int szFilename; - LPTSTR lpszFile; - - switch(umsg) { - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_LBUTTONDBLCLK: // OG Added dblclk as WM_LBUTTONDOWN - WIN_EVENT_MOUSE(umsg,wParam, lParam); - return 0; - case WM_PAINT: - win_event_redraw(); - break; - case WM_DROPFILES: - numDraggedFiles = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0); - for (i = 0; i < numDraggedFiles; i++) { - szFilename = DragQueryFile((HDROP)wParam, i, NULL, 0); - lpszFile = (LPTSTR)malloc(szFilename + 1); - szFilename = DragQueryFile((HDROP)wParam, i, lpszFile, szFilename + 1); - cfg_inspect_maybe_insert_file(lpszFile, 0); - free(lpszFile); - } - DragFinish((HDROP)wParam); - break; - } - switch(umsg) { - HANDLE_MSG(hwnd, WM_KEYUP, WIN_EVENT_KEY); - HANDLE_MSG(hwnd, WM_KEYDOWN, WIN_EVENT_KEY); - HANDLE_MSG(hwnd, WM_SYSKEYUP, WIN_EVENT_KEY); - HANDLE_MSG(hwnd, WM_SYSKEYDOWN, WIN_EVENT_KEY); - HANDLE_MSG(hwnd, WM_DESTROY, win_event_quit); - } - - return DefWindowProc(hwnd, umsg, wParam, lParam); -} - -void gsportinit(HWND _hwnd) -{ - g_hwnd_main = _hwnd; - - HDC localdc = GetDC(g_hwnd_main); - SetTextColor(localdc, RGB(0, 0, 0)); - SetBkColor(localdc, RGB(255, 255, 255)); - - g_main_cdc = CreateCompatibleDC(localdc); - ReleaseDC(g_hwnd_main,localdc); -} - -void gsportshut() -{ - if (g_main_cdc) - { - DeleteDC(g_main_cdc); - g_main_cdc = NULL; - } - g_hwnd_main = NULL; -} - -void -check_input_events() -{ - x_check_input_events(); - - // OG Unstack Mouse Events - int i=last_win32_mouse; - while(i!=next_win32_mouse) - { - win_event_mouse(win32_mouses[i].umsg,win32_mouses[i].wparam,win32_mouses[i].lparam); - int lb = win32_mouses[i].wparam&1; - i = (i+1)%MAX_EVENT; - if (lb != (win32_mouses[i].wparam&1)) - break; // don't send up & down event at the same time - } - last_win32_mouse=i; - - for(i=0;idev_handle != -1) - { - DeleteObject(kimage_ptr->dev_handle); - kimage_ptr->dev_handle = (void*)-1; - } - else - if (kimage_ptr->data_ptr) - { - free(kimage_ptr->data_ptr); - kimage_ptr->data_ptr = NULL; - } -} - -// OG Free video global memory -void -xdriver_end() // Should be renamed to dev_video_shut() ??? -{ - - x_release_kimage(&g_mainwin_kimage); - - GlobalFree(g_bmapinfo_ptr); // allocated in dev_video_init - g_bmapinfo_ptr = 0; - - printf("win32 video driver end\n"); -} - -void -x_get_kimage(Kimage *kimage_ptr) -{ - byte *ptr; - int width; - int height; - int depth, mdepth; - int size; - - width = kimage_ptr->width_req; - height = kimage_ptr->height; - depth = kimage_ptr->depth; - mdepth = kimage_ptr->mdepth; - - size = 0; - if(depth == g_screen_depth) { - /* Use g_bmapinfo_ptr, adjusting width, height */ - g_bmaphdr_ptr->biWidth = width; - g_bmaphdr_ptr->biHeight = -height; - - HDC localdc = GetDC(g_hwnd_main); // OG Use on the fly DC - kimage_ptr->dev_handle = CreateDIBSection(localdc, - g_bmapinfo_ptr, DIB_RGB_COLORS, - (VOID **)&(kimage_ptr->data_ptr), NULL, 0); - ReleaseDC(g_hwnd_main,localdc); - } else { - /* allocate buffers for video.c to draw into */ - - size = (width*height*mdepth) >> 3; - ptr = (byte *)malloc(size); - - if(ptr == 0) { - printf("malloc for data failed, mdepth: %d\n", mdepth); - exit(2); - } - - kimage_ptr->data_ptr = ptr; - - kimage_ptr->dev_handle = (void *)-1; - - } - printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr, - kimage_ptr->dev_handle, kimage_ptr->data_ptr, size); - - return; -} - -void -dev_video_init() -{ - int extra_size; - int lores_col; - int i; - - printf("Preparing graphics system\n"); - - // OG fix g_num_a2_keycodes identification - g_num_a2_keycodes = sizeof(g_a2_key_to_wsym)/3/sizeof(int); - g_num_a2_keycodes--; // last entry=-1 - - /* - g_num_a2_keycodes = 0; - for(i = 0; i < maxcode; i++) { - int a2code = g_a2_key_to_wsym[i][0]; - if(a2code < 0) { - g_num_a2_keycodes = i; - } - } - */ - - // OG Forcing 16bits depth for WiNCE -#ifndef UNDER_CE - g_screen_depth = 24; - g_screen_mdepth = 32; -#else - g_screen_depth = 16; - g_screen_mdepth = 16; - - -extern word32 g_red_mask ; -extern word32 g_green_mask ; -extern word32 g_blue_mask ; -extern int g_red_left_shift; -extern int g_green_left_shift; -extern int g_blue_left_shift ; -extern int g_red_right_shift ; -extern int g_green_right_shift ; -extern int g_blue_right_shift ; - - - g_red_mask = 0xff; - g_green_mask = 0xff; - g_blue_mask = 0xff; - g_red_left_shift = 10; - g_green_left_shift = 5; - g_blue_left_shift = 0; - g_red_right_shift = 3; - g_green_right_shift = 3; - g_blue_right_shift = 3; -#endif - - extra_size = sizeof(RGBQUAD); - if(g_screen_depth == 8) { - extra_size = 256 * sizeof(RGBQUAD); - } - g_bmapinfo_ptr = (BITMAPINFO *)GlobalAlloc(GPTR, - sizeof(BITMAPINFOHEADER) + extra_size); - - g_bmaphdr_ptr = (BITMAPINFOHEADER *)g_bmapinfo_ptr; - g_bmaphdr_ptr->biSize = sizeof(BITMAPINFOHEADER); - g_bmaphdr_ptr->biWidth = A2_WINDOW_WIDTH; - g_bmaphdr_ptr->biHeight = -A2_WINDOW_HEIGHT; - g_bmaphdr_ptr->biPlanes = 1; - g_bmaphdr_ptr->biBitCount = g_screen_mdepth; - g_bmaphdr_ptr->biCompression = BI_RGB; - g_bmaphdr_ptr->biClrUsed = 0; - - video_get_kimages(); - - if(g_screen_depth != 8) { - // Allocate g_mainwin_kimage - video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, - g_screen_mdepth); - } - - for(i = 0; i < 256; i++) { - lores_col = g_lores_colors[i & 0xf]; - video_update_color_raw(i, lores_col); - g_a2palette_8to1624[i] = g_palette_8to1624[i]; - } - - g_installed_full_superhires_colormap = 1; - -#ifndef UNDER_CE - ShowWindow(g_hwnd_main, SW_SHOWDEFAULT); -#else - ShowWindow(g_hwnd_main, SW_SHOW); -#endif - UpdateWindow(g_hwnd_main); - - printf("Done with dev_video_init\n"); - fflush(stdout); -} - -void -x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, - int width, int height) -{ - void *bitm_old; - - HDC localdc = GetDC(g_hwnd_main); - HDC localcdc = g_main_cdc; - - bitm_old = SelectObject(localcdc, kimage_ptr->dev_handle); - - if (g_win_fullscreen_scale == 1) - BitBlt(localdc, destx + g_win_fullscreen_offsetx, desty + g_win_fullscreen_offsety, width, height, localcdc, srcx, srcy, SRCCOPY); - else - { - FULLSCREEN_SCALE_TYPE xdest = destx * g_win_fullscreen_scale + g_win_fullscreen_offsetx; - FULLSCREEN_SCALE_TYPE ydest = desty * g_win_fullscreen_scale + g_win_fullscreen_offsety; - FULLSCREEN_SCALE_TYPE wdest = width * g_win_fullscreen_scale; - FULLSCREEN_SCALE_TYPE hdest = height * g_win_fullscreen_scale; - - StretchBlt(localdc, (int)xdest, (int)ydest, (int)wdest, (int)hdest, localcdc, srcx, srcy, width, height, SRCCOPY); - } - - SelectObject(localcdc, bitm_old); - ReleaseDC(g_hwnd_main,localdc); -} - -void -x_push_done() -{ -} - -void -x_auto_repeat_on(int must) -{ -} - -void -x_auto_repeat_off(int must) -{ -} - -void -x_hide_pointer(int do_hide) -{ - if(do_hide) { - ShowCursor(0); - } else { - ShowCursor(1); - } -} - -void -x_full_screen(int do_full) -{ - MONITORINFO monitor_info; - FULLSCREEN_SCALE_TYPE width, height, scalex, scaley; - int top, left; - - g_win_status_debug = 1 - do_full; - if (do_full && !g_win_fullscreen_state) { - g_main_window_saved_style = GetWindowLong(g_hwnd_main, GWL_STYLE); - g_main_window_saved_exstyle = GetWindowLong(g_hwnd_main, GWL_EXSTYLE); - GetWindowRect(g_hwnd_main, &g_main_window_saved_rect); - SetWindowLong(g_hwnd_main, GWL_STYLE, g_main_window_saved_style & ~(WS_CAPTION | WS_THICKFRAME)); - SetWindowLong(g_hwnd_main, GWL_EXSTYLE, g_main_window_saved_exstyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); - - monitor_info.cbSize = sizeof(monitor_info); - GetMonitorInfo(MonitorFromWindow(g_hwnd_main, MONITOR_DEFAULTTONEAREST), &monitor_info); - left = monitor_info.rcMonitor.left; - top = monitor_info.rcMonitor.top; - width = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.right - monitor_info.rcMonitor.left); - height = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top); - scalex = width / X_A2_WINDOW_WIDTH; - scaley = height / X_A2_WINDOW_HEIGHT; - g_win_fullscreen_scale = (scalex <= scaley) ? scalex : scaley; - g_win_fullscreen_offsetx = ((int)width - (int)(g_win_fullscreen_scale * X_A2_WINDOW_WIDTH)) / 2; - g_win_fullscreen_offsety = ((int)height - (int)(g_win_fullscreen_scale * X_A2_WINDOW_HEIGHT)) / 2; - SetWindowPos(g_hwnd_main, NULL, left, top, (int)width, (int)height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); - - g_win_fullscreen_state = 1; - RedrawWindow(g_hwnd_main, NULL, NULL, RDW_INVALIDATE); - - - } else { - if (g_win_fullscreen_state) { - g_win_fullscreen_offsetx = 0; - g_win_fullscreen_offsety = 0; - g_win_fullscreen_scale = 1; - SetWindowLong(g_hwnd_main, GWL_STYLE, g_main_window_saved_style); - SetWindowLong(g_hwnd_main, GWL_EXSTYLE, g_main_window_saved_exstyle); - SetWindowPos(g_hwnd_main, NULL, - g_main_window_saved_rect.left, - g_main_window_saved_rect.top, - g_main_window_saved_rect.right - g_main_window_saved_rect.left, - g_main_window_saved_rect.bottom - g_main_window_saved_rect.top, - SWP_SHOWWINDOW); - - g_win_fullscreen_state = 0; - RedrawWindow(g_hwnd_main, NULL, NULL, RDW_INVALIDATE); - } - } - return; -} - -void -clipboard_paste() -{ - if (!IsClipboardFormatAvailable(CF_TEXT)) - return; - if (!OpenClipboard(g_hwnd_main)) - return; - { - HGLOBAL hclipboard = GetClipboardData(CF_TEXT); - if (!hclipboard) { - CloseClipboard(); - return; - } - { - LPSTR clipboard = (LPSTR)GlobalLock(hclipboard); - if (!clipboard) { - CloseClipboard(); - return; - } - if (g_clipboard) { - free(g_clipboard); - g_clipboard_pos = 0; - } - g_clipboard = strdup(clipboard); - } - GlobalUnlock(hclipboard); - } - CloseClipboard(); -} - -int -clipboard_get_char() -{ - if (!g_clipboard) - return 0; - if (g_clipboard[g_clipboard_pos] == '\n') - g_clipboard_pos++; - if (g_clipboard[g_clipboard_pos] == '\0') - return 0; - return g_clipboard[g_clipboard_pos++] | 0x80; -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ +#define STRICT /* Tell Windows we want compile type checks */ + +#include +#include +#include + +#include "defc.h" +#include "protos.h" +#include "protos_windriver.h" +#include "win_keymap.h" + +extern int Verbose; +extern int g_pause; +extern int g_warp_pointer; +extern int g_screen_depth; +extern Kimage g_mainwin_kimage; +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; +extern int g_lores_colors[]; +extern int g_installed_full_superhires_colormap; +extern int g_config_control_panel; + +extern void quitEmulator(); +extern void x_toggle_status_lines(); +extern void x_show_console(int show); +extern void x_check_input_events(); + +int g_win_capslock_down = 0; +int g_screen_mdepth = 0; +int g_num_a2_keycodes = 0; +int g_win_button_states = 0; +int g_use_shmem = 1; + +HDC g_main_cdc; +HWND g_hwnd_main; +BITMAPINFO *g_bmapinfo_ptr = 0; +volatile BITMAPINFOHEADER *g_bmaphdr_ptr = 0; + +// KEGS32 specific customisations +int g_win_status_debug = 1; // Current visibility of status lines. +int g_win_status_debug_request = 1; // Desired visibility of status lines. +int g_win_show_console = 0; // Current visibility of console. +int g_win_show_console_request = 1; // Desired visibility of console. +RECT g_main_window_saved_rect; +int g_main_window_saved_style; +int g_main_window_saved_exstyle; +int g_win_fullscreen_state = 0; +#if 0 // enable non-integral full-screen scaling + #define FULLSCREEN_SCALE_TYPE float +#else + #define FULLSCREEN_SCALE_TYPE int +#endif +FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale = 1; +int g_win_fullscreen_offsetx = 0; +int g_win_fullscreen_offsety = 0; + +LPSTR g_clipboard; +size_t g_clipboard_pos; + +int x_calc_ratio(float ratiox, float ratioy); + + +int +win_update_mouse(int x, int y, int button_states, int buttons_valid) +{ + int buttons_changed; + +#ifdef ACTIVEGS + if (g_config_control_panel) // OG ignore input events while in debugger + return 0; + + buttons_valid &= 1; // filter out middle & right button + +#endif + + buttons_changed = ((g_win_button_states & buttons_valid) != + button_states); + g_win_button_states = (g_win_button_states & ~buttons_valid) | + (button_states & buttons_valid); + if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && + (y == A2_WINDOW_HEIGHT/2) && (!buttons_changed) ) { + /* tell adb routs to recenter but ignore this motion */ + update_mouse(x, y, 0, -1); + return 0; + } + return update_mouse(x, y, button_states, buttons_valid & 7); +} + + +// OG Added asynchronous key & mouse handler +#define ASYNCEVENT + +#ifndef ASYNCEVENT +#define WIN_EVENT_MOUSE win_event_mouse +#define WIN_EVENT_KEY win_event_key +#else +extern void add_event_mouse(int umsg,WPARAM wParam, LPARAM lParam); +extern void add_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags); +#define WIN_EVENT_MOUSE add_event_mouse +#define WIN_EVENT_KEY add_event_key +#endif + +struct win32_mouse +{ + int umsg; + int wparam; + int lparam; +}; + +struct win32_key +{ + UINT raw_vk; + BOOL down; + int repeat; + UINT flags; +}; + +int last_win32_mouse=0; +int next_win32_mouse=0; + +int nb_win32_key=0; + +#define MAX_EVENT 1024 +struct win32_mouse win32_mouses[MAX_EVENT]; +struct win32_key win32_keys[MAX_EVENT]; + +// OG Push Mouse Event + +void add_event_mouse(int umsg,WPARAM wParam, LPARAM lParam) +{ + +#ifdef ACTIVEGS + if (g_config_control_panel) // OG ignore input events while in debugger + return; +#endif + + win32_mouses[next_win32_mouse].umsg = umsg; + win32_mouses[next_win32_mouse].wparam = wParam; + win32_mouses[next_win32_mouse].lparam = lParam; + next_win32_mouse = (next_win32_mouse+1)%MAX_EVENT; + +// ASSERT (next_win32_mouse==last_win32_mouse) +} + +// OG Push Key Event + +void +add_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags) +{ +#ifdef ACTIVEGS + if (g_config_control_panel) // OG ignore input events while in debugger + return; +#endif + + if (nb_win32_key>=MAX_EVENT) + return; + + win32_keys[nb_win32_key].raw_vk = raw_vk; + win32_keys[nb_win32_key].down = down; + win32_keys[nb_win32_key].repeat = repeat; + win32_keys[nb_win32_key].flags = flags; + + nb_win32_key++; +} + +void +win_event_mouse(int umsg,WPARAM wParam, LPARAM lParam) +{ + POINT pt; + word32 flags; + int buttons; + int x, y; + int motion; + + x = LOWORD(lParam); + y = HIWORD(lParam); + + + // OG Reformat the mouse coordinates + float ratiox = 0.0, ratioy = 0.0; + if (!g_warp_pointer && x_calc_ratio(ratiox,ratioy)) + { + x = (int)((float)(x)/ratiox); + y = (int)((float)(y)/ratioy); + } + + flags = wParam; + x -= BASE_MARGIN_LEFT; + y -= BASE_MARGIN_TOP; + + buttons = (flags & 1) + + (((flags >> 1) & 1) << 2) + + (((flags >> 4) & 1) << 1); +#if 0 + if (umsg!=WM_MOUSEMOVE) + printf("Mouse at %d, %d fl: %08x, but: %d\n", x, y, flags, buttons); +#endif + motion = win_update_mouse(x, y, buttons, 7); + + if(motion && g_warp_pointer) { + /* move mouse to center of screen */ + pt.x = BASE_MARGIN_LEFT + A2_WINDOW_WIDTH/2; + pt.y = BASE_MARGIN_TOP + A2_WINDOW_HEIGHT/2; + ClientToScreen(g_hwnd_main, &pt); + SetCursorPos(pt.x, pt.y); + } +} + +void +win_event_key(HWND hwnd, UINT raw_vk, BOOL down, int repeat, UINT flags) +{ + word32 vk; + int a2code; + int is_up; + int capslock_down; + int i; + + if((flags & 0x4000) && down) { + /* auto-repeating, just ignore it */ + return; + } + + vk = raw_vk + (flags & 0x100); +#if 0 + printf("Key event, vk=%04x, down:%d, repeat: %d, flags: %08x\n", + vk, down, repeat, flags); +#endif + + /* remap a few keys here.. sigh */ + if((vk & 0xff) == VK_APPS) { + /* remap to command */ + vk = VK_MENU; + } + + if((vk & 0xff) == VK_CAPITAL) { + // Windows gives us up-and-down events of the actual key + // Use GetKeyState to get the true toggle state, and pass + // that on to the adb interface + capslock_down = GetKeyState(VK_CAPITAL) & 0x01; + if(capslock_down != g_win_capslock_down) { + g_win_capslock_down = capslock_down; + adb_physical_key_update(0x39, !capslock_down); + } + + return; // Do no more processing! + } + + /* search a2key_to_wsym to find wsym in col 1 or 2 */ + i = 0; + is_up = !down; + for(i = g_num_a2_keycodes-1; i >= 0; i--) { + a2code = g_a2_key_to_wsym[i][0]; + if((vk == g_a2_key_to_wsym[i][1]) || + (vk == g_a2_key_to_wsym[i][2])) { + vid_printf("Found vk:%04x = %02x\n", vk, a2code); + adb_physical_key_update(a2code, is_up); + return; + } + } + printf("VK: %04x unknown\n", vk); +} + +void +win_event_quit(HWND hwnd) +{ + quitEmulator(); +} + +extern int g_needfullrefreshfornextframe ; + +void +win_event_redraw() +{ + g_needfullrefreshfornextframe = 1; +} + +LRESULT CALLBACK +win_event_handler(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) +{ + int i; + int numDraggedFiles; + int szFilename; + LPTSTR lpszFile; + + switch(umsg) { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_LBUTTONDBLCLK: // OG Added dblclk as WM_LBUTTONDOWN + WIN_EVENT_MOUSE(umsg,wParam, lParam); + return 0; + case WM_PAINT: + win_event_redraw(); + break; + case WM_DROPFILES: + numDraggedFiles = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0); + for (i = 0; i < numDraggedFiles; i++) { + szFilename = DragQueryFile((HDROP)wParam, i, NULL, 0); + lpszFile = (LPTSTR)malloc(szFilename + 1); + szFilename = DragQueryFile((HDROP)wParam, i, lpszFile, szFilename + 1); + cfg_inspect_maybe_insert_file(lpszFile, 0); + free(lpszFile); + } + DragFinish((HDROP)wParam); + break; + } + switch(umsg) { + HANDLE_MSG(hwnd, WM_KEYUP, WIN_EVENT_KEY); + HANDLE_MSG(hwnd, WM_KEYDOWN, WIN_EVENT_KEY); + HANDLE_MSG(hwnd, WM_SYSKEYUP, WIN_EVENT_KEY); + HANDLE_MSG(hwnd, WM_SYSKEYDOWN, WIN_EVENT_KEY); + HANDLE_MSG(hwnd, WM_DESTROY, win_event_quit); + } + + return DefWindowProc(hwnd, umsg, wParam, lParam); +} + +void gsportinit(HWND _hwnd) +{ + g_hwnd_main = _hwnd; + + HDC localdc = GetDC(g_hwnd_main); + SetTextColor(localdc, RGB(0, 0, 0)); + SetBkColor(localdc, RGB(255, 255, 255)); + + g_main_cdc = CreateCompatibleDC(localdc); + ReleaseDC(g_hwnd_main,localdc); +} + +void gsportshut() +{ + if (g_main_cdc) + { + DeleteDC(g_main_cdc); + g_main_cdc = NULL; + } + g_hwnd_main = NULL; +} + +void +check_input_events() +{ + x_check_input_events(); + + // OG Unstack Mouse Events + int i=last_win32_mouse; + while(i!=next_win32_mouse) + { + win_event_mouse(win32_mouses[i].umsg,win32_mouses[i].wparam,win32_mouses[i].lparam); + int lb = win32_mouses[i].wparam&1; + i = (i+1)%MAX_EVENT; + if (lb != (win32_mouses[i].wparam&1)) + break; // don't send up & down event at the same time + } + last_win32_mouse=i; + + for(i=0;idev_handle != -1) + { + DeleteObject(kimage_ptr->dev_handle); + kimage_ptr->dev_handle = (void*)-1; + } + else + if (kimage_ptr->data_ptr) + { + free(kimage_ptr->data_ptr); + kimage_ptr->data_ptr = NULL; + } +} + +// OG Free video global memory +void +xdriver_end() // Should be renamed to dev_video_shut() ??? +{ + + x_release_kimage(&g_mainwin_kimage); + + GlobalFree(g_bmapinfo_ptr); // allocated in dev_video_init + g_bmapinfo_ptr = 0; + + printf("win32 video driver end\n"); +} + +void +x_get_kimage(Kimage *kimage_ptr) +{ + byte *ptr; + int width; + int height; + int depth, mdepth; + int size; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + mdepth = kimage_ptr->mdepth; + + size = 0; + if(depth == g_screen_depth) { + /* Use g_bmapinfo_ptr, adjusting width, height */ + g_bmaphdr_ptr->biWidth = width; + g_bmaphdr_ptr->biHeight = -height; + + HDC localdc = GetDC(g_hwnd_main); // OG Use on the fly DC + kimage_ptr->dev_handle = CreateDIBSection(localdc, + g_bmapinfo_ptr, DIB_RGB_COLORS, + (VOID **)&(kimage_ptr->data_ptr), NULL, 0); + ReleaseDC(g_hwnd_main,localdc); + } else { + /* allocate buffers for video.c to draw into */ + + size = (width*height*mdepth) >> 3; + ptr = (byte *)malloc(size); + + if(ptr == 0) { + printf("malloc for data failed, mdepth: %d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + kimage_ptr->dev_handle = (void *)-1; + + } + printf("kim: %p, dev:%p data: %p, size: %08x\n", kimage_ptr, + kimage_ptr->dev_handle, kimage_ptr->data_ptr, size); + + return; +} + +void +dev_video_init() +{ + int extra_size; + int lores_col; + int i; + + printf("Preparing graphics system\n"); + + // OG fix g_num_a2_keycodes identification + g_num_a2_keycodes = sizeof(g_a2_key_to_wsym)/3/sizeof(int); + g_num_a2_keycodes--; // last entry=-1 + + /* + g_num_a2_keycodes = 0; + for(i = 0; i < maxcode; i++) { + int a2code = g_a2_key_to_wsym[i][0]; + if(a2code < 0) { + g_num_a2_keycodes = i; + } + } + */ + + // OG Forcing 16bits depth for WiNCE +#ifndef UNDER_CE + g_screen_depth = 24; + g_screen_mdepth = 32; +#else + g_screen_depth = 16; + g_screen_mdepth = 16; + + +extern word32 g_red_mask ; +extern word32 g_green_mask ; +extern word32 g_blue_mask ; +extern int g_red_left_shift; +extern int g_green_left_shift; +extern int g_blue_left_shift ; +extern int g_red_right_shift ; +extern int g_green_right_shift ; +extern int g_blue_right_shift ; + + + g_red_mask = 0xff; + g_green_mask = 0xff; + g_blue_mask = 0xff; + g_red_left_shift = 10; + g_green_left_shift = 5; + g_blue_left_shift = 0; + g_red_right_shift = 3; + g_green_right_shift = 3; + g_blue_right_shift = 3; +#endif + + extra_size = sizeof(RGBQUAD); + if(g_screen_depth == 8) { + extra_size = 256 * sizeof(RGBQUAD); + } + g_bmapinfo_ptr = (BITMAPINFO *)GlobalAlloc(GPTR, + sizeof(BITMAPINFOHEADER) + extra_size); + + g_bmaphdr_ptr = (BITMAPINFOHEADER *)g_bmapinfo_ptr; + g_bmaphdr_ptr->biSize = sizeof(BITMAPINFOHEADER); + g_bmaphdr_ptr->biWidth = A2_WINDOW_WIDTH; + g_bmaphdr_ptr->biHeight = -A2_WINDOW_HEIGHT; + g_bmaphdr_ptr->biPlanes = 1; + g_bmaphdr_ptr->biBitCount = g_screen_mdepth; + g_bmaphdr_ptr->biCompression = BI_RGB; + g_bmaphdr_ptr->biClrUsed = 0; + + video_get_kimages(); + + if(g_screen_depth != 8) { + // Allocate g_mainwin_kimage + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, + g_screen_mdepth); + } + + for(i = 0; i < 256; i++) { + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + + g_installed_full_superhires_colormap = 1; + +#ifndef UNDER_CE + ShowWindow(g_hwnd_main, SW_SHOWDEFAULT); +#else + ShowWindow(g_hwnd_main, SW_SHOW); +#endif + UpdateWindow(g_hwnd_main); + + printf("Done with dev_video_init\n"); + fflush(stdout); +} + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, + int width, int height) +{ + void *bitm_old; + + HDC localdc = GetDC(g_hwnd_main); + HDC localcdc = g_main_cdc; + + bitm_old = SelectObject(localcdc, kimage_ptr->dev_handle); + + if (g_win_fullscreen_scale == 1) + BitBlt(localdc, destx + g_win_fullscreen_offsetx, desty + g_win_fullscreen_offsety, width, height, localcdc, srcx, srcy, SRCCOPY); + else + { + FULLSCREEN_SCALE_TYPE xdest = destx * g_win_fullscreen_scale + g_win_fullscreen_offsetx; + FULLSCREEN_SCALE_TYPE ydest = desty * g_win_fullscreen_scale + g_win_fullscreen_offsety; + FULLSCREEN_SCALE_TYPE wdest = width * g_win_fullscreen_scale; + FULLSCREEN_SCALE_TYPE hdest = height * g_win_fullscreen_scale; + + StretchBlt(localdc, (int)xdest, (int)ydest, (int)wdest, (int)hdest, localcdc, srcx, srcy, width, height, SRCCOPY); + } + + SelectObject(localcdc, bitm_old); + ReleaseDC(g_hwnd_main,localdc); +} + +void +x_push_done() +{ +} + +void +x_auto_repeat_on(int must) +{ +} + +void +x_auto_repeat_off(int must) +{ +} + +void +x_hide_pointer(int do_hide) +{ + if(do_hide) { + ShowCursor(0); + } else { + ShowCursor(1); + } +} + +void +x_full_screen(int do_full) +{ + MONITORINFO monitor_info; + FULLSCREEN_SCALE_TYPE width, height, scalex, scaley; + int top, left; + + g_win_status_debug = 1 - do_full; + if (do_full && !g_win_fullscreen_state) { + g_main_window_saved_style = GetWindowLong(g_hwnd_main, GWL_STYLE); + g_main_window_saved_exstyle = GetWindowLong(g_hwnd_main, GWL_EXSTYLE); + GetWindowRect(g_hwnd_main, &g_main_window_saved_rect); + SetWindowLong(g_hwnd_main, GWL_STYLE, g_main_window_saved_style & ~(WS_CAPTION | WS_THICKFRAME)); + SetWindowLong(g_hwnd_main, GWL_EXSTYLE, g_main_window_saved_exstyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfo(MonitorFromWindow(g_hwnd_main, MONITOR_DEFAULTTONEAREST), &monitor_info); + left = monitor_info.rcMonitor.left; + top = monitor_info.rcMonitor.top; + width = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.right - monitor_info.rcMonitor.left); + height = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top); + scalex = width / X_A2_WINDOW_WIDTH; + scaley = height / X_A2_WINDOW_HEIGHT; + g_win_fullscreen_scale = (scalex <= scaley) ? scalex : scaley; + g_win_fullscreen_offsetx = ((int)width - (int)(g_win_fullscreen_scale * X_A2_WINDOW_WIDTH)) / 2; + g_win_fullscreen_offsety = ((int)height - (int)(g_win_fullscreen_scale * X_A2_WINDOW_HEIGHT)) / 2; + SetWindowPos(g_hwnd_main, NULL, left, top, (int)width, (int)height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + + g_win_fullscreen_state = 1; + RedrawWindow(g_hwnd_main, NULL, NULL, RDW_INVALIDATE); + + + } else { + if (g_win_fullscreen_state) { + g_win_fullscreen_offsetx = 0; + g_win_fullscreen_offsety = 0; + g_win_fullscreen_scale = 1; + SetWindowLong(g_hwnd_main, GWL_STYLE, g_main_window_saved_style); + SetWindowLong(g_hwnd_main, GWL_EXSTYLE, g_main_window_saved_exstyle); + SetWindowPos(g_hwnd_main, NULL, + g_main_window_saved_rect.left, + g_main_window_saved_rect.top, + g_main_window_saved_rect.right - g_main_window_saved_rect.left, + g_main_window_saved_rect.bottom - g_main_window_saved_rect.top, + SWP_SHOWWINDOW); + + g_win_fullscreen_state = 0; + RedrawWindow(g_hwnd_main, NULL, NULL, RDW_INVALIDATE); + } + } + return; +} + +void +clipboard_paste() +{ + if (!IsClipboardFormatAvailable(CF_TEXT)) + return; + if (!OpenClipboard(g_hwnd_main)) + return; + { + HGLOBAL hclipboard = GetClipboardData(CF_TEXT); + if (!hclipboard) { + CloseClipboard(); + return; + } + { + LPSTR clipboard = (LPSTR)GlobalLock(hclipboard); + if (!clipboard) { + CloseClipboard(); + return; + } + if (g_clipboard) { + free(g_clipboard); + g_clipboard_pos = 0; + } + g_clipboard = strdup(clipboard); + } + GlobalUnlock(hclipboard); + } + CloseClipboard(); +} + +int +clipboard_get_char() +{ + if (!g_clipboard) + return 0; + if (g_clipboard[g_clipboard_pos] == '\n') + g_clipboard_pos++; + if (g_clipboard[g_clipboard_pos] == '\0') + return 0; + return g_clipboard[g_clipboard_pos++] | 0x80; +} diff --git a/src/win_keymap.h b/src/win_keymap.h index 913506b..00b8d59 100644 --- a/src/win_keymap.h +++ b/src/win_keymap.h @@ -1,124 +1,124 @@ -/* this table is used to search for the Windows VK_* in col 1 or 2 */ -/* flags bit 8 is or'ed into the VK, so we can distinguish keypad keys */ -/* regardless of numlock */ -int g_a2_key_to_wsym[][3] = { - { 0x35, VK_ESCAPE, 0 }, - { 0x7a, VK_F1, 0 }, - { 0x78, VK_F2, 0 }, // OG Was 7B but F2 is defined has 0x78 in a2_key_to_ascii - { 0x63, VK_F3, 0 }, - { 0x76, VK_F4, 0 }, - { 0x60, VK_F5, 0 }, - { 0x61, VK_F6, 0 }, - { 0x62, VK_F7, 0 }, - { 0x64, VK_F8, 0 }, - { 0x65, VK_F9, 0 }, - { 0x6d, VK_F10, 0 }, - { 0x67, VK_F11, 0 }, - { 0x6f, VK_F12, 0 }, - { 0x69, VK_F13, 0 }, - { 0x6b, VK_F14, 0 }, - { 0x71, VK_F15, 0 }, - { 0x7f, VK_PAUSE, VK_CANCEL+0x100 }, - - { 0x32, 0xc0, 0 }, /* '`' */ - { 0x12, '1', 0 }, - { 0x13, '2', 0 }, - { 0x14, '3', 0 }, - { 0x15, '4', 0 }, - { 0x17, '5', 0 }, - { 0x16, '6', 0 }, - { 0x1a, '7', 0 }, - { 0x1c, '8', 0 }, - { 0x19, '9', 0 }, - { 0x1d, '0', 0 }, - { 0x1b, 0xbd, 0 }, /* '-' */ - { 0x18, 0xbb, 0 }, /* '=' */ - { 0x33, VK_BACK, 0 }, /* backspace */ - { 0x72, VK_INSERT+0x100, 0 }, /* Insert key */ -/* { 0x73, XK_Home, 0 }, alias VK_HOME to be KP_Equal! */ - { 0x74, VK_PRIOR+0x100, 0 }, /* pageup */ - { 0x47, VK_NUMLOCK, VK_NUMLOCK+0x100 }, /* clear */ - { 0x51, VK_HOME+0x100, 0 }, /* KP_equal is HOME key */ - { 0x4b, VK_DIVIDE, VK_DIVIDE+0x100 }, - { 0x43, VK_MULTIPLY, VK_MULTIPLY+0x100 }, - - { 0x30, VK_TAB, 0 }, - { 0x0c, 'Q', 0 }, - { 0x0d, 'W', 0 }, - { 0x0e, 'E', 0 }, - { 0x0f, 'R', 0 }, - { 0x11, 'T', 0 }, - { 0x10, 'Y', 0 }, - { 0x20, 'U', 0 }, - { 0x22, 'I', 0 }, - { 0x1f, 'O', 0 }, - { 0x23, 'P', 0 }, - { 0x21, 0xdb, 0 }, /* [ */ - { 0x1e, 0xdd, 0 }, /* ] */ - { 0x2a, 0xdc, 0 }, /* backslash, bar */ - { 0x75, VK_DELETE+0x100, 0 }, - { 0x77, VK_END+0x100, VK_END }, - { 0x79, VK_NEXT+0x100, 0 }, - { 0x59, VK_NUMPAD7, VK_HOME }, - { 0x5b, VK_NUMPAD8, VK_UP }, - { 0x5c, VK_NUMPAD9, VK_PRIOR }, - { 0x4e, VK_SUBTRACT, VK_SUBTRACT+0x100 }, - - // { 0x39, VK_CAPITAL, 0 }, // Handled specially! - { 0x00, 'A', 0 }, - { 0x01, 'S', 0 }, - { 0x02, 'D', 0 }, - { 0x03, 'F', 0 }, - { 0x05, 'G', 0 }, - { 0x04, 'H', 0 }, - { 0x26, 'J', 0 }, - { 0x28, 'K', 0 }, - { 0x25, 'L', 0 }, - { 0x29, 0xba, 0 }, /* ; */ - { 0x27, 0xde, 0 }, /* single quote */ - { 0x24, VK_RETURN, 0 }, - { 0x56, VK_NUMPAD4, VK_LEFT }, - { 0x57, VK_NUMPAD5, VK_CLEAR }, - { 0x58, VK_NUMPAD6, VK_RIGHT }, - { 0x45, VK_ADD, 0 }, - - { 0x38, VK_SHIFT, 0 }, - { 0x06, 'Z', 0 }, - { 0x07, 'X', 0 }, - { 0x08, 'C', 0 }, - { 0x09, 'V', 0 }, - { 0x0b, 'B', 0 }, - { 0x2d, 'N', 0 }, - { 0x2e, 'M', 0 }, - { 0x2b, 0xbc, 0 }, /* , */ - { 0x2f, 0xbe, 0 }, /* . */ - { 0x2c, 0xbf, 0 }, /* / */ - { 0x3e, VK_UP+0x100, 0 }, - { 0x53, VK_NUMPAD1, VK_END }, - { 0x54, VK_NUMPAD2, VK_DOWN }, - { 0x55, VK_NUMPAD3, VK_NEXT }, - - { 0x36, VK_CONTROL, VK_CONTROL+0x100 }, - { 0x3a, VK_SNAPSHOT+0x100, VK_MENU+0x100 },/* Opt=prntscrn or alt-r */ - -// OG ActiveGS map OA-CA to Win & AltKey -#ifndef ACTIVEGS - { 0x37, VK_SCROLL, VK_MENU }, /* Command=scr_lock or alt-l */ -#else - { 0x7f, VK_CANCEL, 0 }, - { 0x3A, VK_LWIN+0x100, VK_LWIN }, - { 0x37, VK_MENU, 0 }, /* Command=alt-l */ - { 0x37, VK_LMENU, 0 }, /* Command=alt-l */ - { 0x7F, VK_SCROLL,0 }, /* RESET */ - { 0x36, VK_LCONTROL, 0 }, // CTRL -#endif - - { 0x31, ' ', 0 }, - { 0x3b, VK_LEFT+0x100, 0 }, - { 0x3d, VK_DOWN+0x100, 0 }, - { 0x3c, VK_RIGHT+0x100, 0 }, - { 0x52, VK_NUMPAD0, VK_INSERT }, - { 0x41, VK_DECIMAL, VK_DECIMAL }, - { 0x4c, VK_RETURN+0x100, 0 }, - { -1, -1, -1 } -}; \ No newline at end of file +/* this table is used to search for the Windows VK_* in col 1 or 2 */ +/* flags bit 8 is or'ed into the VK, so we can distinguish keypad keys */ +/* regardless of numlock */ +int g_a2_key_to_wsym[][3] = { + { 0x35, VK_ESCAPE, 0 }, + { 0x7a, VK_F1, 0 }, + { 0x78, VK_F2, 0 }, // OG Was 7B but F2 is defined has 0x78 in a2_key_to_ascii + { 0x63, VK_F3, 0 }, + { 0x76, VK_F4, 0 }, + { 0x60, VK_F5, 0 }, + { 0x61, VK_F6, 0 }, + { 0x62, VK_F7, 0 }, + { 0x64, VK_F8, 0 }, + { 0x65, VK_F9, 0 }, + { 0x6d, VK_F10, 0 }, + { 0x67, VK_F11, 0 }, + { 0x6f, VK_F12, 0 }, + { 0x69, VK_F13, 0 }, + { 0x6b, VK_F14, 0 }, + { 0x71, VK_F15, 0 }, + { 0x7f, VK_PAUSE, VK_CANCEL+0x100 }, + + { 0x32, 0xc0, 0 }, /* '`' */ + { 0x12, '1', 0 }, + { 0x13, '2', 0 }, + { 0x14, '3', 0 }, + { 0x15, '4', 0 }, + { 0x17, '5', 0 }, + { 0x16, '6', 0 }, + { 0x1a, '7', 0 }, + { 0x1c, '8', 0 }, + { 0x19, '9', 0 }, + { 0x1d, '0', 0 }, + { 0x1b, 0xbd, 0 }, /* '-' */ + { 0x18, 0xbb, 0 }, /* '=' */ + { 0x33, VK_BACK, 0 }, /* backspace */ + { 0x72, VK_INSERT+0x100, 0 }, /* Insert key */ +/* { 0x73, XK_Home, 0 }, alias VK_HOME to be KP_Equal! */ + { 0x74, VK_PRIOR+0x100, 0 }, /* pageup */ + { 0x47, VK_NUMLOCK, VK_NUMLOCK+0x100 }, /* clear */ + { 0x51, VK_HOME+0x100, 0 }, /* KP_equal is HOME key */ + { 0x4b, VK_DIVIDE, VK_DIVIDE+0x100 }, + { 0x43, VK_MULTIPLY, VK_MULTIPLY+0x100 }, + + { 0x30, VK_TAB, 0 }, + { 0x0c, 'Q', 0 }, + { 0x0d, 'W', 0 }, + { 0x0e, 'E', 0 }, + { 0x0f, 'R', 0 }, + { 0x11, 'T', 0 }, + { 0x10, 'Y', 0 }, + { 0x20, 'U', 0 }, + { 0x22, 'I', 0 }, + { 0x1f, 'O', 0 }, + { 0x23, 'P', 0 }, + { 0x21, 0xdb, 0 }, /* [ */ + { 0x1e, 0xdd, 0 }, /* ] */ + { 0x2a, 0xdc, 0 }, /* backslash, bar */ + { 0x75, VK_DELETE+0x100, 0 }, + { 0x77, VK_END+0x100, VK_END }, + { 0x79, VK_NEXT+0x100, 0 }, + { 0x59, VK_NUMPAD7, VK_HOME }, + { 0x5b, VK_NUMPAD8, VK_UP }, + { 0x5c, VK_NUMPAD9, VK_PRIOR }, + { 0x4e, VK_SUBTRACT, VK_SUBTRACT+0x100 }, + + // { 0x39, VK_CAPITAL, 0 }, // Handled specially! + { 0x00, 'A', 0 }, + { 0x01, 'S', 0 }, + { 0x02, 'D', 0 }, + { 0x03, 'F', 0 }, + { 0x05, 'G', 0 }, + { 0x04, 'H', 0 }, + { 0x26, 'J', 0 }, + { 0x28, 'K', 0 }, + { 0x25, 'L', 0 }, + { 0x29, 0xba, 0 }, /* ; */ + { 0x27, 0xde, 0 }, /* single quote */ + { 0x24, VK_RETURN, 0 }, + { 0x56, VK_NUMPAD4, VK_LEFT }, + { 0x57, VK_NUMPAD5, VK_CLEAR }, + { 0x58, VK_NUMPAD6, VK_RIGHT }, + { 0x45, VK_ADD, 0 }, + + { 0x38, VK_SHIFT, 0 }, + { 0x06, 'Z', 0 }, + { 0x07, 'X', 0 }, + { 0x08, 'C', 0 }, + { 0x09, 'V', 0 }, + { 0x0b, 'B', 0 }, + { 0x2d, 'N', 0 }, + { 0x2e, 'M', 0 }, + { 0x2b, 0xbc, 0 }, /* , */ + { 0x2f, 0xbe, 0 }, /* . */ + { 0x2c, 0xbf, 0 }, /* / */ + { 0x3e, VK_UP+0x100, 0 }, + { 0x53, VK_NUMPAD1, VK_END }, + { 0x54, VK_NUMPAD2, VK_DOWN }, + { 0x55, VK_NUMPAD3, VK_NEXT }, + + { 0x36, VK_CONTROL, VK_CONTROL+0x100 }, + { 0x3a, VK_SNAPSHOT+0x100, VK_MENU+0x100 },/* Opt=prntscrn or alt-r */ + +// OG ActiveGS map OA-CA to Win & AltKey +#ifndef ACTIVEGS + { 0x37, VK_SCROLL, VK_MENU }, /* Command=scr_lock or alt-l */ +#else + { 0x7f, VK_CANCEL, 0 }, + { 0x3A, VK_LWIN+0x100, VK_LWIN }, + { 0x37, VK_MENU, 0 }, /* Command=alt-l */ + { 0x37, VK_LMENU, 0 }, /* Command=alt-l */ + { 0x7F, VK_SCROLL,0 }, /* RESET */ + { 0x36, VK_LCONTROL, 0 }, // CTRL +#endif + + { 0x31, ' ', 0 }, + { 0x3b, VK_LEFT+0x100, 0 }, + { 0x3d, VK_DOWN+0x100, 0 }, + { 0x3c, VK_RIGHT+0x100, 0 }, + { 0x52, VK_NUMPAD0, VK_INSERT }, + { 0x41, VK_DECIMAL, VK_DECIMAL }, + { 0x4c, VK_RETURN+0x100, 0 }, + { -1, -1, -1 } +}; diff --git a/src/winresource.h b/src/winresource.h index f40907f..64a91d0 100644 --- a/src/winresource.h +++ b/src/winresource.h @@ -1,58 +1,58 @@ -//{{NO_DEPENDENCIES}} -// $Id: $ -// Microsoft Developer Studio generated include file. -// Used by win32.rc -// -#define CREATEPROCESS_MANIFEST 1 -#define IDD_ABOUT_DIALOG 101 -#define IDC_GSPORT32 102 -#define IDR_TOOLBAR 103 -#define IDD_DLG_DISKCONF 104 -#define IDR_ACCEL 105 -#define IDD_GSPORT32_KEY 106 -#define ID_TOOLBAR 5000 -#define ID_STATUSBAR 5001 -#define IDC_EDIT_S5D1 10051 -#define IDC_EDIT_S5D2 10052 -#define IDC_EDIT_S6D1 10061 -#define IDC_EDIT_S6D2 10062 -#define IDC_EDIT_S7D1 10071 -#define IDC_EDIT_S7D2 10072 -#define IDC_BTN_S5D1 11051 -#define IDC_BTN_S5D2 11052 -#define IDC_BTN_S6D1 11061 -#define IDC_BTN_S6D2 11062 -#define IDC_BTN_S7D1 11071 -#define IDC_BTN_S7D2 11072 -#define ID_HELP_ABOUT 40001 -#define ID_FILE_EXIT 40002 -#define ID_FILE_DISK 40003 -#define ID_FILE_SENDRESET 40004 -#define ID_FILE_JOYSTICK 40005 -#define ID_FILE_DEBUGSTAT 40006 -#define ID_FILE_FULLSCREEN 40012 -#define ID_FILE_SPEED 40013 -#define ID_HELP_KEY 40014 -#define ID_FILE_SENDREBOOT 40007 -#define ID_FILE_FLUSHPRINTER 40017 -#define ID_SPEED_1MHZ 50001 -#define ID_SPEED_2MHZ 50002 -#define ID_SPEED_8MHZ 50003 -#define ID_SPEED_FMHZ 50004 -#define IDD_SPEEDDIALOG 117 -#define IDC_SLOW 1007 -#define IDC_CUSTOM 1008 -#define IDC_EDITCUSTOM 1009 -#define IDC_NORMAL 1010 -#define IDC_FASTEST 1011 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 111 -#define _APS_NEXT_COMMAND_VALUE 40013 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// $Id: $ +// Microsoft Developer Studio generated include file. +// Used by win32.rc +// +#define CREATEPROCESS_MANIFEST 1 +#define IDD_ABOUT_DIALOG 101 +#define IDC_GSPORT32 102 +#define IDR_TOOLBAR 103 +#define IDD_DLG_DISKCONF 104 +#define IDR_ACCEL 105 +#define IDD_GSPORT32_KEY 106 +#define ID_TOOLBAR 5000 +#define ID_STATUSBAR 5001 +#define IDC_EDIT_S5D1 10051 +#define IDC_EDIT_S5D2 10052 +#define IDC_EDIT_S6D1 10061 +#define IDC_EDIT_S6D2 10062 +#define IDC_EDIT_S7D1 10071 +#define IDC_EDIT_S7D2 10072 +#define IDC_BTN_S5D1 11051 +#define IDC_BTN_S5D2 11052 +#define IDC_BTN_S6D1 11061 +#define IDC_BTN_S6D2 11062 +#define IDC_BTN_S7D1 11071 +#define IDC_BTN_S7D2 11072 +#define ID_HELP_ABOUT 40001 +#define ID_FILE_EXIT 40002 +#define ID_FILE_DISK 40003 +#define ID_FILE_SENDRESET 40004 +#define ID_FILE_JOYSTICK 40005 +#define ID_FILE_DEBUGSTAT 40006 +#define ID_FILE_FULLSCREEN 40012 +#define ID_FILE_SPEED 40013 +#define ID_HELP_KEY 40014 +#define ID_FILE_SENDREBOOT 40007 +#define ID_FILE_FLUSHPRINTER 40017 +#define ID_SPEED_1MHZ 50001 +#define ID_SPEED_2MHZ 50002 +#define ID_SPEED_8MHZ 50003 +#define ID_SPEED_FMHZ 50004 +#define IDD_SPEEDDIALOG 117 +#define IDC_SLOW 1007 +#define IDC_CUSTOM 1008 +#define IDC_EDITCUSTOM 1009 +#define IDC_NORMAL 1010 +#define IDC_FASTEST 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40013 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/xdriver.c b/src/xdriver.c index 793a3b1..bc754d7 100644 --- a/src/xdriver.c +++ b/src/xdriver.c @@ -1,1417 +1,1419 @@ -/* - GSPLUS - Advanced Apple IIGS Emulator Environment - Copyright (C) 2010 - 2012 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -# if !defined(__CYGWIN__) && !defined(__POWERPC__) -/* No shared memory on Cygwin */ -# define X_SHARED_MEM -#endif /* CYGWIN */ - -#include -#include -#include -#include -#include -#include - -#ifdef X_SHARED_MEM -# include -# include -# include -#endif - -int XShmQueryExtension(Display *display); - -#include "defc.h" -#include "protos_xdriver.h" - -#define FONT_NAME_STATUS "8x13" - -extern int Verbose; - -extern int g_warp_pointer; -extern int g_screen_depth; -extern int g_force_depth; -int g_screen_mdepth = 0; - -extern int _Xdebug; - -extern int g_send_sound_to_file; - -extern int g_quit_sim_now; - -int g_has_focus = 0; -int g_auto_repeat_on = -1; -int g_x_shift_control_state = 0; - - -Display *g_display = 0; -Visual *g_vis = 0; -Window g_a2_win; -GC g_a2_winGC; -Atom WM_DELETE_WINDOW; -XFontStruct *g_text_FontSt; -Colormap g_a2_colormap = 0; -Colormap g_default_colormap = 0; -int g_needs_cmap = 0; -int g_win_status_debug = 0; // Current visibility of status lines. -int g_win_status_debug_request = 0; // Desired visibility of status lines. - -extern word32 g_red_mask; -extern word32 g_green_mask; -extern word32 g_blue_mask; -extern int g_red_left_shift; -extern int g_green_left_shift; -extern int g_blue_left_shift; -extern int g_red_right_shift; -extern int g_green_right_shift; -extern int g_blue_right_shift; - -#ifdef X_SHARED_MEM -int g_use_shmem = 1; -#else -int g_use_shmem = 0; -#endif - -extern Kimage g_mainwin_kimage; - -extern int Max_color_size; - -XColor g_xcolor_a2vid_array[256]; - -extern word32 g_palette_8to1624[256]; -extern word32 g_a2palette_8to1624[256]; - -int g_alt_left_up = 1; -int g_alt_right_up = 1; - -extern word32 g_full_refresh_needed; - -extern int g_border_sides_refresh_needed; -extern int g_border_special_refresh_needed; -extern int g_status_refresh_needed; - -extern int g_lores_colors[]; -extern int g_cur_a2_stat; - -extern int g_a2vid_palette; - -extern int g_installed_full_superhires_colormap; - -extern int g_screen_redraw_skip_amt; - -extern word32 g_a2_screen_buffer_changed; - -extern char *g_status_ptrs[MAX_STATUS_LINES]; - -Cursor g_cursor; -Pixmap g_cursor_shape; -Pixmap g_cursor_mask; - -XColor g_xcolor_black = { 0, 0x0000, 0x0000, 0x0000, DoRed|DoGreen|DoBlue, 0 }; -XColor g_xcolor_white = { 0, 0xffff, 0xffff, 0xffff, DoRed|DoGreen|DoBlue, 0 }; - -int g_depth_attempt_list[] = { 16, 24, 15, 8 }; - - -#define X_EVENT_LIST_ALL_WIN \ - (ExposureMask | ButtonPressMask | ButtonReleaseMask | \ - OwnerGrabButtonMask | KeyPressMask | KeyReleaseMask | \ - KeymapStateMask | ColormapChangeMask | FocusChangeMask) - -#define X_BASE_WIN_EVENT_LIST \ - (X_EVENT_LIST_ALL_WIN | PointerMotionMask | ButtonMotionMask) - -#define X_A2_WIN_EVENT_LIST \ - (X_BASE_WIN_EVENT_LIST) - -int g_num_a2_keycodes = 0; - -int a2_key_to_xsym[][3] = { - { 0x35, XK_Escape, 0 }, - { 0x7a, XK_F1, 0 }, - { 0x78, XK_F2, 0 }, - { 0x63, XK_F3, 0 }, - { 0x76, XK_F4, 0 }, - { 0x60, XK_F5, 0 }, - { 0x61, XK_F6, 0 }, - { 0x62, XK_F7, 0 }, - { 0x64, XK_F8, 0 }, - { 0x65, XK_F9, 0 }, - { 0x6d, XK_F10, 0 }, - { 0x67, XK_F11, 0 }, - { 0x6f, XK_F12, 0 }, - { 0x69, XK_F13, 0 }, - { 0x6b, XK_F14, 0 }, - { 0x71, XK_F15, 0 }, - { 0x7f, XK_Pause, XK_Break }, - { 0x32, '`', '~' }, /* Key number 18? */ - { 0x12, '1', '!' }, - { 0x13, '2', '@' }, - { 0x14, '3', '#' }, - { 0x15, '4', '$' }, - { 0x17, '5', '%' }, - { 0x16, '6', '^' }, - { 0x1a, '7', '&' }, - { 0x1c, '8', '*' }, - { 0x19, '9', '(' }, - { 0x1d, '0', ')' }, - { 0x1b, '-', '_' }, - { 0x18, '=', '+' }, - { 0x33, XK_BackSpace, 0 }, - { 0x72, XK_Insert, XK_Help }, /* Help? */ -/* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ - { 0x74, XK_Page_Up, 0 }, - { 0x47, XK_Num_Lock, XK_Clear }, /* Clear */ - { 0x51, XK_KP_Equal, XK_Home }, /* Note XK_Home alias! */ - { 0x4b, XK_KP_Divide, 0 }, - { 0x43, XK_KP_Multiply, 0 }, - - { 0x30, XK_Tab, 0 }, - { 0x0c, 'q', 'Q' }, - { 0x0d, 'w', 'W' }, - { 0x0e, 'e', 'E' }, - { 0x0f, 'r', 'R' }, - { 0x11, 't', 'T' }, - { 0x10, 'y', 'Y' }, - { 0x20, 'u', 'U' }, - { 0x22, 'i', 'I' }, - { 0x1f, 'o', 'O' }, - { 0x23, 'p', 'P' }, - { 0x21, '[', '{' }, - { 0x1e, ']', '}' }, - { 0x2a, 0x5c, '|' }, /* backslash, bar */ - { 0x75, XK_Delete, 0 }, - { 0x77, XK_End, 0 }, - { 0x79, XK_Page_Down, 0 }, - { 0x59, XK_KP_7, XK_KP_Home }, - { 0x5b, XK_KP_8, XK_KP_Up }, - { 0x5c, XK_KP_9, XK_KP_Page_Up }, - { 0x4e, XK_KP_Subtract, 0 }, - - { 0x39, XK_Caps_Lock, 0 }, - { 0x00, 'a', 'A' }, - { 0x01, 's', 'S' }, - { 0x02, 'd', 'D' }, - { 0x03, 'f', 'F' }, - { 0x05, 'g', 'G' }, - { 0x04, 'h', 'H' }, - { 0x26, 'j', 'J' }, - { 0x28, 'k', 'K' }, - { 0x25, 'l', 'L' }, - { 0x29, ';', ':' }, - { 0x27, 0x27, '"' }, /* single quote */ - { 0x24, XK_Return, 0 }, - { 0x56, XK_KP_4, XK_KP_Left }, - { 0x57, XK_KP_5, 0 }, - { 0x58, XK_KP_6, XK_KP_Right }, - { 0x45, XK_KP_Add, 0 }, - - { 0x38, XK_Shift_L, XK_Shift_R }, - { 0x06, 'z', 'Z' }, - { 0x07, 'x', 'X' }, - { 0x08, 'c', 'C' }, - { 0x09, 'v', 'V' }, - { 0x0b, 'b', 'B' }, - { 0x2d, 'n', 'N' }, - { 0x2e, 'm', 'M' }, - { 0x2b, ',', '<' }, - { 0x2f, '.', '>' }, - { 0x2c, '/', '?' }, - { 0x3e, XK_Up, 0 }, - { 0x53, XK_KP_1, XK_KP_End }, - { 0x54, XK_KP_2, XK_KP_Down }, - { 0x55, XK_KP_3, XK_KP_Page_Down }, - - { 0x36, XK_Control_L, XK_Control_R }, - { 0x3a, XK_Print, XK_Sys_Req }, /* Option */ - { 0x37, XK_Scroll_Lock, 0 }, /* Command */ - { 0x31, ' ', 0 }, - { 0x3b, XK_Left, 0 }, - { 0x3d, XK_Down, 0 }, - { 0x3c, XK_Right, 0 }, - { 0x52, XK_KP_0, XK_KP_Insert }, - { 0x41, XK_KP_Decimal, XK_KP_Separator }, - { 0x4c, XK_KP_Enter, 0 }, - { -1, -1, -1 } -}; - -int -main(int argc, char **argv) -{ - return gsportmain(argc, argv); -} - -void -x_dialog_create_gsport_conf(const char *str) -{ - // Just write the config file already... - config_write_config_gsport_file(); -} - -int -x_show_alert(int is_fatal, const char *str) -{ - /* Not implemented yet */ - adb_all_keys_up(); - - clear_fatal_logs(); - return 0; -} - - -#define MAKE_2(val) ( (val << 8) + val) - -void -x_update_color(int col_num, int red, int green, int blue, word32 rgb) -{ - XColor *xcol; - - xcol = &(g_xcolor_a2vid_array[col_num]); - xcol->red = MAKE_2(red); - xcol->green = MAKE_2(green); - xcol->blue = MAKE_2(blue); - xcol->flags = DoRed | DoGreen | DoBlue; -} - -void -x_update_physical_colormap() -{ - if(g_needs_cmap) { - XStoreColors(g_display, g_a2_colormap, - &g_xcolor_a2vid_array[0], Max_color_size); - } -} - -void -show_xcolor_array() -{ - int i; - - for(i = 0; i < 256; i++) { - printf("%02x: %08x\n", i, g_palette_8to1624[i]); - -#if 0 - printf("%02x: %04x %04x %04x, %02x %x\n", - i, xcolor_array[i].red, xcolor_array[i].green, - xcolor_array[i].blue, (word32)xcolor_array[i].pixel, - xcolor_array[i].flags); -#endif - } -} - - -int -my_error_handler(Display *display, XErrorEvent *ev) -{ - char msg[1024]; - XGetErrorText(display, ev->error_code, msg, 1000); - printf("X Error code %s\n", msg); - fflush(stdout); - - return 0; -} - -void -xdriver_end() -{ - - printf("xdriver_end\n"); - if(g_display) { - x_auto_repeat_on(1); - XFlush(g_display); - } -} - -void -show_colormap(char *str, Colormap cmap, int index1, int index2, int index3) -{ - XColor xcol; - int i; - int pix; - - printf("Show colormap: %08x = %s, cmap cells: %d,%d,%d\n", - (int)cmap, str, index1, index2, index3); - for(i = 0; i < index1 + index2 + index3; i++) { - pix = i; - if(i >= index1) { - pix = (i-index1)*index1; - if(i >= (index1 + index2)) { - pix = (i - index1 - index2)*index2*index1; - } - } - if(i == 0 && index1 < 250) { - pix = 0x842; - } - xcol.pixel = pix; - XQueryColor(g_display, cmap, &xcol); - printf("Cell %03x: pix: %03x, R:%04x, G:%04x, B:%04x\n", - i, (int)xcol.pixel, xcol.red, xcol.green, xcol.blue); - } -} - -void -x_badpipe(int signum) -{ - /* restore normal sigpipe handling */ - signal(SIGPIPE, SIG_DFL); - - /* attempt to xset r */ - system("xset r"); - my_exit(5); -} - -void -dev_video_init() -{ - int tmp_array[0x80]; - XGCValues new_gc; - XSetWindowAttributes win_attr; - XSizeHints my_winSizeHints; - XClassHint my_winClassHint; - XTextProperty my_winText; - XVisualInfo *visualList; - char **font_ptr; - char cursor_data; - word32 create_win_list; - int depth; - int len; - int cmap_alloc_amt; - int cnt; - int font_height; - int base_height; - int screen_num; - char *myTextString[1]; - word32 lores_col; - int ret; - int i; - int keycode; - - printf("Preparing X Windows graphics system\n"); - ret = 0; - - signal(SIGPIPE, x_badpipe); - - g_num_a2_keycodes = 0; - for(i = 0; i <= 0x7f; i++) { - tmp_array[i] = 0; - } - for(i = 0; i < 0x7f; i++) { - keycode = a2_key_to_xsym[i][0]; - if(keycode < 0) { - g_num_a2_keycodes = i; - break; - } else if(keycode > 0x7f) { - printf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); - exit(2); - } else { - if(tmp_array[keycode]) { - printf("a2_key_to_x[%d] = %02x used by %d\n", - i, keycode, tmp_array[keycode] - 1); - } - tmp_array[keycode] = i + 1; - } - } - -#if 0 - printf("Setting _Xdebug = 1, makes X synchronous\n"); - _Xdebug = 1; -#endif - - g_display = XOpenDisplay(NULL); - if(g_display == NULL) { - fprintf(stderr, "Can't open display\n"); - exit(1); - } - - vid_printf("Just opened display = %p\n", g_display); - fflush(stdout); - - screen_num = DefaultScreen(g_display); - - len = sizeof(g_depth_attempt_list)/sizeof(int); - if(g_force_depth > 0) { - /* Only use the requested user depth */ - len = 1; - g_depth_attempt_list[0] = g_force_depth; - } - g_vis = 0; - for(i = 0; i < len; i++) { - depth = g_depth_attempt_list[i]; - - g_vis = x_try_find_visual(depth, screen_num, - &visualList); - if(g_vis != 0) { - break; - } - } - if(g_vis == 0) { - fprintf(stderr, "Couldn't find any visuals at any depth!\n"); - exit(2); - } - - g_default_colormap = XDefaultColormap(g_display, screen_num); - if(!g_default_colormap) { - printf("g_default_colormap == 0!\n"); - exit(4); - } - - g_a2_colormap = -1; - cmap_alloc_amt = AllocNone; - if(g_needs_cmap) { - cmap_alloc_amt = AllocAll; - } - g_a2_colormap = XCreateColormap(g_display, - RootWindow(g_display,screen_num), g_vis, - cmap_alloc_amt); - - vid_printf("g_a2_colormap: %08x, main: %08x\n", - (word32)g_a2_colormap, (word32)g_default_colormap); - - if(g_needs_cmap && g_a2_colormap == g_default_colormap) { - printf("A2_colormap = default colormap!\n"); - exit(4); - } - - /* and define cursor */ - cursor_data = 0; - g_cursor_shape = XCreatePixmapFromBitmapData(g_display, - RootWindow(g_display,screen_num), &cursor_data, 1, 1, 1, 0, 1); - g_cursor_mask = XCreatePixmapFromBitmapData(g_display, - RootWindow(g_display,screen_num), &cursor_data, 1, 1, 1, 0, 1); - - g_cursor = XCreatePixmapCursor(g_display, g_cursor_shape, - g_cursor_mask, &g_xcolor_black, &g_xcolor_white, 0, 0); - - XFreePixmap(g_display, g_cursor_shape); - XFreePixmap(g_display, g_cursor_mask); - - XFlush(g_display); - - win_attr.event_mask = X_A2_WIN_EVENT_LIST; - win_attr.colormap = g_a2_colormap; - win_attr.backing_store = WhenMapped; - win_attr.border_pixel = 1; - win_attr.background_pixel = 0; - if(g_warp_pointer) { - win_attr.cursor = g_cursor; - } else { - win_attr.cursor = None; - } - - vid_printf("About to a2_win, depth: %d\n", g_screen_depth); - fflush(stdout); - - create_win_list = CWEventMask | CWBackingStore | CWCursor; - create_win_list |= CWColormap | CWBorderPixel | CWBackPixel; - - base_height = X_A2_WINDOW_HEIGHT; - if (g_win_status_debug) - base_height += MAX_STATUS_LINES * 13; - - g_a2_win = XCreateWindow(g_display, RootWindow(g_display, screen_num), - 0, 0, BASE_WINDOW_WIDTH, base_height, - 0, g_screen_depth, InputOutput, g_vis, - create_win_list, &win_attr); - - XSetWindowColormap(g_display, g_a2_win, g_a2_colormap); - - XFlush(g_display); - -/* Check for XShm */ -#ifdef X_SHARED_MEM - if(g_use_shmem) { - ret = XShmQueryExtension(g_display); - if(ret == 0) { - printf("XShmQueryExt ret: %d\n", ret); - printf("not using shared memory\n"); - g_use_shmem = 0; - } else { - printf("Will use shared memory for X\n"); - } - } -#endif - - video_get_kimages(); - if(g_screen_depth != 8) { - video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, - g_screen_mdepth); - } - - if(!g_use_shmem) { - if(g_screen_redraw_skip_amt < 0) { - g_screen_redraw_skip_amt = 3; - } - printf("Not using shared memory, setting skip_amt = %d\n", - g_screen_redraw_skip_amt); - } - - /* Done with visualList now */ - XFree(visualList); - - for(i = 0; i < 256; i++) { - g_xcolor_a2vid_array[i].pixel = i; - lores_col = g_lores_colors[i & 0xf]; - video_update_color_raw(i, lores_col); - g_a2palette_8to1624[i] = g_palette_8to1624[i]; - } - - x_update_physical_colormap(); - - g_installed_full_superhires_colormap = !g_needs_cmap; - - myTextString[0] = "GSport"; - - XStringListToTextProperty(myTextString, 1, &my_winText); - - my_winSizeHints.flags = PSize | PMinSize | PMaxSize; - my_winSizeHints.width = BASE_WINDOW_WIDTH; - my_winSizeHints.height = base_height; - my_winSizeHints.min_width = BASE_WINDOW_WIDTH; - my_winSizeHints.min_height = base_height; - my_winSizeHints.max_width = BASE_WINDOW_WIDTH; - my_winSizeHints.max_height = base_height; - my_winClassHint.res_name = "GSport"; - my_winClassHint.res_class = "GSport"; - - XSetWMProperties(g_display, g_a2_win, &my_winText, &my_winText, 0, - 0, &my_winSizeHints, 0, &my_winClassHint); - - WM_DELETE_WINDOW = XInternAtom(g_display, "WM_DELETE_WINDOW", False); - XSetWMProtocols(g_display, g_a2_win, &WM_DELETE_WINDOW, 1); - XMapRaised(g_display, g_a2_win); - - XSync(g_display, False); - - g_a2_winGC = XCreateGC(g_display, g_a2_win, 0, (XGCValues *) 0); - font_ptr = XListFonts(g_display, FONT_NAME_STATUS, 4, &cnt); - - vid_printf("act_cnt of fonts: %d\n", cnt); - for(i = 0; i < cnt; i++) { - vid_printf("Font %d: %s\n", i, font_ptr[i]); - } - fflush(stdout); - g_text_FontSt = XLoadQueryFont(g_display, FONT_NAME_STATUS); - vid_printf("font # returned: %08x\n", (word32)(g_text_FontSt->fid)); - font_height = g_text_FontSt->ascent + g_text_FontSt->descent; - vid_printf("font_height: %d\n", font_height); - - vid_printf("widest width: %d\n", g_text_FontSt->max_bounds.width); - - new_gc.font = g_text_FontSt->fid; - new_gc.fill_style = FillSolid; - XChangeGC(g_display, g_a2_winGC, GCFillStyle | GCFont, &new_gc); - - /* XSync(g_display, False); */ -#if 0 -/* MkLinux for Powermac depth 15 has bugs--this was to try to debug them */ - if(g_screen_depth == 15) { - /* draw phony screen */ - ptr16 = (word16 *)dint_main_win; - for(i = 0; i < 320*400; i++) { - ptr16[i] = 0; - } - for(i = 0; i < 400; i++) { - for(j = 0; j < 640; j++) { - sh = (j / 20) & 0x1f; - val = sh; - val = val; - *ptr16++ = val; - } - } - XPutImage(g_display, g_a2_win, g_a2_winGC, xint_main_win, - 0, 0, - BASE_MARGIN_LEFT, BASE_MARGIN_TOP, - 640, 400); - XFlush(g_display); - } -#endif - - - XFlush(g_display); - fflush(stdout); -} - -Visual * -x_try_find_visual(int depth, int screen_num, XVisualInfo **visual_list_ptr) -{ - XVisualInfo *visualList; - XVisualInfo *v_chosen; - XVisualInfo vTemplate; - int visualsMatched; - int mdepth; - int needs_cmap; - int visual_chosen; - int match8, match24; - int i; - - vTemplate.screen = screen_num; - vTemplate.depth = depth; - - visualList = XGetVisualInfo(g_display, - (VisualScreenMask | VisualDepthMask), - &vTemplate, &visualsMatched); - - vid_printf("visuals matched: %d\n", visualsMatched); - if(visualsMatched == 0) { - return (Visual *)0; - } - - visual_chosen = -1; - needs_cmap = 0; - for(i = 0; i < visualsMatched; i++) { - printf("Visual %d\n", i); - printf(" id: %08x, screen: %d, depth: %d, class: %d\n", - (word32)visualList[i].visualid, - visualList[i].screen, - visualList[i].depth, - visualList[i].class); - printf(" red: %08lx, green: %08lx, blue: %08lx\n", - visualList[i].red_mask, - visualList[i].green_mask, - visualList[i].blue_mask); - printf(" cmap size: %d, bits_per_rgb: %d\n", - visualList[i].colormap_size, - visualList[i].bits_per_rgb); - match8 = (visualList[i].class == PseudoColor); - match24 = (visualList[i].class == TrueColor); - if((depth == 8) && match8) { - visual_chosen = i; - Max_color_size = visualList[i].colormap_size; - needs_cmap = 1; - break; - } - if((depth != 8) && match24) { - visual_chosen = i; - Max_color_size = -1; - needs_cmap = 0; - break; - } - } - - if(visual_chosen < 0) { - printf("Couldn't find any good visuals at depth %d!\n", - depth); - return (Visual *)0; - } - - printf("Chose visual: %d, max_colors: %d\n", visual_chosen, - Max_color_size); - - v_chosen = &(visualList[visual_chosen]); - x_set_mask_and_shift(v_chosen->red_mask, &g_red_mask, - &g_red_left_shift, &g_red_right_shift); - x_set_mask_and_shift(v_chosen->green_mask, &g_green_mask, - &g_green_left_shift, &g_green_right_shift); - x_set_mask_and_shift(v_chosen->blue_mask, &g_blue_mask, - &g_blue_left_shift, &g_blue_right_shift); - - g_screen_depth = depth; - mdepth = depth; - if(depth > 8) { - mdepth = 16; - } - if(depth > 16) { - mdepth = 32; - } - g_screen_mdepth = mdepth; - g_needs_cmap = needs_cmap; - *visual_list_ptr = visualList; - - return v_chosen->visual; -} - -void -x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, - int *shift_right_ptr) -{ - int shift; - int i; - - /* Shift until we find first set bit in mask, then remember mask,shift*/ - - shift = 0; - for(i = 0; i < 32; i++) { - if(x_mask & 1) { - /* we're done! */ - break; - } - x_mask = x_mask >> 1; - shift++; - } - *mask_ptr = x_mask; - *shift_left_ptr = shift; - /* Now, calculate shift_right_ptr */ - shift = 0; - x_mask |= 1; // make sure at least one bit is set - while(x_mask < 0x80) { - shift++; - x_mask = x_mask << 1; - } - - *shift_right_ptr = shift; - return; - -} - -int g_xshm_error = 0; - -int -xhandle_shm_error(Display *display, XErrorEvent *event) -{ - g_xshm_error = 1; - return 0; -} - -void -x_get_kimage(Kimage *kimage_ptr) { - if(g_use_shmem) { - g_use_shmem = get_shm(kimage_ptr); - } - if(!g_use_shmem) { - get_ximage(kimage_ptr); - } -} - -int -get_shm(Kimage *kimage_ptr) -{ -#ifdef X_SHARED_MEM - XShmSegmentInfo *seginfo; - XImage *xim; - int (*old_x_handler)(Display *, XErrorEvent *); - int width; - int height; - int depth; - - width = kimage_ptr->width_req; - height = kimage_ptr->height; - depth = kimage_ptr->depth; - - seginfo = (XShmSegmentInfo *)malloc(sizeof(XShmSegmentInfo)); - xim = XShmCreateImage(g_display, g_vis, depth, ZPixmap, - (char *)0, seginfo, width, height); - - /* check mdepth! */ - if(xim->bits_per_pixel != kimage_ptr->mdepth) { - printf("get_shm bits_per_pix: %d != %d\n", - xim->bits_per_pixel, g_screen_mdepth); - } - - vid_printf("xim: %p\n", xim); - kimage_ptr->dev_handle = xim; - kimage_ptr->dev_handle2 = seginfo; - if(xim == 0) { - return 0; - } - - /* It worked, we got it */ - seginfo->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, - IPC_CREAT | 0777); - vid_printf("seginfo->shmid = %d\n", seginfo->shmid); - if(seginfo->shmid < 0) { - XDestroyImage(xim); - return 0; - } - - /* Still working */ - seginfo->shmaddr = (char *)shmat(seginfo->shmid, 0, 0); - vid_printf("seginfo->shmaddr: %p\n", seginfo->shmaddr); - if(seginfo->shmaddr == ((char *) -1)) { - XDestroyImage(xim); - return 0; - } - - /* Still working */ - xim->data = seginfo->shmaddr; - seginfo->readOnly = False; - - /* XShmAttach will trigger X error if server is remote, so catch it */ - g_xshm_error = 0; - old_x_handler = XSetErrorHandler(xhandle_shm_error); - - XShmAttach(g_display, seginfo); - XSync(g_display, False); - - - vid_printf("about to RMID the shmid\n"); - shmctl(seginfo->shmid, IPC_RMID, 0); - - XFlush(g_display); - XSetErrorHandler(old_x_handler); - - if(g_xshm_error) { - XDestroyImage(xim); - /* We could release the shared mem segment, but by doing the */ - /* RMID, it will go away when we die now, so just leave it */ - printf("Not using shared memory\n"); - return 0; - } - - kimage_ptr->data_ptr = (byte *)xim->data; - vid_printf("Sharing memory. xim: %p, xim->data: %p\n", xim, xim->data); - - return 1; -#else - return 0; /* No shared memory */ -#endif /* X_SHARED_MEM */ -} - -void -get_ximage(Kimage *kimage_ptr) -{ - XImage *xim; - byte *ptr; - int width; - int height; - int depth; - int mdepth; - - width = kimage_ptr->width_req; - height = kimage_ptr->height; - depth = kimage_ptr->depth; - mdepth = kimage_ptr->mdepth; - - ptr = (byte *)malloc((width * height * mdepth) >> 3); - - vid_printf("ptr: %p\n", ptr); - - if(ptr == 0) { - printf("malloc for data failed, mdepth: %d\n", mdepth); - exit(2); - } - - kimage_ptr->data_ptr = ptr; - - xim = XCreateImage(g_display, g_vis, depth, ZPixmap, 0, - (char *)ptr, width, height, 8, 0); - -#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command - xim->byte_order = LSBFirst; -#else - xim->byte_order = MSBFirst; -#endif - XInitImage(xim); /* adjust to new byte order */ - - /* check mdepth! */ - if(xim->bits_per_pixel != mdepth) { - printf("shm_ximage bits_per_pix: %d != %d\n", - xim->bits_per_pixel, mdepth); - } - - vid_printf("xim: %p\n", xim); - - kimage_ptr->dev_handle = xim; - - return; -} - - -void -x_toggle_status_lines() -{ - XSizeHints my_winSizeHints; - XClassHint my_winClassHint; - int base_height = X_A2_WINDOW_HEIGHT; - if ((g_win_status_debug = !g_win_status_debug)) - base_height += MAX_STATUS_LINES * 13; - //printf("Resize returns %d\n", XResizeWindow(g_display, g_a2_win, BASE_WINDOW_WIDTH, base_height)); - my_winSizeHints.flags = PSize | PMinSize | PMaxSize; - my_winSizeHints.width = BASE_WINDOW_WIDTH; - my_winSizeHints.height = base_height; - my_winSizeHints.min_width = BASE_WINDOW_WIDTH; - my_winSizeHints.min_height = base_height; - my_winSizeHints.max_width = BASE_WINDOW_WIDTH; - my_winSizeHints.max_height = base_height; - my_winClassHint.res_name = "GSport"; - my_winClassHint.res_class = "GSport"; - XSetWMProperties(g_display, g_a2_win, 0, 0, 0, - 0, &my_winSizeHints, 0, &my_winClassHint); - XMapRaised(g_display, g_a2_win); - XFlush(g_display); - x_redraw_status_lines(); -} - -void -x_redraw_status_lines() -{ - char *buf; - int line; - int height; - int margin; - word32 white, black; - - if (g_win_status_debug) - { - height = g_text_FontSt->ascent + g_text_FontSt->descent; - margin = g_text_FontSt->ascent; - - white = (g_a2vid_palette << 4) + 0xf; - black = (g_a2vid_palette << 4) + 0x0; - if(g_screen_depth != 8) { - white = (2 << (g_screen_depth - 1)) - 1; - black = 0; - } - XSetForeground(g_display, g_a2_winGC, white); - XSetBackground(g_display, g_a2_winGC, black); - - for(line = 0; line < MAX_STATUS_LINES; line++) { - buf = g_status_ptrs[line]; - if(buf == 0) { - /* skip it */ - continue; - } - XDrawImageString(g_display, g_a2_win, g_a2_winGC, 0, - X_A2_WINDOW_HEIGHT + height*line + margin, - buf, strlen(buf)); - } - - XFlush(g_display); - } -} - - -void -x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, - int width, int height) -{ - XImage *xim; - - xim = (XImage *)kimage_ptr->dev_handle; - -#ifdef X_SHARED_MEM - if(g_use_shmem) { - XShmPutImage(g_display, g_a2_win, g_a2_winGC, xim, - srcx, srcy, destx, desty, width, height, False); - } -#endif - if(!g_use_shmem) { - XPutImage(g_display, g_a2_win, g_a2_winGC, xim, - srcx, srcy, destx, desty, width, height); - } -} - -void -x_push_done() -{ - XFlush(g_display); -} - - -#define KEYBUFLEN 128 - -int g_num_check_input_calls = 0; -int g_check_input_flush_rate = 2; - -int -x_update_mouse(int raw_x, int raw_y, int button_states, int buttons_valid) -{ - int x, y; - - x = raw_x - BASE_MARGIN_LEFT; - y = raw_y - BASE_MARGIN_TOP; - - if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && - (y == A2_WINDOW_HEIGHT/2) && (buttons_valid == 0) ) { - /* tell adb routs to recenter but ignore this motion */ - update_mouse(x, y, 0, -1); - return 0; - } - return update_mouse(x, y, button_states, buttons_valid & 7); -} - -void -check_input_events() -{ - XEvent ev; - int len; - int motion; - int buttons; - int refresh_needed; - - g_num_check_input_calls--; - if(g_num_check_input_calls < 0) { - len = XPending(g_display); - g_num_check_input_calls = g_check_input_flush_rate; - } else { - len = QLength(g_display); - } - - motion = 0; - refresh_needed = 0; - while(len > 0) { - XNextEvent(g_display, &ev); - len--; - if(len == 0) { - /* Xaccel on linux only buffers one X event */ - /* must look for more now */ - len = XPending(g_display); - } - switch(ev.type) { - case FocusIn: - case FocusOut: - if(ev.xfocus.type == FocusOut) { - /* Allow keyrepeat again! */ - vid_printf("Left window, auto repeat on\n"); - x_auto_repeat_on(0); - g_has_focus = 0; - } else if(ev.xfocus.type == FocusIn) { - /* Allow keyrepeat again! */ - vid_printf("Enter window, auto repeat off\n"); - x_auto_repeat_off(0); - g_has_focus = 1; - } - break; - case EnterNotify: - case LeaveNotify: - /* These events are disabled now */ - printf("Enter/Leave event for winow %08x, sub: %08x\n", - (word32)ev.xcrossing.window, - (word32)ev.xcrossing.subwindow); - printf("Enter/L mode: %08x, detail: %08x, type:%02x\n", - ev.xcrossing.mode, ev.xcrossing.detail, - ev.xcrossing.type); - break; - case ButtonPress: - vid_printf("Got button press of button %d!\n", - ev.xbutton.button); - buttons = (1 << ev.xbutton.button) >> 1; - motion |= x_update_mouse(ev.xbutton.x, ev.xbutton.y, - buttons, buttons & 7); - - break; - case ButtonRelease: - buttons = (1 << ev.xbutton.button) >> 1; - motion |= x_update_mouse(ev.xbutton.x, ev.xbutton.y, 0, - buttons & 7); - break; - case MotionNotify: - if(ev.xmotion.window != g_a2_win) { - printf("Motion in window %08x unknown!\n", - (word32)ev.xmotion.window); - } - motion |= x_update_mouse(ev.xmotion.x, ev.xmotion.y, 0, - 0); - break; - case Expose: - refresh_needed = -1; - break; - case NoExpose: - /* do nothing */ - break; - case KeyPress: - case KeyRelease: - handle_keysym(&ev); - break; - case KeymapNotify: - break; - case ColormapNotify: - vid_printf("ColormapNotify for %08x\n", - (word32)(ev.xcolormap.window)); - vid_printf("colormap: %08x, new: %d, state: %d\n", - (word32)ev.xcolormap.colormap, - ev.xcolormap.new, ev.xcolormap.state); - break; - case ClientMessage: - if (ev.xclient.data.l[0] == (long)WM_DELETE_WINDOW) - { - iwm_shut(); - my_exit(1); - } - break; - default: - printf("X event 0x%08x is unknown!\n", - ev.type); - break; - } - } - - if(motion && g_warp_pointer) { - XWarpPointer(g_display, None, g_a2_win, 0, 0, 0, 0, - BASE_MARGIN_LEFT + (A2_WINDOW_WIDTH/2), - BASE_MARGIN_TOP + (A2_WINDOW_HEIGHT/2)); - } - - if(refresh_needed) { - printf("Full refresh needed\n"); - g_a2_screen_buffer_changed = -1; - g_full_refresh_needed = -1; - - g_border_sides_refresh_needed = 1; - g_border_special_refresh_needed = 1; - g_status_refresh_needed = 1; - - /* x_refresh_ximage(); */ - /* redraw_border(); */ - } - -} - -void -x_hide_pointer(int do_hide) -{ - if(do_hide) { - XDefineCursor(g_display, g_a2_win, g_cursor); - } else { - XDefineCursor(g_display, g_a2_win, None); - } -} - - -void -handle_keysym(XEvent *xev_in) -{ - KeySym keysym; - word32 state; - int keycode; - int a2code; - int type; - int is_up; - - keycode = xev_in->xkey.keycode; - type = xev_in->xkey.type; - - keysym = XLookupKeysym(&(xev_in->xkey), 0); - - state = xev_in->xkey.state; - - vid_printf("keycode: %d, type: %d, state:%d, sym: %08x\n", - keycode, type, state, (word32)keysym); - - x_update_modifier_state(state); - - is_up = 0; - if(type == KeyRelease) { - is_up = 1; - } - -#if 0 - if(keysym == XK_Alt_L || keysym == XK_Meta_L) { - g_alt_left_up = is_up; - } - - if(keysym == XK_Alt_R || keysym == XK_Meta_R) { - g_alt_right_up = is_up; - } - - if(g_alt_left_up == 0 && g_alt_right_up == 0) { - printf("Sending sound to file\n"); - g_send_sound_to_file = 1; - } else { - if(g_send_sound_to_file) { - printf("Stopping sending sound to file\n"); - close_sound_file(); - } - g_send_sound_to_file = 0; - } -#endif - - /* first, do conversions */ - switch(keysym) { - case XK_Alt_R: - case XK_Meta_R: - case XK_Super_R: - case XK_Mode_switch: - case XK_Cancel: - keysym = XK_Print; /* option */ - break; - case XK_Alt_L: - case XK_Meta_L: - case XK_Super_L: - case XK_Menu: - keysym = XK_Scroll_Lock; /* cmd */ - break; - case 0x1000003: - if(keycode == 0x3c) { - /* enter key on Mac OS X laptop--make it option */ - keysym = XK_Print; - } - break; - case NoSymbol: - switch(keycode) { - /* 94-95 are for my PC101 kbd + windows keys on HPUX */ - case 0x0095: - /* left windows key = option */ - keysym = XK_Print; - break; - case 0x0096: - case 0x0094: - /* right windows key = cmd */ - keysym = XK_Scroll_Lock; - break; - /* 0072 is for cra@WPI.EDU who says it's Break under XFree86 */ - case 0x0072: - /* 006e is break according to mic@research.nj.nec.com */ - case 0x006e: - keysym = XK_Break; - break; - - /* 0x0042, 0x0046, and 0x0048 are the windows keys according */ - /* to Geoff Weiss on Solaris x86 */ - case 0x0042: - case 0x0046: - /* flying windows == open apple */ - keysym = XK_Scroll_Lock; - break; - case 0x0048: - case 0x0076: /* Windows menu key on Mac OS X */ - /* menu windows == option */ - keysym = XK_Print; - break; - } - } - - a2code = x_keysym_to_a2code(keysym, is_up); - if(a2code >= 0) { - adb_physical_key_update(a2code, is_up); - } else if(a2code != -2) { - printf("Keysym: %04x of keycode: %02x unknown\n", - (word32)keysym, keycode); - } -} - -int -x_keysym_to_a2code(int keysym, int is_up) -{ - int i; - - if(keysym == 0) { - return -1; - } - - if((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) { - if(is_up) { - g_x_shift_control_state &= ~ShiftMask; - } else { - g_x_shift_control_state |= ShiftMask; - } - } - if(keysym == XK_Caps_Lock) { - if(is_up) { - g_x_shift_control_state &= ~LockMask; - } else { - g_x_shift_control_state |= LockMask; - } - } - if((keysym == XK_Control_L) || (keysym == XK_Control_R)) { - if(is_up) { - g_x_shift_control_state &= ~ControlMask; - } else { - g_x_shift_control_state |= ControlMask; - } - } - - /* Look up Apple 2 keycode */ - for(i = g_num_a2_keycodes - 1; i >= 0; i--) { - if((keysym == a2_key_to_xsym[i][1]) || - (keysym == a2_key_to_xsym[i][2])) { - - vid_printf("Found keysym:%04x = a[%d] = %04x or %04x\n", - (int)keysym, i, a2_key_to_xsym[i][1], - a2_key_to_xsym[i][2]); - - return a2_key_to_xsym[i][0]; - } - } - - return -1; -} - -void -x_update_modifier_state(int state) -{ - int state_xor; - int is_up; - - state = state & (ControlMask | LockMask | ShiftMask); - state_xor = g_x_shift_control_state ^ state; - is_up = 0; - if(state_xor & ControlMask) { - is_up = ((state & ControlMask) == 0); - adb_physical_key_update(0x36, is_up); - } - if(state_xor & LockMask) { - is_up = ((state & LockMask) == 0); - adb_physical_key_update(0x39, is_up); - } - if(state_xor & ShiftMask) { - is_up = ((state & ShiftMask) == 0); - adb_physical_key_update(0x38, is_up); - } - - g_x_shift_control_state = state; -} - -void -x_auto_repeat_on(int must) -{ - if((g_auto_repeat_on <= 0) || must) { - g_auto_repeat_on = 1; - XAutoRepeatOn(g_display); - XFlush(g_display); - adb_kbd_repeat_off(); - } -} - -void -x_auto_repeat_off(int must) -{ - if((g_auto_repeat_on != 0) || must) { - XAutoRepeatOff(g_display); - XFlush(g_display); - g_auto_repeat_on = 0; - adb_kbd_repeat_off(); - } -} - -void -x_full_screen(int do_full) -{ - return; -} - -// OG Adding release -void x_release_kimage(Kimage* kimage_ptr) -{ - if (kimage_ptr->dev_handle == (void*)-1) - { - free(kimage_ptr->data_ptr); - kimage_ptr->data_ptr = NULL; - } -} - -// OG Addding ratio -int x_calc_ratio(float x,float y) -{ - return 1; -} - -void -clipboard_paste(void) -{ - // TODO: Add clipboard support -} - -int -clipboard_get_char(void) -{ - // TODO: Add clipboard support - return 0; -} +/* + GSPLUS - Advanced Apple IIGS Emulator Environment + Copyright (C) 2016 - Dagen Brock + + Copyright (C) 2010 - 2012 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +# if !defined(__CYGWIN__) && !defined(__POWERPC__) +/* No shared memory on Cygwin */ +# define X_SHARED_MEM +#endif /* CYGWIN */ + +#include +#include +#include +#include +#include +#include + +#ifdef X_SHARED_MEM +# include +# include +# include +#endif + +int XShmQueryExtension(Display *display); + +#include "defc.h" +#include "protos_xdriver.h" + +#define FONT_NAME_STATUS "8x13" + +extern int Verbose; + +extern int g_warp_pointer; +extern int g_screen_depth; +extern int g_force_depth; +int g_screen_mdepth = 0; + +extern int _Xdebug; + +extern int g_send_sound_to_file; + +extern int g_quit_sim_now; + +int g_has_focus = 0; +int g_auto_repeat_on = -1; +int g_x_shift_control_state = 0; + + +Display *g_display = 0; +Visual *g_vis = 0; +Window g_a2_win; +GC g_a2_winGC; +Atom WM_DELETE_WINDOW; +XFontStruct *g_text_FontSt; +Colormap g_a2_colormap = 0; +Colormap g_default_colormap = 0; +int g_needs_cmap = 0; +int g_win_status_debug = 0; // Current visibility of status lines. +int g_win_status_debug_request = 0; // Desired visibility of status lines. + +extern word32 g_red_mask; +extern word32 g_green_mask; +extern word32 g_blue_mask; +extern int g_red_left_shift; +extern int g_green_left_shift; +extern int g_blue_left_shift; +extern int g_red_right_shift; +extern int g_green_right_shift; +extern int g_blue_right_shift; + +#ifdef X_SHARED_MEM +int g_use_shmem = 1; +#else +int g_use_shmem = 0; +#endif + +extern Kimage g_mainwin_kimage; + +extern int Max_color_size; + +XColor g_xcolor_a2vid_array[256]; + +extern word32 g_palette_8to1624[256]; +extern word32 g_a2palette_8to1624[256]; + +int g_alt_left_up = 1; +int g_alt_right_up = 1; + +extern word32 g_full_refresh_needed; + +extern int g_border_sides_refresh_needed; +extern int g_border_special_refresh_needed; +extern int g_status_refresh_needed; + +extern int g_lores_colors[]; +extern int g_cur_a2_stat; + +extern int g_a2vid_palette; + +extern int g_installed_full_superhires_colormap; + +extern int g_screen_redraw_skip_amt; + +extern word32 g_a2_screen_buffer_changed; + +extern char *g_status_ptrs[MAX_STATUS_LINES]; + +Cursor g_cursor; +Pixmap g_cursor_shape; +Pixmap g_cursor_mask; + +XColor g_xcolor_black = { 0, 0x0000, 0x0000, 0x0000, DoRed|DoGreen|DoBlue, 0 }; +XColor g_xcolor_white = { 0, 0xffff, 0xffff, 0xffff, DoRed|DoGreen|DoBlue, 0 }; + +int g_depth_attempt_list[] = { 16, 24, 15, 8 }; + + +#define X_EVENT_LIST_ALL_WIN \ + (ExposureMask | ButtonPressMask | ButtonReleaseMask | \ + OwnerGrabButtonMask | KeyPressMask | KeyReleaseMask | \ + KeymapStateMask | ColormapChangeMask | FocusChangeMask) + +#define X_BASE_WIN_EVENT_LIST \ + (X_EVENT_LIST_ALL_WIN | PointerMotionMask | ButtonMotionMask) + +#define X_A2_WIN_EVENT_LIST \ + (X_BASE_WIN_EVENT_LIST) + +int g_num_a2_keycodes = 0; + +int a2_key_to_xsym[][3] = { + { 0x35, XK_Escape, 0 }, + { 0x7a, XK_F1, 0 }, + { 0x78, XK_F2, 0 }, + { 0x63, XK_F3, 0 }, + { 0x76, XK_F4, 0 }, + { 0x60, XK_F5, 0 }, + { 0x61, XK_F6, 0 }, + { 0x62, XK_F7, 0 }, + { 0x64, XK_F8, 0 }, + { 0x65, XK_F9, 0 }, + { 0x6d, XK_F10, 0 }, + { 0x67, XK_F11, 0 }, + { 0x6f, XK_F12, 0 }, + { 0x69, XK_F13, 0 }, + { 0x6b, XK_F14, 0 }, + { 0x71, XK_F15, 0 }, + { 0x7f, XK_Pause, XK_Break }, + { 0x32, '`', '~' }, /* Key number 18? */ + { 0x12, '1', '!' }, + { 0x13, '2', '@' }, + { 0x14, '3', '#' }, + { 0x15, '4', '$' }, + { 0x17, '5', '%' }, + { 0x16, '6', '^' }, + { 0x1a, '7', '&' }, + { 0x1c, '8', '*' }, + { 0x19, '9', '(' }, + { 0x1d, '0', ')' }, + { 0x1b, '-', '_' }, + { 0x18, '=', '+' }, + { 0x33, XK_BackSpace, 0 }, + { 0x72, XK_Insert, XK_Help }, /* Help? */ +/* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ + { 0x74, XK_Page_Up, 0 }, + { 0x47, XK_Num_Lock, XK_Clear }, /* Clear */ + { 0x51, XK_KP_Equal, XK_Home }, /* Note XK_Home alias! */ + { 0x4b, XK_KP_Divide, 0 }, + { 0x43, XK_KP_Multiply, 0 }, + + { 0x30, XK_Tab, 0 }, + { 0x0c, 'q', 'Q' }, + { 0x0d, 'w', 'W' }, + { 0x0e, 'e', 'E' }, + { 0x0f, 'r', 'R' }, + { 0x11, 't', 'T' }, + { 0x10, 'y', 'Y' }, + { 0x20, 'u', 'U' }, + { 0x22, 'i', 'I' }, + { 0x1f, 'o', 'O' }, + { 0x23, 'p', 'P' }, + { 0x21, '[', '{' }, + { 0x1e, ']', '}' }, + { 0x2a, 0x5c, '|' }, /* backslash, bar */ + { 0x75, XK_Delete, 0 }, + { 0x77, XK_End, 0 }, + { 0x79, XK_Page_Down, 0 }, + { 0x59, XK_KP_7, XK_KP_Home }, + { 0x5b, XK_KP_8, XK_KP_Up }, + { 0x5c, XK_KP_9, XK_KP_Page_Up }, + { 0x4e, XK_KP_Subtract, 0 }, + + { 0x39, XK_Caps_Lock, 0 }, + { 0x00, 'a', 'A' }, + { 0x01, 's', 'S' }, + { 0x02, 'd', 'D' }, + { 0x03, 'f', 'F' }, + { 0x05, 'g', 'G' }, + { 0x04, 'h', 'H' }, + { 0x26, 'j', 'J' }, + { 0x28, 'k', 'K' }, + { 0x25, 'l', 'L' }, + { 0x29, ';', ':' }, + { 0x27, 0x27, '"' }, /* single quote */ + { 0x24, XK_Return, 0 }, + { 0x56, XK_KP_4, XK_KP_Left }, + { 0x57, XK_KP_5, 0 }, + { 0x58, XK_KP_6, XK_KP_Right }, + { 0x45, XK_KP_Add, 0 }, + + { 0x38, XK_Shift_L, XK_Shift_R }, + { 0x06, 'z', 'Z' }, + { 0x07, 'x', 'X' }, + { 0x08, 'c', 'C' }, + { 0x09, 'v', 'V' }, + { 0x0b, 'b', 'B' }, + { 0x2d, 'n', 'N' }, + { 0x2e, 'm', 'M' }, + { 0x2b, ',', '<' }, + { 0x2f, '.', '>' }, + { 0x2c, '/', '?' }, + { 0x3e, XK_Up, 0 }, + { 0x53, XK_KP_1, XK_KP_End }, + { 0x54, XK_KP_2, XK_KP_Down }, + { 0x55, XK_KP_3, XK_KP_Page_Down }, + + { 0x36, XK_Control_L, XK_Control_R }, + { 0x3a, XK_Print, XK_Sys_Req }, /* Option */ + { 0x37, XK_Scroll_Lock, 0 }, /* Command */ + { 0x31, ' ', 0 }, + { 0x3b, XK_Left, 0 }, + { 0x3d, XK_Down, 0 }, + { 0x3c, XK_Right, 0 }, + { 0x52, XK_KP_0, XK_KP_Insert }, + { 0x41, XK_KP_Decimal, XK_KP_Separator }, + { 0x4c, XK_KP_Enter, 0 }, + { -1, -1, -1 } +}; + +int +main(int argc, char **argv) +{ + return gsportmain(argc, argv); +} + +void +x_dialog_create_gsport_conf(const char *str) +{ + // Just write the config file already... + config_write_config_gsport_file(); +} + +int +x_show_alert(int is_fatal, const char *str) +{ + /* Not implemented yet */ + adb_all_keys_up(); + + clear_fatal_logs(); + return 0; +} + + +#define MAKE_2(val) ( (val << 8) + val) + +void +x_update_color(int col_num, int red, int green, int blue, word32 rgb) +{ + XColor *xcol; + + xcol = &(g_xcolor_a2vid_array[col_num]); + xcol->red = MAKE_2(red); + xcol->green = MAKE_2(green); + xcol->blue = MAKE_2(blue); + xcol->flags = DoRed | DoGreen | DoBlue; +} + +void +x_update_physical_colormap() +{ + if(g_needs_cmap) { + XStoreColors(g_display, g_a2_colormap, + &g_xcolor_a2vid_array[0], Max_color_size); + } +} + +void +show_xcolor_array() +{ + int i; + + for(i = 0; i < 256; i++) { + printf("%02x: %08x\n", i, g_palette_8to1624[i]); + +#if 0 + printf("%02x: %04x %04x %04x, %02x %x\n", + i, xcolor_array[i].red, xcolor_array[i].green, + xcolor_array[i].blue, (word32)xcolor_array[i].pixel, + xcolor_array[i].flags); +#endif + } +} + + +int +my_error_handler(Display *display, XErrorEvent *ev) +{ + char msg[1024]; + XGetErrorText(display, ev->error_code, msg, 1000); + printf("X Error code %s\n", msg); + fflush(stdout); + + return 0; +} + +void +xdriver_end() +{ + + printf("xdriver_end\n"); + if(g_display) { + x_auto_repeat_on(1); + XFlush(g_display); + } +} + +void +show_colormap(char *str, Colormap cmap, int index1, int index2, int index3) +{ + XColor xcol; + int i; + int pix; + + printf("Show colormap: %08x = %s, cmap cells: %d,%d,%d\n", + (int)cmap, str, index1, index2, index3); + for(i = 0; i < index1 + index2 + index3; i++) { + pix = i; + if(i >= index1) { + pix = (i-index1)*index1; + if(i >= (index1 + index2)) { + pix = (i - index1 - index2)*index2*index1; + } + } + if(i == 0 && index1 < 250) { + pix = 0x842; + } + xcol.pixel = pix; + XQueryColor(g_display, cmap, &xcol); + printf("Cell %03x: pix: %03x, R:%04x, G:%04x, B:%04x\n", + i, (int)xcol.pixel, xcol.red, xcol.green, xcol.blue); + } +} + +void +x_badpipe(int signum) +{ + /* restore normal sigpipe handling */ + signal(SIGPIPE, SIG_DFL); + + /* attempt to xset r */ + system("xset r"); + my_exit(5); +} + +void +dev_video_init() +{ + int tmp_array[0x80]; + XGCValues new_gc; + XSetWindowAttributes win_attr; + XSizeHints my_winSizeHints; + XClassHint my_winClassHint; + XTextProperty my_winText; + XVisualInfo *visualList; + char **font_ptr; + char cursor_data; + word32 create_win_list; + int depth; + int len; + int cmap_alloc_amt; + int cnt; + int font_height; + int base_height; + int screen_num; + char *myTextString[1]; + word32 lores_col; + int ret; + int i; + int keycode; + + printf("Preparing X Windows graphics system\n"); + ret = 0; + + signal(SIGPIPE, x_badpipe); + + g_num_a2_keycodes = 0; + for(i = 0; i <= 0x7f; i++) { + tmp_array[i] = 0; + } + for(i = 0; i < 0x7f; i++) { + keycode = a2_key_to_xsym[i][0]; + if(keycode < 0) { + g_num_a2_keycodes = i; + break; + } else if(keycode > 0x7f) { + printf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); + exit(2); + } else { + if(tmp_array[keycode]) { + printf("a2_key_to_x[%d] = %02x used by %d\n", + i, keycode, tmp_array[keycode] - 1); + } + tmp_array[keycode] = i + 1; + } + } + +#if 0 + printf("Setting _Xdebug = 1, makes X synchronous\n"); + _Xdebug = 1; +#endif + + g_display = XOpenDisplay(NULL); + if(g_display == NULL) { + fprintf(stderr, "Can't open display\n"); + exit(1); + } + + vid_printf("Just opened display = %p\n", g_display); + fflush(stdout); + + screen_num = DefaultScreen(g_display); + + len = sizeof(g_depth_attempt_list)/sizeof(int); + if(g_force_depth > 0) { + /* Only use the requested user depth */ + len = 1; + g_depth_attempt_list[0] = g_force_depth; + } + g_vis = 0; + for(i = 0; i < len; i++) { + depth = g_depth_attempt_list[i]; + + g_vis = x_try_find_visual(depth, screen_num, + &visualList); + if(g_vis != 0) { + break; + } + } + if(g_vis == 0) { + fprintf(stderr, "Couldn't find any visuals at any depth!\n"); + exit(2); + } + + g_default_colormap = XDefaultColormap(g_display, screen_num); + if(!g_default_colormap) { + printf("g_default_colormap == 0!\n"); + exit(4); + } + + g_a2_colormap = -1; + cmap_alloc_amt = AllocNone; + if(g_needs_cmap) { + cmap_alloc_amt = AllocAll; + } + g_a2_colormap = XCreateColormap(g_display, + RootWindow(g_display,screen_num), g_vis, + cmap_alloc_amt); + + vid_printf("g_a2_colormap: %08x, main: %08x\n", + (word32)g_a2_colormap, (word32)g_default_colormap); + + if(g_needs_cmap && g_a2_colormap == g_default_colormap) { + printf("A2_colormap = default colormap!\n"); + exit(4); + } + + /* and define cursor */ + cursor_data = 0; + g_cursor_shape = XCreatePixmapFromBitmapData(g_display, + RootWindow(g_display,screen_num), &cursor_data, 1, 1, 1, 0, 1); + g_cursor_mask = XCreatePixmapFromBitmapData(g_display, + RootWindow(g_display,screen_num), &cursor_data, 1, 1, 1, 0, 1); + + g_cursor = XCreatePixmapCursor(g_display, g_cursor_shape, + g_cursor_mask, &g_xcolor_black, &g_xcolor_white, 0, 0); + + XFreePixmap(g_display, g_cursor_shape); + XFreePixmap(g_display, g_cursor_mask); + + XFlush(g_display); + + win_attr.event_mask = X_A2_WIN_EVENT_LIST; + win_attr.colormap = g_a2_colormap; + win_attr.backing_store = WhenMapped; + win_attr.border_pixel = 1; + win_attr.background_pixel = 0; + if(g_warp_pointer) { + win_attr.cursor = g_cursor; + } else { + win_attr.cursor = None; + } + + vid_printf("About to a2_win, depth: %d\n", g_screen_depth); + fflush(stdout); + + create_win_list = CWEventMask | CWBackingStore | CWCursor; + create_win_list |= CWColormap | CWBorderPixel | CWBackPixel; + + base_height = X_A2_WINDOW_HEIGHT; + if (g_win_status_debug) + base_height += MAX_STATUS_LINES * 13; + + g_a2_win = XCreateWindow(g_display, RootWindow(g_display, screen_num), + 0, 0, BASE_WINDOW_WIDTH, base_height, + 0, g_screen_depth, InputOutput, g_vis, + create_win_list, &win_attr); + + XSetWindowColormap(g_display, g_a2_win, g_a2_colormap); + + XFlush(g_display); + +/* Check for XShm */ +#ifdef X_SHARED_MEM + if(g_use_shmem) { + ret = XShmQueryExtension(g_display); + if(ret == 0) { + printf("XShmQueryExt ret: %d\n", ret); + printf("not using shared memory\n"); + g_use_shmem = 0; + } else { + printf("Will use shared memory for X\n"); + } + } +#endif + + video_get_kimages(); + if(g_screen_depth != 8) { + video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, + g_screen_mdepth); + } + + if(!g_use_shmem) { + if(g_screen_redraw_skip_amt < 0) { + g_screen_redraw_skip_amt = 3; + } + printf("Not using shared memory, setting skip_amt = %d\n", + g_screen_redraw_skip_amt); + } + + /* Done with visualList now */ + XFree(visualList); + + for(i = 0; i < 256; i++) { + g_xcolor_a2vid_array[i].pixel = i; + lores_col = g_lores_colors[i & 0xf]; + video_update_color_raw(i, lores_col); + g_a2palette_8to1624[i] = g_palette_8to1624[i]; + } + + x_update_physical_colormap(); + + g_installed_full_superhires_colormap = !g_needs_cmap; + + myTextString[0] = "GSport"; + + XStringListToTextProperty(myTextString, 1, &my_winText); + + my_winSizeHints.flags = PSize | PMinSize | PMaxSize; + my_winSizeHints.width = BASE_WINDOW_WIDTH; + my_winSizeHints.height = base_height; + my_winSizeHints.min_width = BASE_WINDOW_WIDTH; + my_winSizeHints.min_height = base_height; + my_winSizeHints.max_width = BASE_WINDOW_WIDTH; + my_winSizeHints.max_height = base_height; + my_winClassHint.res_name = "GSport"; + my_winClassHint.res_class = "GSport"; + + XSetWMProperties(g_display, g_a2_win, &my_winText, &my_winText, 0, + 0, &my_winSizeHints, 0, &my_winClassHint); + + WM_DELETE_WINDOW = XInternAtom(g_display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(g_display, g_a2_win, &WM_DELETE_WINDOW, 1); + XMapRaised(g_display, g_a2_win); + + XSync(g_display, False); + + g_a2_winGC = XCreateGC(g_display, g_a2_win, 0, (XGCValues *) 0); + font_ptr = XListFonts(g_display, FONT_NAME_STATUS, 4, &cnt); + + vid_printf("act_cnt of fonts: %d\n", cnt); + for(i = 0; i < cnt; i++) { + vid_printf("Font %d: %s\n", i, font_ptr[i]); + } + fflush(stdout); + g_text_FontSt = XLoadQueryFont(g_display, FONT_NAME_STATUS); + vid_printf("font # returned: %08x\n", (word32)(g_text_FontSt->fid)); + font_height = g_text_FontSt->ascent + g_text_FontSt->descent; + vid_printf("font_height: %d\n", font_height); + + vid_printf("widest width: %d\n", g_text_FontSt->max_bounds.width); + + new_gc.font = g_text_FontSt->fid; + new_gc.fill_style = FillSolid; + XChangeGC(g_display, g_a2_winGC, GCFillStyle | GCFont, &new_gc); + + /* XSync(g_display, False); */ +#if 0 +/* MkLinux for Powermac depth 15 has bugs--this was to try to debug them */ + if(g_screen_depth == 15) { + /* draw phony screen */ + ptr16 = (word16 *)dint_main_win; + for(i = 0; i < 320*400; i++) { + ptr16[i] = 0; + } + for(i = 0; i < 400; i++) { + for(j = 0; j < 640; j++) { + sh = (j / 20) & 0x1f; + val = sh; + val = val; + *ptr16++ = val; + } + } + XPutImage(g_display, g_a2_win, g_a2_winGC, xint_main_win, + 0, 0, + BASE_MARGIN_LEFT, BASE_MARGIN_TOP, + 640, 400); + XFlush(g_display); + } +#endif + + + XFlush(g_display); + fflush(stdout); +} + +Visual * +x_try_find_visual(int depth, int screen_num, XVisualInfo **visual_list_ptr) +{ + XVisualInfo *visualList; + XVisualInfo *v_chosen; + XVisualInfo vTemplate; + int visualsMatched; + int mdepth; + int needs_cmap; + int visual_chosen; + int match8, match24; + int i; + + vTemplate.screen = screen_num; + vTemplate.depth = depth; + + visualList = XGetVisualInfo(g_display, + (VisualScreenMask | VisualDepthMask), + &vTemplate, &visualsMatched); + + vid_printf("visuals matched: %d\n", visualsMatched); + if(visualsMatched == 0) { + return (Visual *)0; + } + + visual_chosen = -1; + needs_cmap = 0; + for(i = 0; i < visualsMatched; i++) { + printf("Visual %d\n", i); + printf(" id: %08x, screen: %d, depth: %d, class: %d\n", + (word32)visualList[i].visualid, + visualList[i].screen, + visualList[i].depth, + visualList[i].class); + printf(" red: %08lx, green: %08lx, blue: %08lx\n", + visualList[i].red_mask, + visualList[i].green_mask, + visualList[i].blue_mask); + printf(" cmap size: %d, bits_per_rgb: %d\n", + visualList[i].colormap_size, + visualList[i].bits_per_rgb); + match8 = (visualList[i].class == PseudoColor); + match24 = (visualList[i].class == TrueColor); + if((depth == 8) && match8) { + visual_chosen = i; + Max_color_size = visualList[i].colormap_size; + needs_cmap = 1; + break; + } + if((depth != 8) && match24) { + visual_chosen = i; + Max_color_size = -1; + needs_cmap = 0; + break; + } + } + + if(visual_chosen < 0) { + printf("Couldn't find any good visuals at depth %d!\n", + depth); + return (Visual *)0; + } + + printf("Chose visual: %d, max_colors: %d\n", visual_chosen, + Max_color_size); + + v_chosen = &(visualList[visual_chosen]); + x_set_mask_and_shift(v_chosen->red_mask, &g_red_mask, + &g_red_left_shift, &g_red_right_shift); + x_set_mask_and_shift(v_chosen->green_mask, &g_green_mask, + &g_green_left_shift, &g_green_right_shift); + x_set_mask_and_shift(v_chosen->blue_mask, &g_blue_mask, + &g_blue_left_shift, &g_blue_right_shift); + + g_screen_depth = depth; + mdepth = depth; + if(depth > 8) { + mdepth = 16; + } + if(depth > 16) { + mdepth = 32; + } + g_screen_mdepth = mdepth; + g_needs_cmap = needs_cmap; + *visual_list_ptr = visualList; + + return v_chosen->visual; +} + +void +x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, + int *shift_right_ptr) +{ + int shift; + int i; + + /* Shift until we find first set bit in mask, then remember mask,shift*/ + + shift = 0; + for(i = 0; i < 32; i++) { + if(x_mask & 1) { + /* we're done! */ + break; + } + x_mask = x_mask >> 1; + shift++; + } + *mask_ptr = x_mask; + *shift_left_ptr = shift; + /* Now, calculate shift_right_ptr */ + shift = 0; + x_mask |= 1; // make sure at least one bit is set + while(x_mask < 0x80) { + shift++; + x_mask = x_mask << 1; + } + + *shift_right_ptr = shift; + return; + +} + +int g_xshm_error = 0; + +int +xhandle_shm_error(Display *display, XErrorEvent *event) +{ + g_xshm_error = 1; + return 0; +} + +void +x_get_kimage(Kimage *kimage_ptr) { + if(g_use_shmem) { + g_use_shmem = get_shm(kimage_ptr); + } + if(!g_use_shmem) { + get_ximage(kimage_ptr); + } +} + +int +get_shm(Kimage *kimage_ptr) +{ +#ifdef X_SHARED_MEM + XShmSegmentInfo *seginfo; + XImage *xim; + int (*old_x_handler)(Display *, XErrorEvent *); + int width; + int height; + int depth; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + + seginfo = (XShmSegmentInfo *)malloc(sizeof(XShmSegmentInfo)); + xim = XShmCreateImage(g_display, g_vis, depth, ZPixmap, + (char *)0, seginfo, width, height); + + /* check mdepth! */ + if(xim->bits_per_pixel != kimage_ptr->mdepth) { + printf("get_shm bits_per_pix: %d != %d\n", + xim->bits_per_pixel, g_screen_mdepth); + } + + vid_printf("xim: %p\n", xim); + kimage_ptr->dev_handle = xim; + kimage_ptr->dev_handle2 = seginfo; + if(xim == 0) { + return 0; + } + + /* It worked, we got it */ + seginfo->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, + IPC_CREAT | 0777); + vid_printf("seginfo->shmid = %d\n", seginfo->shmid); + if(seginfo->shmid < 0) { + XDestroyImage(xim); + return 0; + } + + /* Still working */ + seginfo->shmaddr = (char *)shmat(seginfo->shmid, 0, 0); + vid_printf("seginfo->shmaddr: %p\n", seginfo->shmaddr); + if(seginfo->shmaddr == ((char *) -1)) { + XDestroyImage(xim); + return 0; + } + + /* Still working */ + xim->data = seginfo->shmaddr; + seginfo->readOnly = False; + + /* XShmAttach will trigger X error if server is remote, so catch it */ + g_xshm_error = 0; + old_x_handler = XSetErrorHandler(xhandle_shm_error); + + XShmAttach(g_display, seginfo); + XSync(g_display, False); + + + vid_printf("about to RMID the shmid\n"); + shmctl(seginfo->shmid, IPC_RMID, 0); + + XFlush(g_display); + XSetErrorHandler(old_x_handler); + + if(g_xshm_error) { + XDestroyImage(xim); + /* We could release the shared mem segment, but by doing the */ + /* RMID, it will go away when we die now, so just leave it */ + printf("Not using shared memory\n"); + return 0; + } + + kimage_ptr->data_ptr = (byte *)xim->data; + vid_printf("Sharing memory. xim: %p, xim->data: %p\n", xim, xim->data); + + return 1; +#else + return 0; /* No shared memory */ +#endif /* X_SHARED_MEM */ +} + +void +get_ximage(Kimage *kimage_ptr) +{ + XImage *xim; + byte *ptr; + int width; + int height; + int depth; + int mdepth; + + width = kimage_ptr->width_req; + height = kimage_ptr->height; + depth = kimage_ptr->depth; + mdepth = kimage_ptr->mdepth; + + ptr = (byte *)malloc((width * height * mdepth) >> 3); + + vid_printf("ptr: %p\n", ptr); + + if(ptr == 0) { + printf("malloc for data failed, mdepth: %d\n", mdepth); + exit(2); + } + + kimage_ptr->data_ptr = ptr; + + xim = XCreateImage(g_display, g_vis, depth, ZPixmap, 0, + (char *)ptr, width, height, 8, 0); + +#if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command + xim->byte_order = LSBFirst; +#else + xim->byte_order = MSBFirst; +#endif + XInitImage(xim); /* adjust to new byte order */ + + /* check mdepth! */ + if(xim->bits_per_pixel != mdepth) { + printf("shm_ximage bits_per_pix: %d != %d\n", + xim->bits_per_pixel, mdepth); + } + + vid_printf("xim: %p\n", xim); + + kimage_ptr->dev_handle = xim; + + return; +} + + +void +x_toggle_status_lines() +{ + XSizeHints my_winSizeHints; + XClassHint my_winClassHint; + int base_height = X_A2_WINDOW_HEIGHT; + if ((g_win_status_debug = !g_win_status_debug)) + base_height += MAX_STATUS_LINES * 13; + //printf("Resize returns %d\n", XResizeWindow(g_display, g_a2_win, BASE_WINDOW_WIDTH, base_height)); + my_winSizeHints.flags = PSize | PMinSize | PMaxSize; + my_winSizeHints.width = BASE_WINDOW_WIDTH; + my_winSizeHints.height = base_height; + my_winSizeHints.min_width = BASE_WINDOW_WIDTH; + my_winSizeHints.min_height = base_height; + my_winSizeHints.max_width = BASE_WINDOW_WIDTH; + my_winSizeHints.max_height = base_height; + my_winClassHint.res_name = "GSport"; + my_winClassHint.res_class = "GSport"; + XSetWMProperties(g_display, g_a2_win, 0, 0, 0, + 0, &my_winSizeHints, 0, &my_winClassHint); + XMapRaised(g_display, g_a2_win); + XFlush(g_display); + x_redraw_status_lines(); +} + +void +x_redraw_status_lines() +{ + char *buf; + int line; + int height; + int margin; + word32 white, black; + + if (g_win_status_debug) + { + height = g_text_FontSt->ascent + g_text_FontSt->descent; + margin = g_text_FontSt->ascent; + + white = (g_a2vid_palette << 4) + 0xf; + black = (g_a2vid_palette << 4) + 0x0; + if(g_screen_depth != 8) { + white = (2 << (g_screen_depth - 1)) - 1; + black = 0; + } + XSetForeground(g_display, g_a2_winGC, white); + XSetBackground(g_display, g_a2_winGC, black); + + for(line = 0; line < MAX_STATUS_LINES; line++) { + buf = g_status_ptrs[line]; + if(buf == 0) { + /* skip it */ + continue; + } + XDrawImageString(g_display, g_a2_win, g_a2_winGC, 0, + X_A2_WINDOW_HEIGHT + height*line + margin, + buf, strlen(buf)); + } + + XFlush(g_display); + } +} + + +void +x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, + int width, int height) +{ + XImage *xim; + + xim = (XImage *)kimage_ptr->dev_handle; + +#ifdef X_SHARED_MEM + if(g_use_shmem) { + XShmPutImage(g_display, g_a2_win, g_a2_winGC, xim, + srcx, srcy, destx, desty, width, height, False); + } +#endif + if(!g_use_shmem) { + XPutImage(g_display, g_a2_win, g_a2_winGC, xim, + srcx, srcy, destx, desty, width, height); + } +} + +void +x_push_done() +{ + XFlush(g_display); +} + + +#define KEYBUFLEN 128 + +int g_num_check_input_calls = 0; +int g_check_input_flush_rate = 2; + +int +x_update_mouse(int raw_x, int raw_y, int button_states, int buttons_valid) +{ + int x, y; + + x = raw_x - BASE_MARGIN_LEFT; + y = raw_y - BASE_MARGIN_TOP; + + if(g_warp_pointer && (x == A2_WINDOW_WIDTH/2) && + (y == A2_WINDOW_HEIGHT/2) && (buttons_valid == 0) ) { + /* tell adb routs to recenter but ignore this motion */ + update_mouse(x, y, 0, -1); + return 0; + } + return update_mouse(x, y, button_states, buttons_valid & 7); +} + +void +check_input_events() +{ + XEvent ev; + int len; + int motion; + int buttons; + int refresh_needed; + + g_num_check_input_calls--; + if(g_num_check_input_calls < 0) { + len = XPending(g_display); + g_num_check_input_calls = g_check_input_flush_rate; + } else { + len = QLength(g_display); + } + + motion = 0; + refresh_needed = 0; + while(len > 0) { + XNextEvent(g_display, &ev); + len--; + if(len == 0) { + /* Xaccel on linux only buffers one X event */ + /* must look for more now */ + len = XPending(g_display); + } + switch(ev.type) { + case FocusIn: + case FocusOut: + if(ev.xfocus.type == FocusOut) { + /* Allow keyrepeat again! */ + vid_printf("Left window, auto repeat on\n"); + x_auto_repeat_on(0); + g_has_focus = 0; + } else if(ev.xfocus.type == FocusIn) { + /* Allow keyrepeat again! */ + vid_printf("Enter window, auto repeat off\n"); + x_auto_repeat_off(0); + g_has_focus = 1; + } + break; + case EnterNotify: + case LeaveNotify: + /* These events are disabled now */ + printf("Enter/Leave event for winow %08x, sub: %08x\n", + (word32)ev.xcrossing.window, + (word32)ev.xcrossing.subwindow); + printf("Enter/L mode: %08x, detail: %08x, type:%02x\n", + ev.xcrossing.mode, ev.xcrossing.detail, + ev.xcrossing.type); + break; + case ButtonPress: + vid_printf("Got button press of button %d!\n", + ev.xbutton.button); + buttons = (1 << ev.xbutton.button) >> 1; + motion |= x_update_mouse(ev.xbutton.x, ev.xbutton.y, + buttons, buttons & 7); + + break; + case ButtonRelease: + buttons = (1 << ev.xbutton.button) >> 1; + motion |= x_update_mouse(ev.xbutton.x, ev.xbutton.y, 0, + buttons & 7); + break; + case MotionNotify: + if(ev.xmotion.window != g_a2_win) { + printf("Motion in window %08x unknown!\n", + (word32)ev.xmotion.window); + } + motion |= x_update_mouse(ev.xmotion.x, ev.xmotion.y, 0, + 0); + break; + case Expose: + refresh_needed = -1; + break; + case NoExpose: + /* do nothing */ + break; + case KeyPress: + case KeyRelease: + handle_keysym(&ev); + break; + case KeymapNotify: + break; + case ColormapNotify: + vid_printf("ColormapNotify for %08x\n", + (word32)(ev.xcolormap.window)); + vid_printf("colormap: %08x, new: %d, state: %d\n", + (word32)ev.xcolormap.colormap, + ev.xcolormap.new, ev.xcolormap.state); + break; + case ClientMessage: + if (ev.xclient.data.l[0] == (long)WM_DELETE_WINDOW) + { + iwm_shut(); + my_exit(1); + } + break; + default: + printf("X event 0x%08x is unknown!\n", + ev.type); + break; + } + } + + if(motion && g_warp_pointer) { + XWarpPointer(g_display, None, g_a2_win, 0, 0, 0, 0, + BASE_MARGIN_LEFT + (A2_WINDOW_WIDTH/2), + BASE_MARGIN_TOP + (A2_WINDOW_HEIGHT/2)); + } + + if(refresh_needed) { + printf("Full refresh needed\n"); + g_a2_screen_buffer_changed = -1; + g_full_refresh_needed = -1; + + g_border_sides_refresh_needed = 1; + g_border_special_refresh_needed = 1; + g_status_refresh_needed = 1; + + /* x_refresh_ximage(); */ + /* redraw_border(); */ + } + +} + +void +x_hide_pointer(int do_hide) +{ + if(do_hide) { + XDefineCursor(g_display, g_a2_win, g_cursor); + } else { + XDefineCursor(g_display, g_a2_win, None); + } +} + + +void +handle_keysym(XEvent *xev_in) +{ + KeySym keysym; + word32 state; + int keycode; + int a2code; + int type; + int is_up; + + keycode = xev_in->xkey.keycode; + type = xev_in->xkey.type; + + keysym = XLookupKeysym(&(xev_in->xkey), 0); + + state = xev_in->xkey.state; + + vid_printf("keycode: %d, type: %d, state:%d, sym: %08x\n", + keycode, type, state, (word32)keysym); + + x_update_modifier_state(state); + + is_up = 0; + if(type == KeyRelease) { + is_up = 1; + } + +#if 0 + if(keysym == XK_Alt_L || keysym == XK_Meta_L) { + g_alt_left_up = is_up; + } + + if(keysym == XK_Alt_R || keysym == XK_Meta_R) { + g_alt_right_up = is_up; + } + + if(g_alt_left_up == 0 && g_alt_right_up == 0) { + printf("Sending sound to file\n"); + g_send_sound_to_file = 1; + } else { + if(g_send_sound_to_file) { + printf("Stopping sending sound to file\n"); + close_sound_file(); + } + g_send_sound_to_file = 0; + } +#endif + + /* first, do conversions */ + switch(keysym) { + case XK_Alt_R: + case XK_Meta_R: + case XK_Super_R: + case XK_Mode_switch: + case XK_Cancel: + keysym = XK_Print; /* option */ + break; + case XK_Alt_L: + case XK_Meta_L: + case XK_Super_L: + case XK_Menu: + keysym = XK_Scroll_Lock; /* cmd */ + break; + case 0x1000003: + if(keycode == 0x3c) { + /* enter key on Mac OS X laptop--make it option */ + keysym = XK_Print; + } + break; + case NoSymbol: + switch(keycode) { + /* 94-95 are for my PC101 kbd + windows keys on HPUX */ + case 0x0095: + /* left windows key = option */ + keysym = XK_Print; + break; + case 0x0096: + case 0x0094: + /* right windows key = cmd */ + keysym = XK_Scroll_Lock; + break; + /* 0072 is for cra@WPI.EDU who says it's Break under XFree86 */ + case 0x0072: + /* 006e is break according to mic@research.nj.nec.com */ + case 0x006e: + keysym = XK_Break; + break; + + /* 0x0042, 0x0046, and 0x0048 are the windows keys according */ + /* to Geoff Weiss on Solaris x86 */ + case 0x0042: + case 0x0046: + /* flying windows == open apple */ + keysym = XK_Scroll_Lock; + break; + case 0x0048: + case 0x0076: /* Windows menu key on Mac OS X */ + /* menu windows == option */ + keysym = XK_Print; + break; + } + } + + a2code = x_keysym_to_a2code(keysym, is_up); + if(a2code >= 0) { + adb_physical_key_update(a2code, is_up); + } else if(a2code != -2) { + printf("Keysym: %04x of keycode: %02x unknown\n", + (word32)keysym, keycode); + } +} + +int +x_keysym_to_a2code(int keysym, int is_up) +{ + int i; + + if(keysym == 0) { + return -1; + } + + if((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) { + if(is_up) { + g_x_shift_control_state &= ~ShiftMask; + } else { + g_x_shift_control_state |= ShiftMask; + } + } + if(keysym == XK_Caps_Lock) { + if(is_up) { + g_x_shift_control_state &= ~LockMask; + } else { + g_x_shift_control_state |= LockMask; + } + } + if((keysym == XK_Control_L) || (keysym == XK_Control_R)) { + if(is_up) { + g_x_shift_control_state &= ~ControlMask; + } else { + g_x_shift_control_state |= ControlMask; + } + } + + /* Look up Apple 2 keycode */ + for(i = g_num_a2_keycodes - 1; i >= 0; i--) { + if((keysym == a2_key_to_xsym[i][1]) || + (keysym == a2_key_to_xsym[i][2])) { + + vid_printf("Found keysym:%04x = a[%d] = %04x or %04x\n", + (int)keysym, i, a2_key_to_xsym[i][1], + a2_key_to_xsym[i][2]); + + return a2_key_to_xsym[i][0]; + } + } + + return -1; +} + +void +x_update_modifier_state(int state) +{ + int state_xor; + int is_up; + + state = state & (ControlMask | LockMask | ShiftMask); + state_xor = g_x_shift_control_state ^ state; + is_up = 0; + if(state_xor & ControlMask) { + is_up = ((state & ControlMask) == 0); + adb_physical_key_update(0x36, is_up); + } + if(state_xor & LockMask) { + is_up = ((state & LockMask) == 0); + adb_physical_key_update(0x39, is_up); + } + if(state_xor & ShiftMask) { + is_up = ((state & ShiftMask) == 0); + adb_physical_key_update(0x38, is_up); + } + + g_x_shift_control_state = state; +} + +void +x_auto_repeat_on(int must) +{ + if((g_auto_repeat_on <= 0) || must) { + g_auto_repeat_on = 1; + XAutoRepeatOn(g_display); + XFlush(g_display); + adb_kbd_repeat_off(); + } +} + +void +x_auto_repeat_off(int must) +{ + if((g_auto_repeat_on != 0) || must) { + XAutoRepeatOff(g_display); + XFlush(g_display); + g_auto_repeat_on = 0; + adb_kbd_repeat_off(); + } +} + +void +x_full_screen(int do_full) +{ + return; +} + +// OG Adding release +void x_release_kimage(Kimage* kimage_ptr) +{ + if (kimage_ptr->dev_handle == (void*)-1) + { + free(kimage_ptr->data_ptr); + kimage_ptr->data_ptr = NULL; + } +} + +// OG Addding ratio +int x_calc_ratio(float x,float y) +{ + return 1; +} + +void +clipboard_paste(void) +{ + // TODO: Add clipboard support +} + +int +clipboard_get_char(void) +{ + // TODO: Add clipboard support + return 0; +}