/*
            __
           / /_______________  ____  ___
          / __/ ___/ ___/ __ \/ __ \/ _ \
         / /_(__  ) /__/ /_/ / /_/ /  __/
         \__/____/\___/\____/ .___/\___/
                           /_/
    
    tscope-internal functions and variables

    By Michael Stevens

    See license.html for copyright information
*/

#include "../include/tscope.h"
#include "../include/tscope/internal.h"

// -----------------------------------------------------------------------
// internal variables 

// variables set by internal.c
int _tscope_flag = 0;

// variables set by screen.c 
int _debug_flag = DEBUG1;
int _ndebug = 5;
int _vdebug[] = { DEBUG0, DEBUG1, DEBUG2, DEBUG3, DEBUG4 };
char *_sdebug[] = { "DEBUG0", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4" };
int _screen_flag = 0;
int _dbuff_flag = 0;

int _refreshrate = 60;
int _screendepth = 16;
int _screensize = SIZE0;
int _nscreensize = 26;
int _vscreensize[] =
    { SIZE0, SIZE1, SIZE2, SIZE3, SIZE4, SIZE5, SIZE6, SIZE7, WSIZE3,
    WSIZE4, WSIZE5, WSIZE6, WSIZE7, QVGA, VGA, SVGA, XGA, XGAplus,
    SXGA, SXGAplus, UXGA, WXGA, WXGAplus, WSXGA, WSXGAplus, WUXGA
};
char *_sscreensize[] =
    { "SIZE0", "SIZE1", "SIZE2", "SIZE3", "SIZE4", "SIZE5", "SIZE6",
    "SIZE7", "WSIZE3", "WSIZE4", "WSIZE5", "WSIZE6", "WSIZE7", "QVGA",
    "VGA", "SVGA",
    "XGA", "XGAplus", "SXGA", "SXGAplus", "UXGA", "WXGA", "WXGAplus",
    "WSXGA",
    "WSXGAplus", "WUXGA"
};
int _screenmode = WINDOW;
int _nscreenmode = 3;
int _vscreenmode[] = { WINDOW, FULLSCREEN, FULLSCREEN_ACCEL };
char *_sscreenmode[] = { "WINDOW", "FULLSCREEN", "FULLSCREEN_ACCEL" };
int _dbuff = OFF;
int _screenx = 320;
int _screeny = 240;

int _actualdepth = 0;
int _actual_refreshrate = 0;
int _actualx = 0;
int _actualy = 0;

int _desktopx = 0;
int _desktopy = 0;
int _desktopdepth = 0;

map *_screenmap, *_dbuffmap, *_destmap;

// variables set by graphics.c 
int _graphics_flag = 0;
int _fgcolor = 0;
int _bgcolor = 0;
int _textbgcolor = -1;
int _fill = OFF;
int _font = 0;
DATAFILE *_fontfile[NFONTS];
FONT *_basefont;

// variables set by coordinates.c 
int _coordinates = CARTESIAN;

// variables set by textio.c 

// variables set by draw.c 

// variables set by timer.c 
int _timer_flag = 0;
int _trigger_flag = 0;
int _vsync_flag = NOSYNC;
int _rtc_flag = 0;
int _rtc_fd = 0;
int _nvsyncmode = 4;
int _vvsyncmode[] = { REALSYNC, SIMSYNC_ACTUAL, SIMSYNC_REQ, WHATEVER };
char *_svsyncmode[] =
    { "REALSYNC", "SIMSYNC_ACTUAL", "SIMSYNC_REQ", "WHATEVER" };
int _wait_flag = BUSYLOOP;
int _nwaitmode = 4;
int _vwaitmode[] = { BUSYLOOP, SLEEP_WAIT, SLEEP_RESP, SLEEP_VSYNC };
char *_swaitmode[] =
    { "BUSYLOOP", "SLEEP_WAIT", "SLEEP_RESP", "SLEEP_VSYNC" };

int _joystick_flag = 0;
int _keyboard_flag = 0;
int _mouse_flag = 0;
int _gameport_flag = 0;
int _serialport_flag = 0;
int _parport_flag = 0;
int _parport1_flag = 0;
int _parport2_flag = 0;
int _parport3_flag = 0;

#ifdef ALLEGRO_WINDOWS
HANDLE _serialport_handle;
#endif
int _serialport_num = 0;

int _serialport_resp_flag = 0;
int _gameport_resp_flag = 0;
int _parport1_resp_flag = 0;
int _parport2_resp_flag = 0;
int _parport3_resp_flag = 0;
int _keyboard_resp_flag = 0;
int _mouse_resp_flag = 0;
int _joystick_resp_flag = 0;

int _key_defined[NRESPKEYS];
int _key_active[NRESPKEYS];
int _n_active_keys = 0;

int _ndefkey = NRESPKEYS;
int _vdefkey[] = { KEY_NULL,
    KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
    KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S,
    KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_0, KEY_1,
    KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0_PAD,
    KEY_1_PAD, KEY_2_PAD, KEY_3_PAD, KEY_4_PAD, KEY_5_PAD, KEY_6_PAD,
    KEY_7_PAD, KEY_8_PAD, KEY_9_PAD, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
    KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
    KEY_ESC, KEY_TILDE, KEY_MINUS, KEY_EQUALS, KEY_BACKSPACE, KEY_TAB,
    KEY_OPENBRACE, KEY_CLOSEBRACE, KEY_ENTER, KEY_COLON, KEY_QUOTE,
    KEY_BACKSLASH, KEY_BACKSLASH2, KEY_COMMA, KEY_STOP, KEY_SLASH,
    KEY_SPACE, KEY_INSERT, KEY_DEL, KEY_HOME, KEY_END, KEY_PGUP,
    KEY_PGDN, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_SLASH_PAD,
    KEY_ASTERISK, KEY_MINUS_PAD, KEY_PLUS_PAD, KEY_DEL_PAD,
    KEY_ENTER_PAD, KEY_PRTSCR, KEY_PAUSE, KEY_ABNT_C1, KEY_YEN,
    KEY_KANA, KEY_CONVERT, KEY_NOCONVERT, KEY_AT, KEY_CIRCUMFLEX,
    KEY_COLON2, KEY_KANJI,
#if (ALLEGRO_SUB_VERSION>0)
    KEY_EQUALS_PAD, KEY_BACKQUOTE, KEY_SEMICOLON, KEY_COMMAND,
    KEY_UNKNOWN1, KEY_UNKNOWN2, KEY_UNKNOWN3, KEY_UNKNOWN4,
    KEY_UNKNOWN5, KEY_UNKNOWN6, KEY_UNKNOWN7, KEY_UNKNOWN8,
#endif
    KEY_LSHIFT, KEY_RSHIFT, KEY_LCONTROL, KEY_RCONTROL, KEY_ALT, KEY_ALTGR,
    KEY_LWIN, KEY_RWIN, KEY_MENU, KEY_SCRLOCK, KEY_NUMLOCK,
    KEY_CAPSLOCK, P1, P2, P3, P4, P5, IP1, IP2, IP3, IP4, IP5, PP1, PP2,
    PP3, PP4, PP5, IPP1, IPP2, IPP3, IPP4, IPP5, PPP1, PPP2, PPP3,
    PPP4, PPP5, IPPP1, IPPP2, IPPP3, IPPP4, IPPP5, G1, G2, G3, G4, IG1,
    IG2, IG3, IG4, S1, S2, S3, S4, S5, S6, S7, J1, J2, J3, J4, J5, J6, J7,
    J8, J9, J10, M1, M2, M3
};
char *_sdefkey[] = { "KEY_NULL",
    "KEY_A", "KEY_B", "KEY_C", "KEY_D", "KEY_E", "KEY_F", "KEY_G", "KEY_H",
    "KEY_I", "KEY_J", "KEY_K", "KEY_L", "KEY_M", "KEY_N", "KEY_O",
    "KEY_P", "KEY_Q", "KEY_R", "KEY_S", "KEY_T", "KEY_U", "KEY_V",
    "KEY_W", "KEY_X", "KEY_Y", "KEY_Z", "KEY_0", "KEY_1", "KEY_2",
    "KEY_3", "KEY_4", "KEY_5", "KEY_6", "KEY_7", "KEY_8", "KEY_9",
    "KEY_0_PAD", "KEY_1_PAD", "KEY_2_PAD", "KEY_3_PAD", "KEY_4_PAD",
    "KEY_5_PAD", "KEY_6_PAD", "KEY_7_PAD", "KEY_8_PAD", "KEY_9_PAD",
    "KEY_F1", "KEY_F2", "KEY_F3", "KEY_F4", "KEY_F5", "KEY_F6",
    "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10", "KEY_F11", "KEY_F12",
    "KEY_ESC", "KEY_TILDE", "KEY_MINUS", "KEY_EQUALS", "KEY_BACKSPACE",
    "KEY_TAB", "KEY_OPENBRACE", "KEY_CLOSEBRACE", "KEY_ENTER",
    "KEY_COLON", "KEY_QUOTE", "KEY_BACKSLASH", "KEY_BACKSLASH2",
    "KEY_COMMA", "KEY_STOP", "KEY_SLASH", "KEY_SPACE", "KEY_INSERT",
    "KEY_DEL", "KEY_HOME", "KEY_END", "KEY_PGUP", "KEY_PGDN",
    "KEY_LEFT", "KEY_RIGHT", "KEY_UP", "KEY_DOWN", "KEY_SLASH_PAD",
    "KEY_ASTERISK", "KEY_MINUS_PAD", "KEY_PLUS_PAD", "KEY_DEL_PAD",
    "KEY_ENTER_PAD", "KEY_PRTSCR", "KEY_PAUSE", "KEY_ABNT_C1",
    "KEY_YEN", "KEY_KANA", "KEY_CONVERT", "KEY_NOCONVERT", "KEY_AT",
    "KEY_CIRCUMFLEX", "KEY_COLON2", "KEY_KANJI",
#if (ALLEGRO_SUB_VERSION>0)
    "KEY_EQUALS_PAD", "KEY_BACKQUOTE", "KEY_SEMICOLON", "KEY_COMMAND",
    "KEY_UNKNOWN1", "KEY_UNKNOWN2", "KEY_UNKNOWN3", "KEY_UNKNOWN4",
    "KEY_UNKNOWN5", "KEY_UNKNOWN6", "KEY_UNKNOWN7", "KEY_UNKNOWN8",
#endif
    "KEY_LSHIFT", "KEY_RSHIFT", "KEY_LCONTROL", "KEY_RCONTROL", "KEY_ALT",
    "KEY_ALTGR", "KEY_LWIN", "KEY_RWIN", "KEY_MENU", "KEY_SCRLOCK",
    "KEY_NUMLOCK", "KEY_CAPSLOCK", "P1", "P2", "P3", "P4", "P5", "IP1",
    "IP2", "IP3", "IP4", "IP5", "PP1", "PP2", "PP3", "PP4", "PP5",
    "IPP1", "IPP2", "IPP3", "IPP4", "IPP5", "PPP1", "PPP2", "PPP3",
    "PPP4", "PPP5", "IPPP1", "IPPP2", "IPPP3", "IPPP4", "IPPP5", "G1",
    "G2", "G3", "G4", "IG1", "IG2", "IG3", "IG4", "S1", "S2", "S3",
    "S4", "S5", "S6", "S7", "J1", "J2", "J3", "J4", "J5", "J6", "J7",
    "J8", "J9", "J10", "M1", "M2", "M3"
};


int _priority = 0;
int _npriority = 6;
int _vpriority[] =
    { REALTIME, HIGH, ABOVE_NORMAL, NORMAL, BELOW_NORMAL, IDLE };
char *_spriority[] =
    { "REALTIME", "HIGH", "ABOVE_NORMAL", "NORMAL", "BELOW_NORMAL",
    "IDLE"
};
__int64 _clockfreq = 0;
#ifdef ALLEGRO_WINDOWS
LARGE_INTEGER _clocktime;
#else
struct timeval _clocktime;
#endif

int _vsync_requestedmode = WHATEVER;
__int64 _vsyncinterval = 0;
int _vsync_limit = 70;

int _trigport = 0;
int _trigaddress = 0;
__int64 _trigtime = 0;

// variables set by random.c
int _random_flag = 0;

int _rndseed[3];

// variables set by mouse.c
int _mousegui_flag = 0;

int _mousecolor = 0;
int _mousex = 0;
int _mousey = 0;
BITMAP *_mousemap;

// variables set by sound.c 
int _sound_flag = 0;

int _volume = 255;
int _pan = 128;
int _loop = 0;

int _samplerate = 22050;
int _streambufsize = 1024;
int _sinefreq = 800;

// variables set by sound2.c
int _snd2_flag = 0;
int _snd2_channels = 1;
int _snd2_samplerate = 22050;
int _snd2_sampleformat = SAMPLE_INTEGER;    
__int64 _snd2_filebufferlength = 0;

// -----------------------------------------------------------------------
// lower level init function.
// needed by screen, timing and sound functions
void _tscope_init()
{
    // execute only once
    if (!_tscope_flag) {
        _tscope_flag = 1;

        // use ascii text instead of unicode
        set_uformat(U_ASCII);

        // open allegro 
#if (ALLEGRO_SUB_VERSION==0)
        allegro_init();
#else
        int tmp;
        tmp = allegro_init();
        if (tmp) {
            fprintf(stderr,
                    "\n\tFatal error - closing Tscope.\n\tUnable to open Allegro subsystem\n\n");
            allegro_message
                ("Fatal error - closing Tscope.\nUnable to open Allegro subsystem");
            exit(-1);
        }
#endif

        atexit(allegro_exit);
        _desktopdepth = desktop_color_depth();
        get_desktop_resolution(&_desktopx, &_desktopy);

        // print some information about the computer we're running on
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Opening tscope-1.0.176\n");
        if (_debug_flag > DEBUG2) {
            fprintf(stderr, "Operating system: ");
            switch (os_type) {
            case OSTYPE_WIN95:
                fprintf(stderr, "Windows 95, ");
                break;
            case OSTYPE_WIN98:
                fprintf(stderr, "Windows 98, ");
                break;
            case OSTYPE_WINME:
                fprintf(stderr, "Windows ME, ");
                break;
            case OSTYPE_WINNT:
                fprintf(stderr, "Windows NT, ");
                break;
            case OSTYPE_WIN2000:
                fprintf(stderr, "Windows 2000, ");
                break;
            case OSTYPE_WINXP:
                fprintf(stderr, "Windows XP, ");
                break;
            default:
                fprintf(stderr, "Unknown, ");
            }
            fprintf(stderr, "version %d, revision %d.\n", os_version,
                    os_revision);
            fprintf(stderr,
                    "Desktop: %d x %d pixels, %d bits per pixel.\n",
                    _desktopx, _desktopy, _desktopdepth);
            fprintf(stderr, "\n");
        }
    }
}

// -----------------------------------------------------------------------
// screen init function
int _screen_init()
{
    // start tscope if necessary
    if (!_tscope_flag)
        _tscope_init();

    // print some information about the requested graphics mode
    if (_debug_flag > DEBUG1)
        fprintf(stderr, "Opening graphics screen\n");
    if (_debug_flag > DEBUG2) {
        fprintf(stderr, "Refreshrate: %d Hz.\n", _refreshrate);
        fprintf(stderr, "Color depth: %d bits.\n", _screendepth);
        fprintf(stderr, "Resolution %d: %d x %d pixels.\n", _screensize,
                _screenx, _screeny);
        if (_screenmode == WINDOW)
            fprintf(stderr, "Screen: windowed.\n");
        else
            fprintf(stderr, "Screen: fullscreen.\n");
        if (_dbuff == TRUE)
            fprintf(stderr, "Double buffer: on.\n\n");
        else
            fprintf(stderr, "Double buffer: off.\n\n");
    }
    // set the requested screen parameters and open screen
    // refreshrate
    request_refresh_rate(_refreshrate);

    // set the color depth to the same as the desktop 
    // when running in windowed mode
    int olddepth = _actualdepth;
    if (_screenmode == WINDOW) {
        if (_debug_flag > DEBUG0)
            fprintf(stderr,
                    "\tColor depth adjusted to desktop (%d bpp).\n",
                    _desktopdepth);
        _actualdepth = _desktopdepth;
    } else
        _actualdepth = _screendepth;
    set_color_depth(_actualdepth);

    // check wether requested window is small enough to fit the desktop
    // shrink if necessary
    if (_screenmode == WINDOW && _screensize != USERDEFINED
        && (_screenx >= _desktopx || _screeny >= _desktopy)) {

        int toosmallforwidescreen = FALSE;

        // widescreen resolutions
        if (_screensize > 2 && _screensize % 2 == 0) {
            if (_desktopx <= WXGA_X) {
                toosmallforwidescreen = TRUE;
            } else if (_desktopx <= WXGAplus_X) {
                _actualx = WXGA_X;
                _actualy = WXGA_Y;
            } else if (_desktopx <= WSXGA_X) {
                _actualx = WXGAplus_X;
                _actualy = WXGAplus_Y;
            } else if (_desktopx <= WSXGAplus_X) {
                _actualx = WXGAplus_X;
                _actualy = WXGAplus_Y;
            } else if (_desktopx <= WUXGA_X) {
                _actualx = WSXGAplus_X;
                _actualy = WSXGAplus_Y;
            } else {
                _actualx = WUXGA_X;
                _actualy = WUXGA_Y;
            }
        }
        // normal resolutions
        if (_screensize <= 2 || _screensize % 2 == 1
            || toosmallforwidescreen) {
            if (_desktopx <= VGA_X) {
                _actualx = QVGA_X;
                _actualy = QVGA_Y;
            } else if (_desktopx <= SVGA_X) {
                _actualx = VGA_X;
                _actualy = VGA_Y;
            } else if (_desktopx <= XGA_X) {
                _actualx = SVGA_X;
                _actualy = SVGA_Y;
            } else if (_desktopx <= XGAplus_X) {
                _actualx = SVGA_X;
                _actualy = SVGA_Y;
            } else if (_desktopx <= SXGA_X) {
                _actualx = XGAplus_X;
                _actualy = XGAplus_Y;
            } else if (_desktopx <= SXGAplus_X) {
                _actualx = XGAplus_X;
                _actualy = XGAplus_Y;
            } else if (_desktopx <= UXGA_X) {
                _actualx = SXGAplus_X;
                _actualy = SXGAplus_Y;
            } else {
                _actualx = UXGA_X;
                _actualy = UXGA_Y;
            }
        }

        if (_debug_flag > DEBUG0)
            fprintf(stderr,
                    "\tScreen resolution adjusted to desktop: %d x %d.\n",
                    _actualx, _actualy);

    } else {
        _actualx = _screenx;
        _actualy = _screeny;
    }

    // try to open the graphics mode
    if (set_gfx_mode(_screenmode, _actualx, _actualy, 0, 0) < 0)
        ts_fatal("_screen_init: error opening graphics mode.");
    set_display_switch_mode(SWITCH_BACKGROUND);
#ifdef ALLEGRO_WINDOWS
#if (ALLEGRO_SUB_VERSION==0)
    set_window_close_button(0);
#endif
#endif

    // if tscope was already running
    // reset colors if colordepth has changed
    if (_screen_flag && _actualdepth != olddepth) {
        _fgcolor = WHITE;
        _mousecolor = GREEN;
        _bgcolor = BLACK;
        _textbgcolor = -1;
#if (ALLEGRO_SUB_VERSION==0)
        text_mode(_textbgcolor);
#endif
    }
    // if tscope was already running, 
    // remove screen bitmap after changing graphics mode
    if (_screen_flag) {
        _screenmap->b = NULL;
        free(_screenmap);
        _screen_flag = 0;
    }
    // make screen bitmap
    _screenmap = malloc(sizeof(map));
    _screenmap->b = screen;
    _screenmap->sw = screen->w;
    _screenmap->sh = screen->h;
    _screenmap->w = screen->w / 2;
    _screenmap->h = screen->h / 2;
    _screen_flag = 1;

    // if tscope was already running, 
    // remove double buffer after changing graphics mode
    if (_dbuff_flag) {
        destroy_bitmap(_dbuffmap->b);
        free(_dbuffmap);
        _dbuff_flag = 0;
    }
    // make double buffer if requested
    if (_dbuff) {
        _dbuffmap = malloc(sizeof(map));
        _dbuffmap->b = create_bitmap(SXMAX, SYMAX);
        _dbuffmap->sw = screen->w;
        _dbuffmap->sh = screen->h;
        _dbuffmap->w = screen->w / 2;
        _dbuffmap->h = screen->h / 2;
        clear_to_color(_dbuffmap->b, _bgcolor);
        _dbuff_flag = 1;
    }
    // set the screen as default drawing destination
    _destmap = _screenmap;

    // if mousegui was already running, update it
    if (_mousegui_flag) {
        _mousegui_exit();
        _mousegui_init();
    }
    // check the refreshrate
    _actual_refreshrate = get_refresh_rate();
    if (_actual_refreshrate != _refreshrate && _debug_flag > DEBUG0)
        fprintf(stderr, "\tRefreshrate is %d Hz, requested %d Hz.\n\n",
                _actual_refreshrate, _refreshrate);

    // if vsync was already running, update vsync status
    if (_vsync_flag) {
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Updating vsync system\n");
        _vsync_exit();
        _vsync_init();
    }
    // return the refreshrate
    return _actual_refreshrate;
}

// -----------------------------------------------------------------------
// graphics init & exit functions
void _graphics_init()
{
    // execute only once
    if (!_graphics_flag) {

        // start screen if necessary
        if (!_screen_flag)
            _screen_init();
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Starting graphics subsystem.\n");

        // set default graphics parameters
        _graphics_flag = 1;
        _fgcolor = WHITE;
        _mousecolor = RED;
        _bgcolor = BLACK;
        ts_textmode(_textbgcolor);

        // make font pointers
        _basefont = font;
        int i;
        for (i = 0; i < NFONTS; i++)
            _fontfile[i] = NULL;

        atexit(_graphics_exit);
    }
}

void _graphics_exit()
{
    // execute only if graphics is running
    if (_graphics_flag) {
        _graphics_flag = 0;

        // remove font files
        int i;
        for (i = 0; i < NFONTS; i++) {
            if (_fontfile[i] != NULL);
            unload_datafile(_fontfile[i]);
        }

        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Graphics subsystem stopped.\n");
    }
}


// -----------------------------------------------------------------------
// timer init & exit functions
__int64 _timer_init()
{
    // execute only once
    if (!_timer_flag) {
        _timer_flag = 1;

        // start tscope if necessary
        if (!_tscope_flag)
            _tscope_init();

        // check frequency of cpu clock
#ifdef ALLEGRO_WINDOWS
        if (!(QueryPerformanceFrequency(&_clocktime)))
            ts_fatal("_timer_init: error starting timer subsystem.");
        _clockfreq = _clocktime.QuadPart;
#else
        _clockfreq = 1000000;
#endif
        if (_debug_flag > DEBUG1) {
            fprintf(stderr, "Timer subsystem started.\n");
            fprintf(stderr, "CPU clock frequency: %lld tics per second\n",
                    _clockfreq);
        }
        // set defaults
        _priority = NORMAL;
        ts_clrkeys();

        // start vsync
        _vsync_init();

        atexit(_timer_exit);
    }
    return _clockfreq;
}

void _timer_exit()
{
    // execute only if timer was running
    if (_timer_flag) {
        ts_clrkeys();
        _timer_flag = 0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Timer subsystem stopped.\n");
    }
}

// -----------------------------------------------------------------------
// vsync init & exit functions
void _vsync_init()
{
    // start timer if necessary
    if (!_timer_flag)
        _timer_init();

    // choose vsync mode
#ifdef ALLEGRO_WINDOWS
    _actual_refreshrate = get_refresh_rate();

    if (_vsync_requestedmode == WHATEVER) {
        if (!_screen_flag) {
            _vsync_flag = SIMSYNC_REQ;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr, "\n\tWindow not running yet\n");
                fprintf(stderr,
                        "\tVsync simulation at requested refreshrate.\n\n");
            }
        } else if (_screenmode == WINDOW) {
            _vsync_flag = SIMSYNC_ACTUAL;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tWindow mode & actual refreshrate known\n");
                fprintf(stderr,
                        "\tVsync simulation at actual refreshrate.\n\n");
            }
        } else if (_actual_refreshrate > _vsync_limit) {
            _vsync_flag = SIMSYNC_ACTUAL;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tFullscreen mode & refreshrate too high\n");
                fprintf(stderr,
                        "\tVsync simulation at actual refreshrate.\n\n");
            }
        } else
            _vsync_flag = REALSYNC;
    } else
        _vsync_flag = _vsync_requestedmode;

    // try to open the port first,
    // fall back to simulation if necessary
    if (_vsync_flag == REALSYNC) {
        if (ioperm(VSYNCPORT, 1, 1)) {
            _vsync_flag = SIMSYNC_ACTUAL;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tError opening register & actual refreshrate known\n");
                fprintf(stderr,
                        "\tVsync simulation at actual refreshrate.\n\n");
            }
        } else {
            atexit(_vsync_exit);
            if (_debug_flag > DEBUG0)
                fprintf(stderr, "Vsync register opened.\n");
        }
    }
    // set simulation parameters if necessary
    if (_vsync_flag == SIMSYNC_REQ)
        _vsyncinterval = _clockfreq / _refreshrate;
    else if (_actual_refreshrate == 0)
        ts_fatal("_vsync_init: error reading refresh rate");
    else
        _vsyncinterval = _clockfreq / _actual_refreshrate;

    if (_debug_flag > DEBUG0)
        fprintf(stderr, "Vsync interval: %lld us\n", ttmu(_vsyncinterval));
