From 6b45d9b2ad6214c811d1ba128c65096ce525b36f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 1 Oct 2013 15:55:10 -0700 Subject: [PATCH] SCP/VIDEO: Added support for libSDL2 video capabilities. Changed existing video layer to carry pixels as 32bpp vs 8bpp for more natural behaviors in libSDL2. --- VAX/vax_vc.c | 10 +- Visual Studio Projects/0ReadMe_Projects.txt | 2 +- Visual Studio Projects/MicroVAX1.vcproj | 14 +- Visual Studio Projects/MicroVAX2.vcproj | 14 +- Visual Studio Projects/Pre-Build-Event.cmd | 2 +- Visual Studio Projects/VAX.vcproj | 2 +- Visual Studio Projects/VAX730.vcproj | 2 +- Visual Studio Projects/VAX750.vcproj | 2 +- Visual Studio Projects/VAX780.vcproj | 2 +- Visual Studio Projects/VAX8600.vcproj | 2 +- Visual Studio Projects/rtVAX1000.vcproj | 2 +- makefile | 26 +- scp.c | 3 - sim_video.c | 933 ++++++++++++++++++-- sim_video.h | 3 +- 15 files changed, 926 insertions(+), 93 deletions(-) diff --git a/VAX/vax_vc.c b/VAX/vax_vc.c index d5a13222..4c6e497e 100644 --- a/VAX/vax_vc.c +++ b/VAX/vax_vc.c @@ -711,7 +711,7 @@ return 0; /* no intr req */ t_stat vc_svc (UNIT *uptr) { t_bool updated = FALSE; /* flag for refresh */ -uint8 line[1024]; +uint32 line[1024]; uint32 ln, col, off; uint8 *cur; @@ -741,7 +741,8 @@ for (ln = 0; ln < VC_YSIZE; ln++) { if ((vc_map[ln] & VCMAP_VLD) == 0) { /* line invalid? */ off = vc_map[ln] * 32; /* get video buf offet */ for (col = 0; col < 1024; col++) - line[col] = (vc_buf[off + (col >> 5)] >> col) & 1; /* 1bpp to 8bpp */ + line[col] = vid_mono_palette[(vc_buf[off + (col >> 5)] >> (col & 0x1F)) & 1]; + /* 1bpp to 32bpp */ if (CUR_V) { /* cursor visible? */ if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */ cur = &vc_cur[((ln - CUR_Y) << 4)]; /* get image base */ @@ -749,10 +750,9 @@ for (ln = 0; ln < VC_YSIZE; ln++) { if ((CUR_X + col) >= 1024) /* Part of cursor off screen? */ continue; /* Skip */ if (CUR_F) /* mask function */ - line[CUR_X + col] = line[CUR_X + col] | cur[col]; + line[CUR_X + col] = vid_mono_palette[(line[CUR_X + col] == vid_mono_palette[1]) | (cur[col] & 1)]; else - line[CUR_X + col] = line[CUR_X + col] & ~cur[col]; - line [CUR_X + col] = line[CUR_X + col] & 1; + line[CUR_X + col] = vid_mono_palette[(line[CUR_X + col] == vid_mono_palette[1]) & (~cur[col] & 1)]; } } } diff --git a/Visual Studio Projects/0ReadMe_Projects.txt b/Visual Studio Projects/0ReadMe_Projects.txt index c892c0b6..3dc0ddde 100644 --- a/Visual Studio Projects/0ReadMe_Projects.txt +++ b/Visual Studio Projects/0ReadMe_Projects.txt @@ -18,7 +18,7 @@ For Example, the directory structure should look like: .../simh/simhv38-2-rc1/BIN/Nt/Win32-Release/vax.exe .../simh/windows-build/pthreads/pthread.h .../simh/windows-build/winpcap/WpdPack/Include/pcap.h - .../simh/windows-build/libSDL/SDL-1.2.15/include/SDL.h + .../simh/windows-build/libSDL/SDL2-2.0.0/include/SDL.h The contents of the windows-build directory can be downloaded from: diff --git a/Visual Studio Projects/MicroVAX1.vcproj b/Visual Studio Projects/MicroVAX1.vcproj index 23f284c6..fb60e3da 100644 --- a/Visual Studio Projects/MicroVAX1.vcproj +++ b/Visual Studio Projects/MicroVAX1.vcproj @@ -44,7 +44,7 @@ -#if defined(HAVE_LIBSDL) && defined(USE_SIM_VIDEO) /* SDL (Simple DirectMedial Layer) */ -#include -#endif #if defined(HAVE_DLOPEN) /* Dynamic Readline support */ #include #endif diff --git a/sim_video.c b/sim_video.c index 5d6bfc2f..2bb8fe88 100644 --- a/sim_video.c +++ b/sim_video.c @@ -61,6 +61,19 @@ typedef struct { int vid_thread (void* arg); +/* + Currently there are two separate video implementations which exist + due to the fact that libSDL and libSDL2 provide vastly different APIs. + + libSDL2 is the distinctly better choice going forward, and, given the + background thread event digestion, is the only one which will work on + OSX. + + We will abandon libSDL (Version 1) completely when the libSDL2 developer + components are readily packaged for most Linux distributions. + */ + +#if SDL_MAJOR_VERSION == 1 t_bool vid_key_state[SDLK_LAST]; t_bool vid_mouse_captured; int32 vid_width; @@ -68,7 +81,7 @@ int32 vid_height; SDL_Surface *vid_image; /* video buffer */ SDL_Surface *vid_window; /* window handle */ SDL_Thread *vid_thread_handle; /* event thread handle */ -SDL_Color vid_palette[256]; +uint32 vid_mono_palette[2]; KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ DEVICE *vid_dev; @@ -166,20 +179,15 @@ if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { return SCPE_EOF; } -void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf) +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) { -int32 i, j; -uint8* pix; +int32 i; +uint32* pixels; -pix = (uint8 *)vid_image->pixels; -pix = pix + (y * vid_width) + x; +pixels = (uint32 *)vid_image->pixels; -for (i = y; i < (y + h); i++) { - for (j = x; j < (x + w); j++) { - *pix++ = *buf++; - } - pix = pix + vid_width; - } +for (i = y; i < (y + h); i++) + memcpy (pixels + (i * vid_width) + x, buf, (size_t)w*sizeof(*pixels)); } void vid_refresh (void) @@ -686,38 +694,38 @@ int vid_thread (void* arg) { SDL_Event event; static char *eventtypes[] = { - "NOEVENT", /**< Unused (do not remove) */ - "ACTIVEEVENT", /**< Application loses/gains visibility */ - "KEYDOWN", /**< Keys pressed */ - "KEYUP", /**< Keys released */ - "MOUSEMOTION", /**< Mouse moved */ - "MOUSEBUTTONDOWN", /**< Mouse button pressed */ - "MOUSEBUTTONUP", /**< Mouse button released */ - "JOYAXISMOTION", /**< Joystick axis motion */ - "JOYBALLMOTION", /**< Joystick trackball motion */ - "JOYHATMOTION", /**< Joystick hat position change */ - "JOYBUTTONDOWN", /**< Joystick button pressed */ - "JOYBUTTONUP", /**< Joystick button released */ - "QUIT", /**< User-requested quit */ - "SYSWMEVENT", /**< System specific event */ - "EVENT_RESERVEDA", /**< Reserved for future use.. */ - "EVENT_RESERVEDB", /**< Reserved for future use.. */ - "VIDEORESIZE", /**< User resized video mode */ - "VIDEOEXPOSE", /**< Screen needs to be redrawn */ - "EVENT_RESERVED2", /**< Reserved for future use.. */ - "EVENT_RESERVED3", /**< Reserved for future use.. */ - "EVENT_RESERVED4", /**< Reserved for future use.. */ - "EVENT_RESERVED5", /**< Reserved for future use.. */ - "EVENT_RESERVED6", /**< Reserved for future use.. */ - "EVENT_RESERVED7", /**< Reserved for future use.. */ - "USEREVENT", /** Events SDL_USEREVENT(24) through SDL_MAXEVENTS-1(31) are for your use */ - "", - "", - "", - "", - "", - "", - "" + "NOEVENT", /**< Unused (do not remove) */ + "ACTIVEEVENT", /**< Application loses/gains visibility */ + "KEYDOWN", /**< Keys pressed */ + "KEYUP", /**< Keys released */ + "MOUSEMOTION", /**< Mouse moved */ + "MOUSEBUTTONDOWN", /**< Mouse button pressed */ + "MOUSEBUTTONUP", /**< Mouse button released */ + "JOYAXISMOTION", /**< Joystick axis motion */ + "JOYBALLMOTION", /**< Joystick trackball motion */ + "JOYHATMOTION", /**< Joystick hat position change */ + "JOYBUTTONDOWN", /**< Joystick button pressed */ + "JOYBUTTONUP", /**< Joystick button released */ + "QUIT", /**< User-requested quit */ + "SYSWMEVENT", /**< System specific event */ + "EVENT_RESERVEDA", /**< Reserved for future use.. */ + "EVENT_RESERVEDB", /**< Reserved for future use.. */ + "VIDEORESIZE", /**< User resized video mode */ + "VIDEOEXPOSE", /**< Screen needs to be redrawn */ + "EVENT_RESERVED2", /**< Reserved for future use.. */ + "EVENT_RESERVED3", /**< Reserved for future use.. */ + "EVENT_RESERVED4", /**< Reserved for future use.. */ + "EVENT_RESERVED5", /**< Reserved for future use.. */ + "EVENT_RESERVED6", /**< Reserved for future use.. */ + "EVENT_RESERVED7", /**< Reserved for future use.. */ + "USEREVENT", /** Events SDL_USEREVENT(24) through SDL_MAXEVENTS-1(31) are for your use */ + "", + "", + "", + "", + "", + "", + "" }; sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Starting\n"); @@ -728,15 +736,14 @@ vid_window = SDL_SetVideoMode (vid_width, vid_height, 8, 0); SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); -vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 8, 0, 0, 0, 0); +if (sim_end) + vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); +else + vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + +vid_mono_palette[0] = sim_end ? 0xFF000000 : 0x000000FF; +vid_mono_palette[1] = 0xFFFFFFFF; -vid_palette[0].r = 0; -vid_palette[0].g = 0; -vid_palette[0].b = 0; -vid_palette[1].r = 255; -vid_palette[1].g = 255; -vid_palette[1].b = 255; -SDL_SetColors (vid_image, vid_palette, 0, 2); SDL_WM_SetCaption (&sim_name[0], &sim_name[0]); @@ -777,13 +784,827 @@ SDL_Quit (); sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Exiting\n"); return 0; } +#else /* libSDL2 implementation */ +t_bool vid_key_state[SDL_NUM_SCANCODES]; +t_bool vid_mouse_captured; +int32 vid_width; +int32 vid_height; +SDL_Texture *vid_texture; /* video buffer in GPU */ +SDL_Window *vid_window; /* window handle */ +SDL_Renderer *vid_renderer; +SDL_Thread *vid_thread_handle; /* event thread handle */ +uint32 vid_mono_palette[2]; /* Monochrome Color Map */ +SDL_Color vid_colors[256]; +KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ +MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ +DEVICE *vid_dev; + +t_stat vid_open (DEVICE *dptr, uint32 width, uint32 height) +{ +if (!vid_active) { + int wait_count = 0; + + vid_active = TRUE; + vid_width = width; + vid_height = height; + vid_mouse_captured = FALSE; + + vid_key_events.head = 0; + vid_key_events.tail = 0; + vid_key_events.count = 0; + vid_key_events.sem = SDL_CreateSemaphore (1); + vid_mouse_events.head = 0; + vid_mouse_events.tail = 0; + vid_mouse_events.count = 0; + vid_mouse_events.sem = SDL_CreateSemaphore (1); + + vid_dev = dptr; + + vid_thread_handle = SDL_CreateThread (vid_thread, "vid-thread", NULL); + if (vid_thread_handle == NULL) { + vid_close (); + return SCPE_OPENERR; + } + while ((!vid_texture) && (++wait_count < 20)) + sim_os_ms_sleep (100); + if (!vid_texture) { + vid_close (); + return SCPE_OPENERR; + } + + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n"); + } +return SCPE_OK; +} + +t_stat vid_close (void) +{ +SDL_Event user_event; +int status; + +if (vid_active) { + vid_active = FALSE; + if (vid_thread_handle) { + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n"); + user_event.type = SDL_USEREVENT; + user_event.user.code = EVENT_CLOSE; + user_event.user.data1 = NULL; + user_event.user.data2 = NULL; + + SDL_PushEvent (&user_event); + SDL_WaitThread (vid_thread_handle, &status); + vid_thread_handle = NULL; + vid_dev = NULL; + } + if (vid_mouse_events.sem) { + SDL_DestroySemaphore(vid_mouse_events.sem); + vid_mouse_events.sem = NULL; + } + if (vid_key_events.sem) { + SDL_DestroySemaphore(vid_key_events.sem); + vid_key_events.sem = NULL; + } + } +return SCPE_OK; +} + +t_stat vid_poll_kb (SIM_KEY_EVENT *ev) +{ +if (SDL_SemTryWait (vid_key_events.sem) == 0) { /* get lock */ + if (vid_key_events.count > 0) { /* events in queue? */ + *ev = vid_key_events.events[vid_key_events.head++]; + vid_key_events.count--; + if (vid_key_events.head == MAX_EVENTS) + vid_key_events.head = 0; + SDL_SemPost (vid_key_events.sem); + return SCPE_OK; + } + SDL_SemPost (vid_key_events.sem); + } +return SCPE_EOF; +} + +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) +{ +if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count > 0) { + *ev = vid_mouse_events.events[vid_mouse_events.head++]; + vid_mouse_events.count--; + if (vid_mouse_events.head == MAX_EVENTS) + vid_mouse_events.head = 0; + SDL_SemPost (vid_mouse_events.sem); + return SCPE_OK; + } + SDL_SemPost (vid_mouse_events.sem); + } +return SCPE_EOF; +} + +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) +{ +int32 i; +uint32 *pixels; +int pitch; + +SDL_LockTexture(vid_texture, NULL, (void *)&pixels, &pitch); + +for (i = y; i < (y + h); i++) + memcpy (pixels + (i * vid_width) + x, buf, (size_t)w*sizeof(*pixels)); +SDL_UnlockTexture(vid_texture); +} + +void vid_refresh (void) +{ +SDL_Event user_event; + +user_event.type = SDL_USEREVENT; +user_event.user.code = EVENT_REDRAW; +user_event.user.data1 = NULL; +user_event.user.data2 = NULL; + +SDL_PushEvent (&user_event); +} + +int vid_map_key (int key) +{ +switch (key) { + + case SDLK_BACKSPACE: + return SIM_KEY_BACKSPACE; + + case SDLK_TAB: + return SIM_KEY_TAB; + + case SDLK_RETURN: + return SIM_KEY_ENTER; + + case SDLK_ESCAPE: + return SIM_KEY_ESC; + + case SDLK_SPACE: + return SIM_KEY_SPACE; + + case SDLK_QUOTE: + return SIM_KEY_SINGLE_QUOTE; + + case SDLK_COMMA: + return SIM_KEY_COMMA; + + case SDLK_MINUS: + return SIM_KEY_MINUS; + + case SDLK_PERIOD: + return SIM_KEY_PERIOD; + + case SDLK_SLASH: + return SIM_KEY_SLASH; + + case SDLK_0: + return SIM_KEY_0; + + case SDLK_1: + return SIM_KEY_1; + + case SDLK_2: + return SIM_KEY_2; + + case SDLK_3: + return SIM_KEY_3; + + case SDLK_4: + return SIM_KEY_4; + + case SDLK_5: + return SIM_KEY_5; + + case SDLK_6: + return SIM_KEY_6; + + case SDLK_7: + return SIM_KEY_7; + + case SDLK_8: + return SIM_KEY_8; + + case SDLK_9: + return SIM_KEY_9; + + case SDLK_SEMICOLON: + return SIM_KEY_SEMICOLON; + + case SDLK_EQUALS: + return SIM_KEY_EQUALS; + + case SDLK_LEFTBRACKET: + return SIM_KEY_LEFT_BRACKET; + + case SDLK_BACKSLASH: + return SIM_KEY_BACKSLASH; + + case SDLK_RIGHTBRACKET: + return SIM_KEY_RIGHT_BRACKET; + + case SDLK_BACKQUOTE: + return SIM_KEY_BACKQUOTE; + + case SDLK_a: + return SIM_KEY_A; + + case SDLK_b: + return SIM_KEY_B; + + case SDLK_c: + return SIM_KEY_C; + + case SDLK_d: + return SIM_KEY_D; + + case SDLK_e: + return SIM_KEY_E; + + case SDLK_f: + return SIM_KEY_F; + + case SDLK_g: + return SIM_KEY_G; + + case SDLK_h: + return SIM_KEY_H; + + case SDLK_i: + return SIM_KEY_I; + + case SDLK_j: + return SIM_KEY_J; + + case SDLK_k: + return SIM_KEY_K; + + case SDLK_l: + return SIM_KEY_L; + + case SDLK_m: + return SIM_KEY_M; + + case SDLK_n: + return SIM_KEY_N; + + case SDLK_o: + return SIM_KEY_O; + + case SDLK_p: + return SIM_KEY_P; + + case SDLK_q: + return SIM_KEY_Q; + + case SDLK_r: + return SIM_KEY_R; + + case SDLK_s: + return SIM_KEY_S; + + case SDLK_t: + return SIM_KEY_T; + + case SDLK_u: + return SIM_KEY_U; + + case SDLK_v: + return SIM_KEY_V; + + case SDLK_w: + return SIM_KEY_W; + + case SDLK_x: + return SIM_KEY_X; + + case SDLK_y: + return SIM_KEY_Y; + + case SDLK_z: + return SIM_KEY_Z; + + case SDLK_DELETE: + return SIM_KEY_DELETE; + + case SDLK_KP_0: + return SIM_KEY_KP_INSERT; + + case SDLK_KP_1: + return SIM_KEY_KP_END; + + case SDLK_KP_2: + return SIM_KEY_KP_DOWN; + + case SDLK_KP_3: + return SIM_KEY_KP_PAGE_DOWN; + + case SDLK_KP_4: + return SIM_KEY_KP_LEFT; + + case SDLK_KP_5: + return SIM_KEY_KP_5; + + case SDLK_KP_6: + return SIM_KEY_KP_RIGHT; + + case SDLK_KP_7: + return SIM_KEY_KP_HOME; + + case SDLK_KP_8: + return SIM_KEY_KP_UP; + + case SDLK_KP_9: + return SIM_KEY_KP_PAGE_UP; + + case SDLK_KP_PERIOD: + return SIM_KEY_KP_DELETE; + + case SDLK_KP_DIVIDE: + return SIM_KEY_KP_DIVIDE; + + case SDLK_KP_MULTIPLY: + return SIM_KEY_KP_MULTIPLY; + + case SDLK_KP_MINUS: + return SIM_KEY_KP_SUBTRACT; + + case SDLK_KP_PLUS: + return SIM_KEY_KP_ADD; + + case SDLK_KP_ENTER: + return SIM_KEY_KP_ENTER; + + case SDLK_UP: + return SIM_KEY_UP; + + case SDLK_DOWN: + return SIM_KEY_DOWN; + + case SDLK_RIGHT: + return SIM_KEY_RIGHT; + + case SDLK_LEFT: + return SIM_KEY_LEFT; + + case SDLK_INSERT: + return SIM_KEY_INSERT; + + case SDLK_HOME: + return SIM_KEY_HOME; + + case SDLK_END: + return SIM_KEY_END; + + case SDLK_PAGEUP: + return SIM_KEY_PAGE_UP; + + case SDLK_PAGEDOWN: + return SIM_KEY_PAGE_DOWN; + + case SDLK_F1: + return SIM_KEY_F1; + + case SDLK_F2: + return SIM_KEY_F2; + + case SDLK_F3: + return SIM_KEY_F3; + + case SDLK_F4: + return SIM_KEY_F4; + + case SDLK_F5: + return SIM_KEY_F5; + + case SDLK_F6: + return SIM_KEY_F6; + + case SDLK_F7: + return SIM_KEY_F7; + + case SDLK_F8: + return SIM_KEY_F8; + + case SDLK_F9: + return SIM_KEY_F9; + + case SDLK_F10: + return SIM_KEY_F10; + + case SDLK_F11: + return SIM_KEY_F11; + + case SDLK_F12: + return SIM_KEY_F12; + + case SDLK_NUMLOCKCLEAR: + return SIM_KEY_NUM_LOCK; + + case SDLK_CAPSLOCK: + return SIM_KEY_CAPS_LOCK; + + case SDLK_SCROLLLOCK: + return SIM_KEY_SCRL_LOCK; + + case SDLK_RSHIFT: + return SIM_KEY_SHIFT_R; + + case SDLK_LSHIFT: + return SIM_KEY_SHIFT_L; + + case SDLK_RCTRL: + return SIM_KEY_CTRL_R; + + case SDLK_LCTRL: + return SIM_KEY_CTRL_L; + + case SDLK_RALT: + return SIM_KEY_ALT_R; + + case SDLK_LALT: + return SIM_KEY_ALT_L; + + case SDLK_LGUI: + return SIM_KEY_WIN_L; + + case SDLK_RGUI: + return SIM_KEY_WIN_R; + + case SDLK_PRINTSCREEN: + return SIM_KEY_PRINT; + + case SDLK_PAUSE: + return SIM_KEY_PAUSE; + + case SDLK_MENU: + return SIM_KEY_MENU; + + default: + return SIM_KEY_UNKNOWN; + } +} + +void vid_key (SDL_KeyboardEvent *event) +{ +SIM_KEY_EVENT ev; + +if (vid_mouse_captured) { + static const Uint8 *KeyStates = NULL; + static int numkeys; + + if (!KeyStates) + KeyStates = SDL_GetKeyboardState(&numkeys); + if ((event->state == SDL_PRESSED) && KeyStates[SDL_SCANCODE_RSHIFT] && (KeyStates[SDL_SCANCODE_LCTRL] || KeyStates[SDL_SCANCODE_RCTRL])) { + sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_key() - Cursor Release\n"); + SDL_SetRelativeMouseMode(SDL_FALSE); /* release cursor, show cursor */ + vid_mouse_captured = FALSE; + return; + } + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_key_events.sem) == 0) { + sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event: State: %d, Keysym: %d\n", event->state, event->keysym); + if (vid_key_events.count < MAX_EVENTS) { + if (event->state == SDL_PRESSED) { + if (!vid_key_state[event->keysym.sym]) { /* Key was not down before */ + vid_key_state[event->keysym.sym] = TRUE; + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_DOWN; + } + else { + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_REPEAT; + } + } + else { + vid_key_state[event->keysym.sym] = FALSE; + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_UP; + } + vid_key_events.events[vid_key_events.tail++] = ev; + vid_key_events.count++; + if (vid_key_events.tail == MAX_EVENTS) + vid_key_events.tail = 0; + } + SDL_SemPost (vid_key_events.sem); + } +} + +void vid_mouse_move (SDL_MouseMotionEvent *event) +{ +SDL_Event dummy_event; +int32 cx; +int32 cy; +SIM_MOUSE_EVENT ev; + +if (!vid_mouse_captured) + return; + +if ((event->x == 0) || + (event->y == 0) || + (event->x == (vid_width - 1)) || + (event->y == (vid_height - 1))) { /* reached edge of window? */ + cx = vid_width / 2; + cy = vid_height / 2; + SDL_WarpMouseInWindow (NULL, cx, cy); /* back to centre */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {}; + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_mouse_events.sem) == 0) { + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: (%d,%d)\n", event->xrel, event->yrel); + if (vid_mouse_events.count < MAX_EVENTS) { + ev.x_rel = event->xrel; + ev.y_rel = (-event->yrel); + ev.b1_state = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; + ev.b2_state = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; + ev.b3_state = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; + vid_mouse_events.b1_state = ev.b1_state; + vid_mouse_events.b2_state = ev.b2_state; + vid_mouse_events.b3_state = ev.b3_state; + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } + SDL_SemPost (vid_mouse_events.sem); + } +} + +void vid_mouse_button (SDL_MouseButtonEvent *event) +{ +SDL_Event dummy_event; +int32 cx; +int32 cy; +SIM_MOUSE_EVENT ev; +t_bool state; + +if (!vid_mouse_captured) { + if ((event->state == SDL_PRESSED) && + (event->button == SDL_BUTTON_LEFT)) { /* left click and cursor not captured? */ + sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_mouse_button() - Cursor Captured\n"); + SDL_SetRelativeMouseMode(SDL_TRUE); /* lock cursor to window, hide cursor */ + cx = vid_width / 2; + cy = vid_height / 2; + SDL_WarpMouseInWindow (NULL, cx, cy); /* back to centre */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {}; + vid_mouse_captured = TRUE; + } + return; + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_mouse_events.sem) == 0) { + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event: State: %d, Button: %d, (%d,%d)\n", event->state, event->button, event->x, event->y); + if (vid_mouse_events.count < MAX_EVENTS) { + state = (event->state == SDL_PRESSED) ? TRUE : FALSE; + ev.x_rel = 0; + ev.y_rel = 0; + switch (event->button) { + case SDL_BUTTON_LEFT: + vid_mouse_events.b1_state = state; + break; + case SDL_BUTTON_MIDDLE: + vid_mouse_events.b2_state = state; + break; + case SDL_BUTTON_RIGHT: + vid_mouse_events.b3_state = state; + break; + } + ev.b1_state = vid_mouse_events.b1_state; + ev.b2_state = vid_mouse_events.b2_state; + ev.b3_state = vid_mouse_events.b3_state; + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } + SDL_SemPost (vid_mouse_events.sem); + } +} + +void vid_update (void) +{ +SDL_Rect vid_dst; + +vid_dst.x = 0; +vid_dst.y = 0; +vid_dst.w = vid_width; +vid_dst.h = vid_height; + +sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: \n"); +SDL_RenderClear(vid_renderer); +SDL_RenderCopy(vid_renderer, vid_texture, NULL, NULL); +SDL_RenderPresent(vid_renderer); +} + +int vid_thread (void* arg) +{ +SDL_Event event; +static char *eventtypes[SDL_LASTEVENT]; +static t_bool initialized = FALSE; + +if (!initialized) { + initialized = TRUE; + eventtypes[SDL_QUIT] = "QUIT"; /**< User-requested quit */ + + /* These application events have special meaning on iOS, see README-ios.txt for details */ + eventtypes[SDL_APP_TERMINATING] = "APP_TERMINATING"; /**< The application is being terminated by the OS + Called on iOS in applicationWillTerminate() + Called on Android in onDestroy() + */ + eventtypes[SDL_APP_LOWMEMORY] = "APP_LOWMEMORY"; /**< The application is low on memory, free memory if possible. + Called on iOS in applicationDidReceiveMemoryWarning() + Called on Android in onLowMemory() + */ + eventtypes[SDL_APP_WILLENTERBACKGROUND] = "APP_WILLENTERBACKGROUND"; /**< The application is about to enter the background + Called on iOS in applicationWillResignActive() + Called on Android in onPause() + */ + eventtypes[SDL_APP_DIDENTERBACKGROUND] = "APP_DIDENTERBACKGROUND"; /**< The application did enter the background and may not get CPU for some time + Called on iOS in applicationDidEnterBackground() + Called on Android in onPause() + */ + eventtypes[SDL_APP_WILLENTERFOREGROUND] = "APP_WILLENTERFOREGROUND"; /**< The application is about to enter the foreground + Called on iOS in applicationWillEnterForeground() + Called on Android in onResume() + */ + eventtypes[SDL_APP_DIDENTERFOREGROUND] = "APP_DIDENTERFOREGROUND"; /**< The application is now interactive + Called on iOS in applicationDidBecomeActive() + Called on Android in onResume() + */ + + /* Window events */ + eventtypes[SDL_WINDOWEVENT] = "WINDOWEVENT"; /**< Window state change */ + eventtypes[SDL_SYSWMEVENT] = "SYSWMEVENT"; /**< System specific event */ + + /* Keyboard events */ + eventtypes[SDL_KEYDOWN] = "KEYDOWN"; /**< Key pressed */ + eventtypes[SDL_KEYUP] = "KEYUP"; /**< Key released */ + eventtypes[SDL_TEXTEDITING] = "TEXTEDITING"; /**< Keyboard text editing (composition) */ + eventtypes[SDL_TEXTINPUT] = "TEXTINPUT"; /**< Keyboard text input */ + + /* Mouse events */ + eventtypes[SDL_MOUSEMOTION] = "MOUSEMOTION"; /**< Mouse moved */ + eventtypes[SDL_MOUSEBUTTONDOWN] = "MOUSEBUTTONDOWN"; /**< Mouse button pressed */ + eventtypes[SDL_MOUSEBUTTONUP] = "MOUSEBUTTONUP"; /**< Mouse button released */ + eventtypes[SDL_MOUSEWHEEL] = "MOUSEWHEEL"; /**< Mouse wheel motion */ + + /* Joystick events */ + eventtypes[SDL_JOYAXISMOTION] = "JOYAXISMOTION"; /**< Joystick axis motion */ + eventtypes[SDL_JOYBALLMOTION] = "JOYBALLMOTION"; /**< Joystick trackball motion */ + eventtypes[SDL_JOYHATMOTION] = "JOYHATMOTION"; /**< Joystick hat position change */ + eventtypes[SDL_JOYBUTTONDOWN] = "JOYBUTTONDOWN"; /**< Joystick button pressed */ + eventtypes[SDL_JOYBUTTONUP] = "JOYBUTTONUP"; /**< Joystick button released */ + eventtypes[SDL_JOYDEVICEADDED] = "JOYDEVICEADDED"; /**< A new joystick has been inserted into the system */ + eventtypes[SDL_JOYDEVICEREMOVED] = "JOYDEVICEREMOVED"; /**< An opened joystick has been removed */ + + /* Game controller events */ + eventtypes[SDL_CONTROLLERAXISMOTION] = "CONTROLLERAXISMOTION"; /**< Game controller axis motion */ + eventtypes[SDL_CONTROLLERBUTTONDOWN] = "CONTROLLERBUTTONDOWN"; /**< Game controller button pressed */ + eventtypes[SDL_CONTROLLERBUTTONUP] = "CONTROLLERBUTTONUP"; /**< Game controller button released */ + eventtypes[SDL_CONTROLLERDEVICEADDED] = "CONTROLLERDEVICEADDED"; /**< A new Game controller has been inserted into the system */ + eventtypes[SDL_CONTROLLERDEVICEREMOVED] = "CONTROLLERDEVICEREMOVED"; /**< An opened Game controller has been removed */ + eventtypes[SDL_CONTROLLERDEVICEREMAPPED] = "CONTROLLERDEVICEREMAPPED"; /**< The controller mapping was updated */ + + /* Touch events */ + eventtypes[SDL_FINGERDOWN] = "FINGERDOWN"; + eventtypes[SDL_FINGERUP] = "FINGERUP"; + eventtypes[SDL_FINGERMOTION] = "FINGERMOTION"; + + /* Gesture events */ + eventtypes[SDL_DOLLARGESTURE] = "DOLLARGESTURE"; + eventtypes[SDL_DOLLARRECORD] = "DOLLARRECORD"; + eventtypes[SDL_MULTIGESTURE] = "MULTIGESTURE"; + + /* Clipboard events */ + eventtypes[SDL_CLIPBOARDUPDATE] = "CLIPBOARDUPDATE"; /**< The clipboard changed */ + + /* Drag and drop events */ + eventtypes[SDL_DROPFILE] = "DROPFILE"; /**< The system requests a file open */ + + /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use, + * and should be allocated with SDL_RegisterEvents() + */ + eventtypes[SDL_USEREVENT] = "USEREVENT"; + + } + +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Starting\n"); + +vid_mono_palette[0] = sim_end ? 0xFF000000 : 0x000000FF; +vid_mono_palette[1] = 0xFFFFFFFF; + +memset (&vid_key_state, 0, sizeof(vid_key_state)); + +SDL_Init (SDL_INIT_VIDEO); + +SDL_CreateWindowAndRenderer (vid_width, vid_height, SDL_WINDOW_SHOWN, &vid_window, &vid_renderer); + +if ((vid_window == NULL) || (vid_renderer == NULL)) { + printf ("%s: Error Creating Video Window: %s\b", sim_dname(vid_dev), SDL_GetError()); + if (sim_log) + fprintf (sim_log, "%s: Error Creating Video Window: %s\b", sim_dname(vid_dev), SDL_GetError()); + SDL_Quit (); + return 0; + } + +SDL_SetRenderDrawColor (vid_renderer, 0, 0, 0, 255); +SDL_RenderClear (vid_renderer); +SDL_RenderPresent (vid_renderer); + +vid_texture = SDL_CreateTexture (vid_renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + vid_width, vid_height); +if (!vid_texture) { + printf ("%s: Error configuring Video environment: %s\b", sim_dname(vid_dev), SDL_GetError()); + if (sim_log) + fprintf (sim_log, "%s: Error configuring Video environment: %s\b", sim_dname(vid_dev), SDL_GetError()); + SDL_DestroyRenderer(vid_renderer); + vid_renderer = NULL; + SDL_DestroyWindow(vid_window); + vid_window = NULL; + SDL_Quit (); + return 0; + } + +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Started\n"); + +while (vid_active) { + if (SDL_WaitEvent (&event)) { + switch (event.type) { + + case SDL_KEYDOWN: + case SDL_KEYUP: + vid_key ((SDL_KeyboardEvent*)&event); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + vid_mouse_button ((SDL_MouseButtonEvent*)&event); + break; + + case SDL_MOUSEMOTION: + vid_mouse_move ((SDL_MouseMotionEvent*)&event); + break; + + case SDL_USEREVENT: + /* There are 2 user events generated */ + /* EVENT_REDRAW to update the display */ + /* EVENT_CLOSE to wake up this thread and let */ + /* it notice vid_active has changed */ + if (event.user.code == EVENT_REDRAW) + vid_update (); + break; + + default: + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type); + break; + } + } + } +SDL_DestroyTexture(vid_texture); +vid_texture = NULL; +SDL_DestroyRenderer(vid_renderer); +vid_renderer = NULL; +SDL_DestroyWindow(vid_window); +vid_window = NULL; +SDL_Quit (); +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Exiting\n"); +return 0; +} +#endif /* libSDL2 implementation */ const char *vid_version(void) { static char SDLVersion[80]; -const SDL_version *ver = SDL_Linked_Version(); +SDL_version compiled, running; -sprintf(SDLVersion, "SDL Version %d.%d.%d", ver->major, ver->minor, ver->patch); +#if SDL_MAJOR_VERSION == 1 +const SDL_version *ver = SDL_Linked_Version(); +running.major = ver->major; +running.minor = ver->minor; +running.patch = ver->patch; +#else +SDL_GetVersion(&running); +#endif +SDL_VERSION(&compiled); + +if ((compiled.major == running.major) && + (compiled.minor == running.minor) && + (compiled.patch == running.patch)) + sprintf(SDLVersion, "SDL Version %d.%d.%d", + compiled.major, compiled.minor, compiled.patch); +else + sprintf(SDLVersion, "SDL Version (Compiled: %d.%d.%d, Runtime: %d.%d.%d)", + compiled.major, compiled.minor, compiled.patch, + running.major, running.minor, running.patch); return (const char *)SDLVersion; } @@ -802,6 +1623,8 @@ return SCPE_OK; /* Non-implemented versions */ +uint32 vid_mono_palette[2]; /* Monochrome Color Map */ + t_stat vid_open (DEVICE *dptr, uint32 width, uint32 height) { return SCPE_NOFNC; @@ -822,7 +1645,7 @@ t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) return SCPE_EOF; } -void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf) +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) { return; } diff --git a/sim_video.h b/sim_video.h index cbaa6259..1c94c917 100644 --- a/sim_video.h +++ b/sim_video.h @@ -172,13 +172,14 @@ t_stat vid_open (DEVICE *dptr, uint32 width, uint32 height); t_stat vid_close (void); t_stat vid_poll_kb (SIM_KEY_EVENT *ev); t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev); -void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf); +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf); void vid_refresh (void); const char *vid_version (void); t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, void* desc); extern t_bool vid_active; +extern uint32 vid_mono_palette[2]; #define SIM_VID_DBG_MOUSE 0x01000000 #define SIM_VID_DBG_KEY 0x02000000