#endif

#ifdef ALLEGRO_LINUX
    if (_vsync_requestedmode == WHATEVER) {
        if (!_screen_flag) {
            _vsync_flag = SIMSYNC_REQ;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr, "\n\tWindow not running yet\n");
                fprintf(stderr,
                        "\tVsync simulation at requested refreshrate.\n\n");
            }
        } else if (_screenmode == WINDOW) {
            _vsync_flag = SIMSYNC_REQ;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tWindow mode & actual refreshrate unknown.\n");
                fprintf(stderr,
                        "\tVsync simulation at requested refreshrate.\n\n");
            }
        } else if (_refreshrate > _vsync_limit) {
            _vsync_flag = SIMSYNC_REQ;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tFullscreen mode & refreshrate too high\n");
                fprintf(stderr,
                        "\tVsync simulation at requested refreshrate.\n\n");
            }
        } else
            _vsync_flag = REALSYNC;
    } else
        _vsync_flag = _vsync_requestedmode;

    if (_vsync_flag == SIMSYNC_ACTUAL) {
        _vsync_flag = SIMSYNC_REQ;
        if (_debug_flag > DEBUG0) {
            fprintf(stderr, "\n\tActual refreshrate not known\n");
            fprintf(stderr,
                    "\tVsync simulation at requested refreshrate.\n\n");
        }
    }

    if (_vsync_flag == REALSYNC) {
        if (geteuid() != 0) {
            _vsync_flag = SIMSYNC_REQ;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tUser has no root privileges & actual refreshrate unknown\n");
                fprintf(stderr,
                        "\tVsync simulation at requested refreshrate.\n\n");
            }
        } else if (ioperm(VSYNCPORT, 1, 1)) {
            _vsync_flag = SIMSYNC_REQ;
            if (_debug_flag > DEBUG0) {
                fprintf(stderr,
                        "\n\tError opening register & actual refreshrate unknown\n");
                fprintf(stderr,
                        "\tVsync simulation at requested refreshrate.\n\n");
            }
        } else {
            atexit(_vsync_exit);
            if (_debug_flag > DEBUG0)
                fprintf(stderr, "Vsync register opened.\n");
        }
    }
    // set simulation parameters if necessary
    _vsyncinterval = _clockfreq / _refreshrate;

    if (_debug_flag > DEBUG0)
        fprintf(stderr, "Vsync interval: %lld us\n", ttmu(_vsyncinterval));
#endif

#ifdef ALLEGRO_MACOSX
    // always revert to simulation at requested refreshrate
    _vsync_flag = SIMSYNC_REQ;
    _vsyncinterval = _clockfreq / _refreshrate;
    //_actual_refreshrate = get_refresh_rate();
    if (_debug_flag > DEBUG0) {
        fprintf(stderr, "\n\tRunning on Mac OS X\n");
        fprintf(stderr, "\tVsync simulation at requested refreshrate\n");
        fprintf(stderr, "\tVsync interval: %lld us\n\n",
                ttmu(_vsyncinterval));
    }
#endif
}


void _vsync_exit()
{
#if defined(ALLEGRO_WINDOWS) || defined(ALLEGRO_LINUX)
    // close registry
    // only necessary with real vsync
    if (_vsync_flag == REALSYNC) {
        ioperm(VSYNCPORT, 1, 0);
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Vsync register closed.\n");
    }
    _vsync_flag = 0;
#endif
}

// -----------------------------------------------------------------------
// real time clock init, nap & exit functions 
// these functions are necessary when running with above normal
// priorities on linux systems
// the _rtc_nap function gives up about 1/2 ms of processor time
// to allow other processes to run

void _rtc_init()
{
#ifdef ALLEGRO_LINUX
    if (geteuid() != 0)
        ts_fatal("_rtc_init: only root can open the real time clock.");

    if (!_rtc_flag) {
        _rtc_flag = 1;
        atexit(_rtc_exit);

        if ((_rtc_fd = open("/dev/rtc", O_RDONLY)) < 0)
            ts_fatal("_rtc_init: error opening real time clock.");

        if (ioctl(_rtc_fd, RTC_IRQP_SET, 8192) < 0)
            ts_fatal
                ("_rtc_init: error setting real time clock frequency.");

        if (ioctl(_rtc_fd, RTC_PIE_ON, 0) < 0)
            ts_fatal
                ("_rtc_init: error setting real time clock interrupts.");

        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Real time clock openend.\n");
    }
#endif
}

void _rtc_nap()
{
#ifdef ALLEGRO_WINDOWS
    Sleep(0);
#elif ALLEGRO_LINUX
    if (_rtc_flag) {
        unsigned long timedata;
        if (read(_rtc_fd, &timedata, sizeof(unsigned long)) < 0)
            ts_fatal("_rtc_nap: error reading real time clock");
    }
#endif
}

void _rtc_exit()
{
#ifdef ALLEGRO_LINUX
    if (_rtc_flag) {

        if (ioctl(_rtc_fd, RTC_PIE_OFF, 0) < 0)
            ts_fatal
                ("_rtc_exit: error removing real time clock interrupts.");
        close(_rtc_fd);

        _rtc_flag = 0;

        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Real time clock closed.\n");
    }
#endif
}

// -----------------------------------------------------------------------
// init & exit functions for input devices

// these functions do not check whether tscope is running
// expect ugly crashes if you call these functions 
// without starting tscope first

void _parport_init(int nr)
{
#ifdef ALLEGRO_LINUX
    if (geteuid() != 0)
        ts_fatal("_parport_init: only root can open the parallel port.");
#endif

#if defined(ALLEGRO_WINDOWS) || defined(ALLEGRO_LINUX)
    if (!_parport_flag) {
        _parport_flag = 1;
        atexit(_parport_exit);
    }

    if (nr == 1 && !_parport1_flag) {
        if (ioperm(PAR1DATA, 3, 1))
            ts_fatal("_parport_init: error opening parallell port 1.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Parallell port 1 opened.\n");
    } else if (nr == 2 && !_parport2_flag) {
        if (ioperm(PAR2DATA, 3, 1))
            ts_fatal("_parport_init: error opening parallell port 2.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Parallell port 2 opened.\n");
    } else if (nr == 3 && !_parport3_flag) {
        if (ioperm(PAR3DATA, 3, 1))
            ts_fatal("_parport_init: error opening parallell port 3.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Parallell port 3 opened.\n");
    } else {
        ts_fatal("_parport_init: unknown parallell port requested.");
    }
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal("_parport_init: parallel port can not be read on macosx.");
#endif
}

void _parport_exit()
{
#ifdef ALLEGRO_LINUX
    if (geteuid() != 0)
        ts_fatal("_parport_exit: only root can close the parallel port.");
#endif

#if defined(ALLEGRO_WINDOWS) || defined(ALLEGRO_LINUX)
    if (_parport_flag) {
        if (_parport1_flag) {
            ioperm(PAR1DATA, 3, 0);
            _parport1_flag = 0;
        }
        if (_parport2_flag) {
            ioperm(PAR2DATA, 3, 0);
            _parport2_flag = 0;
        }
        if (_parport3_flag) {
            ioperm(PAR3DATA, 3, 0);
            _parport3_flag = 0;
        }
        _parport_flag = 0;

        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Parallell ports closed.\n");
    }
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal("_parport_exit: parallel port can not be read on macosx.");
#endif
}

void _gameport_init()
{
#ifdef ALLEGRO_LINUX
    if (geteuid() != 0)
        ts_fatal("_gameport_init: only root can open the game port.");
#endif

#if defined(ALLEGRO_WINDOWS) || defined(ALLEGRO_LINUX)
    if (!_gameport_flag) {
        _gameport_flag = 1;
        if (ioperm(GAMEPORT, 1, 1))
            ts_fatal("_gameport_init: error opening gameport.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Gameport opened.\n");
        atexit(_gameport_exit);
    }
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal("_gameport_init: game port can not be read on macosx.");
#endif
}

void _gameport_exit()
{
#ifdef ALLEGRO_LINUX
    if (geteuid() != 0)
        ts_fatal("_gameport_exit: only root can close the game port.");
#endif

#if defined(ALLEGRO_WINDOWS) || defined(ALLEGRO_LINUX)
    if (_gameport_flag) {
        ioperm(GAMEPORT, 1, 0);
        _gameport_flag = 0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Gameport closed.\n");
    }
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal("_gameport_exit: game port can not be read on macosx.");
#endif
}

void _serialport_init()
{
#ifdef ALLEGRO_WINDOWS
    if (!_serialport_num) {
        ts_fatal
            ("_serialport_init: serial port not specified - use ts_setserialport.");
    }
    if (!_serialport_flag) {
        _serialport_flag = 1;


        char portname[20];
        sprintf(portname, "COM%d", _serialport_num);
        _serialport_handle = CreateFile(portname,
                                        GENERIC_READ | GENERIC_WRITE,
                                        0, NULL, OPEN_EXISTING, 0, NULL);

        if (_serialport_handle == INVALID_HANDLE_VALUE)
            ts_fatal("_serialport_init: error opening serial port %s.",
                     portname);
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Serial port %s opened.\n", portname);

        DCB dcb;
        int status;
        COMMTIMEOUTS ct;

        status = GetCommState(_serialport_handle, &dcb);

        // Setup serial port for 8-N-1
        // (8 bits, no parity, 1 stop bit)
        if (status != 0) {
            dcb.BaudRate = 19200;
            dcb.ByteSize = (unsigned char) 8;
            dcb.Parity = 0;
            dcb.StopBits = 0;
            dcb.fBinary = 1;    // No EOF check
            status = SetCommState(_serialport_handle, &dcb);
        }
        // Setup timeouts
        ct.ReadIntervalTimeout = MAXDWORD;
        ct.ReadTotalTimeoutMultiplier = 0;
        ct.ReadTotalTimeoutConstant = 0;
        ct.WriteTotalTimeoutMultiplier = 0;
        ct.WriteTotalTimeoutConstant = 5000;
        SetCommTimeouts(_serialport_handle, &ct);

        status = SetupComm(_serialport_handle, 128, 128);
        _serialport_flush(_serialport_handle);
        atexit(_serialport_exit);
    }
#endif

#ifdef ALLEGRO_LINUX
    ts_fatal
        ("_serialport_init: serial port not implemented in linux version.");
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal
        ("_serialport_init: serial port not implemented in macosx version.");
#endif
}

int _serialport_flush()
{
#ifdef ALLEGRO_WINDOWS
    int status = 0;
    int done = FALSE;
    char serial_buff[100];
    long bytes_read;

    while (!done) {
        status = ReadFile(_serialport_handle, serial_buff,
                          sizeof(serial_buff), &bytes_read, NULL);

        if (status == 0)
            done = TRUE;        // Error?!

        if (status != 0 && bytes_read < sizeof(serial_buff)) {
            done = TRUE;
        }
    }
    return status;
#endif

#ifdef ALLEGRO_LINUX
    ts_fatal
        ("_serialport_flush: serial port not implemented in linux version.");
    return 1;
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal
        ("_serialport_flush: serial port not implemented in macosx version.");
    return 1;
#endif

}

int _serialport_poll()
{
#ifdef ALLEGRO_WINDOWS
    int num_bytes;
    int input = 0;
    short status;
    char serial_buff[6];
    long comm_status;

    //_serialport_flush();

    serial_buff[0] = '\0';
    num_bytes = 0;

    status =
        ReadFile(_serialport_handle, serial_buff, 1, &comm_status, NULL);
    if (status != 0)
        num_bytes = (short) comm_status;

    if (status == 0)
        ClearCommError(_serialport_handle, &comm_status, NULL);

    if (num_bytes > 0)
        input = (serial_buff[0] & 0x000f);

    return input;
#endif

#ifdef ALLEGRO_LINUX
    ts_fatal
        ("_serialport_poll: serial port not implemented in linux version.");
    return 1;
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal
        ("_serialport_poll: serial port not implemented in macosx version.");
    return 1;
#endif
}

void _serialport_exit()
{
#ifdef ALLEGRO_WINDOWS
    if (_serialport_flag) {
        CloseHandle(_serialport_handle);
        _serialport_flag = 0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Serial port driver removed.\n");
    }
#endif

#ifdef ALLEGRO_LINUX
    ts_fatal
        ("_serialport_exit: serial port not implemented in linux version.");
#endif

#ifdef ALLEGRO_MACOSX
    ts_fatal
        ("_serialport_exit: serial port not implemented in macosx version.");
#endif
}

void _joystick_init()
{
    if (!_joystick_flag) {
        _joystick_flag = 1;
        if (install_joystick(JOY_TYPE_AUTODETECT) != 0)
            ts_fatal("_joystick_init: error loading joystick driver.");
        if (!num_joysticks)
            ts_fatal("_joystick_init: error loading joystick driver.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Joystick driver loaded.\n");
        atexit(_joystick_exit);
    }
}

void _joystick_exit()
{
    if (_joystick_flag) {
        remove_joystick();
        _joystick_flag = 0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Joystick driver removed.\n");
    }
}

void _mouse_init()
{
    if (!_mouse_flag) {
        _mouse_flag = 1;
        if (install_mouse() < 0)
            ts_fatal("_mouse_init: error loading mouse driver.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Mouse driver loaded.\n");
        poll_mouse();
        atexit(_mouse_exit);
    }
}

void _mouse_exit()
{
    if (_mouse_flag) {
        remove_mouse();
        _mouse_flag = 0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Mouse driver removed.\n");
    }
}

void _keyboard_init()
{
    if (!_keyboard_flag) {
        _keyboard_flag = 1;
        if (install_keyboard() < 0)
            ts_fatal("_keyboard_init: error loading keyboard driver.");
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Keyboard driver loaded.\n");
        poll_keyboard();
        atexit(_keyboard_exit);
    }
}

void _keyboard_exit()
{
    if (_keyboard_flag) {
        remove_keyboard();
        _keyboard_flag = 0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Keyboard driver removed.\n");
    }
}

// -----------------------------------------------------------------------
// randomisator init & exit functions

void _random_init()
{
    // execute only once
    if (!_random_flag) {

        atexit(_random_exit);
        _random_flag = 1;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Starting randomisation subsystem.\n");


        // set seed based on clock time
        int junk;
#ifdef ALLEGRO_WINDOWS
        LARGE_INTEGER junk2;
        QueryPerformanceCounter(&junk2);
        junk = (int) junk2.QuadPart;
#else
        struct timeval junk2;
        gettimeofday(&junk2, NULL);
        junk = (int) (junk2.tv_sec * 1000000 + junk2.tv_usec);
#endif

        _rndseed[0] = junk % 30268 + 1;
        _rndseed[1] = junk % 30306 + 1;
        _rndseed[2] = junk % 30322 + 1;

        if (_debug_flag > DEBUG1)
            fprintf(stderr,
                    "Random seeds (clock-based): %d, %d en %d.\n",
                    _rndseed[0], _rndseed[1], _rndseed[2]);
    }
}

void _random_exit()
{
    // execute only if randomization system was running
    if (_random_flag) {

        // save seeds to file
        FILE *seedfile;
        if ((seedfile = fopen("seed.dat", "w")) == NULL)
            ts_fatal("_random_exit: error writing random seeds.");
        fprintf(seedfile, "%d\n", _rndseed[0]);
        fprintf(seedfile, "%d\n", _rndseed[1]);
        fprintf(seedfile, "%d\n", _rndseed[2]);
        fclose(seedfile);
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Randomisation subsystem stopped.\n");
        _random_flag = 0;
    }
}

// -----------------------------------------------------------------------
// mousegui init & exit functions

void _mousegui_init()
{
    // execute only once
    if (!_mousegui_flag) {

        // start graphics if necessary
        if (!_graphics_flag)
            _graphics_init();

        // start mouse driver if necessary
        if (!_mouse_flag)
            _mouse_init();

        // draw mouse bitmap
        _mousegui_flag = 1;
        _mousemap = create_bitmap(24, 24);
        clear_to_color(_mousemap, bitmap_mask_color(screen));
        triangle(_mousemap, 0, 0, 12, 4, 4, 12, _mousecolor);
        rectfill(_mousemap, 4, 4, 12, 12, bitmap_mask_color(screen));
        set_mouse_sprite(_mousemap);
        set_mouse_sprite_focus(0, 0);

        // set default mouse position
        _mousex = sx(XMAX / 2);
        _mousey = sy(-YMAX / 2);

        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Starting mouse subsystem.\n");
        atexit(_mousegui_exit);
    }
}

void _mousegui_exit()
{
    // execute only if mousegui was running
    if (_mousegui_flag) {
        _mousegui_flag = 0;
        destroy_bitmap(_mousemap);
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Mouse subsystem stopped.\n");
    }
}

// -----------------------------------------------------------------------
// sound init & exit functions

void _sound_init()
{
    if (_snd2_flag)
        ts_fatal("_sound_init: new sound system is already running.\n") ;

    // execute only once
    if (!_sound_flag) {

        // start tscope if necessary
        if (!_tscope_flag)
            _tscope_init();

        // load sound driver
        if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL) != 0)
            ts_fatal("_sound_init: error loading sound driver");

        // is it a real sound driver?
        if (digi_card == DIGI_NONE)
            ts_fatal("_sound_init: error loading sound driver");

        // set the flag
        _sound_flag = 1;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Sound driver loaded\n");
        atexit(_sound_exit);
    }
}


void _sound_exit()
{
    // execute only if sound was running
    if (_sound_flag) {
        _sound_flag = 0;
        remove_sound();
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Sound driver removed.\n");
    }
}

// -----------------------------------------------------------------------
// sound2 init & exit functions
void _snd2_init()
{
    if (_sound_flag)
        ts_fatal("_snd2_init: old sound system is already running.\n") ;

    if (!_snd2_flag) {
        // initialize sound driver
        int err;    
        err = Pa_Initialize();
        if(err) 
            ts_fatal(Pa_GetErrorText( err ));
            
        // set the flag
        _snd2_flag=1;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Sound2 driver loaded\n");
        
        atexit(_snd2_exit);
    }
}

void _snd2_exit()
{
    if (_snd2_flag) {
        Pa_Terminate();   
        _snd2_flag=0;
        if (_debug_flag > DEBUG1)
            fprintf(stderr, "Sound driver removed.\n");
    }
}




// -----------------------------------------------------------------------
// helper functions for reading configuration files

int _readcfg(int nval, char **names, char *input)
{
    int i;
    for (i = 0; i < nval; i++)
        if (!strcmp(input, names[i]))
            return i;
    return -1;
}

int _setcfg(char *file)
{
    if (!_tscope_flag)
        _tscope_init();

    FILE *test;
    test = fopen(file, "r");
    if (!test) {
        ts_fatal("Unable to load ini file %s\n", file);
    }
    fclose(test);

    set_config_file(file);
    return 0;
}


top
Persoonlijke pagina Universiteit GentTscope
Allegro | Cygwin | Gcc
© See license.html for copyright information