From a06035a35e44ec087867df36d45f0d6e85eb3e38 Mon Sep 17 00:00:00 2001 From: Patryk Obara Date: Sun, 22 Dec 2019 04:02:56 +0100 Subject: [PATCH] Replace SDL 1.2 with SDL 2.0 This massive patch is based on work of NY00123, which was published on Vogons forum in 2013 and was waiting for inclusion in SVN since then: https://www.vogons.org/viewtopic.php?f=41&t=34770 Revision from December 2018 was used to kickstart this work. However, a number of changes were implemented: - Original patch preserves all SDL 1.2 code by ifdefing it; this patch completely removes all code ifdefed for several versions of SDL 1.2.* This way the code will be easier to maintain going forward and features enabled by SDL 2.0 do not need to be backported. A side-effect of this change is almost-complete removal of DirectDraw support - but users can now use Direct3D based acceleration (without any ifdefs in code). - Code ifdefed for Android was removed to make the project easier to understand and modify. Android port should still be possible, but it requires more work (mostly CI and buildsystem work). Android-related functionalities that were cross-platform were preserved. - Code ifdefed for OpenGL ES (which was only used for Android) was removed - this should not affect Android support, as hardware-accelerated 2D should still be viable via "texture" output, but it was not tested, as buildsystem does not support Android ATM. - SDL_cdrom code is not included; it was outside of scope of SDL2 changes. Inclusion of that library did not justify supporting one small usecase (playblack of CD audio from physical CDs). - Few code warning were fixed (but new sdl_mapper implementation introduces many, many new warnings). - Some formatting changes were implemented. Overall, the original patch had ~40k lines of code - here it was trimmed to +769,-972 (so more old code got removed than new code added). This implementation was extensively tested on Linux and somewhat tested on Windows 10. It fixes numerous issues (too many too list). Testing found two small regressions: - Starting game in fullscreen makes it impossible to switch back to windowed mode correctly (Windows 10) - Scaling works a bit worse, only in text mode, only in window (Linux) This implementation introduces revised user settings in sdl section - it is only partly compatible with settings from SDL 1.2; this is an issue, but it will need to be addressed in a separete commit. --- src/gui/sdl_mapper.cpp | 564 ++++++------------ src/gui/sdlmain.cpp | 1098 ++++++++++++++++++------------------ src/hardware/mixer.cpp | 38 +- src/ints/bios_keyboard.cpp | 40 -- 4 files changed, 768 insertions(+), 972 deletions(-) diff --git a/src/gui/sdl_mapper.cpp b/src/gui/sdl_mapper.cpp index 821b6a85..21a8ca99 100644 --- a/src/gui/sdl_mapper.cpp +++ b/src/gui/sdl_mapper.cpp @@ -44,7 +44,8 @@ enum { CLR_WHITE=2, CLR_RED=3, CLR_BLUE=4, - CLR_GREEN=5 + CLR_GREEN=5, + CLR_LAST=6 }; enum BB_Types { @@ -67,7 +68,8 @@ enum BC_Types { #define MAXSTICKS 8 #define MAXACTIVE 16 -#define MAXBUTTON 32 +// Use 36 for Android (KEYCODE_BUTTON_1..16 are mapped to SDL buttons 20..35) +#define MAXBUTTON 36 #define MAXBUTTON_CAP 16 class CEvent; @@ -298,194 +300,22 @@ protected: }; - -#define MAX_SDLKEYS 323 - -static bool usescancodes; -static Bit8u scancode_map[MAX_SDLKEYS]; - -#define Z SDLK_UNKNOWN - -#if defined (MACOSX) -static SDLKey sdlkey_map[]={ - /* Main block printables */ - /*00-05*/ SDLK_a, SDLK_s, SDLK_d, SDLK_f, SDLK_h, SDLK_g, - /*06-0B*/ SDLK_z, SDLK_x, SDLK_c, SDLK_v, SDLK_WORLD_0, SDLK_b, - /*0C-11*/ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_y, SDLK_t, - /*12-17*/ SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_6, SDLK_5, - /*18-1D*/ SDLK_EQUALS, SDLK_9, SDLK_7, SDLK_MINUS, SDLK_8, SDLK_0, - /*1E-21*/ SDLK_RIGHTBRACKET, SDLK_o, SDLK_u, SDLK_LEFTBRACKET, - /*22-23*/ SDLK_i, SDLK_p, - /*24-29*/ SDLK_RETURN, SDLK_l, SDLK_j, SDLK_QUOTE, SDLK_k, SDLK_SEMICOLON, - /*2A-29*/ SDLK_BACKSLASH, SDLK_COMMA, SDLK_SLASH, SDLK_n, SDLK_m, - /*2F-2F*/ SDLK_PERIOD, - - /* Spaces, controls, modifiers (dosbox uses LMETA only for - * hotkeys, it's not really mapped to an emulated key) */ - /*30-33*/ SDLK_TAB, SDLK_SPACE, SDLK_BACKQUOTE, SDLK_BACKSPACE, - /*34-37*/ Z, SDLK_ESCAPE, Z, SDLK_LMETA, - /*38-3B*/ SDLK_LSHIFT, SDLK_CAPSLOCK, SDLK_LALT, SDLK_LCTRL, - - /*3C-40*/ Z, Z, Z, Z, Z, - - /* Keypad (KP_EQUALS not supported, NUMLOCK used on what is CLEAR - * in Mac OS X) */ - /*41-46*/ SDLK_KP_PERIOD, Z, SDLK_KP_MULTIPLY, Z, SDLK_KP_PLUS, Z, - /*47-4A*/ SDLK_NUMLOCK /*==SDLK_CLEAR*/, Z, Z, Z, - /*4B-4D*/ SDLK_KP_DIVIDE, SDLK_KP_ENTER, Z, - /*4E-51*/ SDLK_KP_MINUS, Z, Z, SDLK_KP_EQUALS, - /*52-57*/ SDLK_KP0, SDLK_KP1, SDLK_KP2, SDLK_KP3, SDLK_KP4, SDLK_KP5, - /*58-5C*/ SDLK_KP6, SDLK_KP7, Z, SDLK_KP8, SDLK_KP9, - - /*5D-5F*/ Z, Z, Z, - - /* Function keys and cursor blocks (F13 not supported, F14 => - * PRINT[SCREEN], F15 => SCROLLOCK, F16 => PAUSE, HELP => INSERT) */ - /*60-64*/ SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F3, SDLK_F8, - /*65-6A*/ SDLK_F9, Z, SDLK_F11, Z, SDLK_F13, SDLK_PAUSE /*==SDLK_F16*/, - /*6B-70*/ SDLK_PRINT /*==SDLK_F14*/, Z, SDLK_F10, Z, SDLK_F12, Z, - /*71-72*/ SDLK_SCROLLOCK /*==SDLK_F15*/, SDLK_INSERT /*==SDLK_HELP*/, - /*73-77*/ SDLK_HOME, SDLK_PAGEUP, SDLK_DELETE, SDLK_F4, SDLK_END, - /*78-7C*/ SDLK_F2, SDLK_PAGEDOWN, SDLK_F1, SDLK_LEFT, SDLK_RIGHT, - /*7D-7E*/ SDLK_DOWN, SDLK_UP, - - /*7F-7F*/ Z, - - /* 4 extra keys that don't really exist, but are needed for - * round-trip mapping (dosbox uses RMETA only for hotkeys, it's - * not really mapped to an emulated key) */ - SDLK_RMETA, SDLK_RSHIFT, SDLK_RALT, SDLK_RCTRL -}; -#define MAX_SCANCODES (0x80+4) -/* Make sure that the table above has the expected size. This - expression will raise a compiler error if the condition is false. */ -typedef char assert_right_size [MAX_SCANCODES == (sizeof(sdlkey_map)/sizeof(sdlkey_map[0])) ? 1 : -1]; - -#else // !MACOSX - -#define MAX_SCANCODES 0xdf -static SDLKey sdlkey_map[MAX_SCANCODES]={SDLK_UNKNOWN,SDLK_ESCAPE, - SDLK_1,SDLK_2,SDLK_3,SDLK_4,SDLK_5,SDLK_6,SDLK_7,SDLK_8,SDLK_9,SDLK_0, - /* 0x0c: */ - SDLK_MINUS,SDLK_EQUALS,SDLK_BACKSPACE,SDLK_TAB, - SDLK_q,SDLK_w,SDLK_e,SDLK_r,SDLK_t,SDLK_y,SDLK_u,SDLK_i,SDLK_o,SDLK_p, - SDLK_LEFTBRACKET,SDLK_RIGHTBRACKET,SDLK_RETURN,SDLK_LCTRL, - SDLK_a,SDLK_s,SDLK_d,SDLK_f,SDLK_g,SDLK_h,SDLK_j,SDLK_k,SDLK_l, - SDLK_SEMICOLON,SDLK_QUOTE,SDLK_BACKQUOTE,SDLK_LSHIFT,SDLK_BACKSLASH, - SDLK_z,SDLK_x,SDLK_c,SDLK_v,SDLK_b,SDLK_n,SDLK_m, - /* 0x33: */ - SDLK_COMMA,SDLK_PERIOD,SDLK_SLASH,SDLK_RSHIFT,SDLK_KP_MULTIPLY, - SDLK_LALT,SDLK_SPACE,SDLK_CAPSLOCK, - SDLK_F1,SDLK_F2,SDLK_F3,SDLK_F4,SDLK_F5,SDLK_F6,SDLK_F7,SDLK_F8,SDLK_F9,SDLK_F10, - /* 0x45: */ - SDLK_NUMLOCK,SDLK_SCROLLOCK, - SDLK_KP7,SDLK_KP8,SDLK_KP9,SDLK_KP_MINUS,SDLK_KP4,SDLK_KP5,SDLK_KP6,SDLK_KP_PLUS, - SDLK_KP1,SDLK_KP2,SDLK_KP3,SDLK_KP0,SDLK_KP_PERIOD, - SDLK_UNKNOWN,SDLK_UNKNOWN, - SDLK_LESS,SDLK_F11,SDLK_F12, Z, Z, Z, Z, Z, Z, Z, - /* 0x60: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0x70: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0x80: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0x90: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0xA0: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0xB0: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0xC0: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0xD0: */ - Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z//,Z,Z, - /* 0xE0: */ - //Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, - /* 0xF0: */ -// Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z//,Z,Z - -}; -#endif - -#undef Z - - -SDLKey MapSDLCode(Bitu skey) { -// LOG_MSG("MapSDLCode %d %X",skey,skey); - if (usescancodes) { - if (skey SDLK_WORLD_95) -#endif - ) { - /* try to retrieve key from symbolic key as scancode is zero */ - if (keysym.symtype!=SDL_KEYDOWN) return 0; - return CreateKeyBind((SDLKey)GetKeyCode(event->key.keysym)); + return CreateKeyBind(event->key.keysym.scancode); }; bool CheckEvent(SDL_Event * event) { if (event->type!=SDL_KEYDOWN && event->type!=SDL_KEYUP) return false; - Bitu key=GetKeyCode(event->key.keysym); -// LOG_MSG("key type %i is %x [%x %x]",event->type,key,event->key.keysym.sym,event->key.keysym.scancode); - assert(Bitu(event->key.keysym.sym)key.keysym.scancode; if (event->type==SDL_KEYDOWN) ActivateBindList(&lists[key],0x7fff,true); else DeactivateBindList(&lists[key],true); return 0; } - CBind * CreateKeyBind(SDLKey _key) { - if (!usescancodes) assert((Bitu)_keyaxes) axes_cap=axes; hats_cap=emulated_hats; if (hats_cap>hats) hats_cap=hats; - LOG_MSG("Using joystick %s with %d axes, %d buttons and %d hat(s)",SDL_JoystickName(stick),axes,buttons,hats); + LOG_MSG("Using joystick %s with %d axes, %d buttons and %d hat(s)",SDL_JoystickNameForIndex(stick),axes,buttons,hats); } ~CStickBindGroup() { SDL_JoystickClose(sdl_joystick); @@ -881,7 +704,7 @@ private: return configname; } const char * BindStart(void) { - if (sdl_joystick!=NULL) return SDL_JoystickName(stick); + if (sdl_joystick!=NULL) return SDL_JoystickNameForIndex(stick); else return "[missing joystick]"; } @@ -1240,6 +1063,9 @@ protected: }; static struct CMapper { + SDL_Window * window; + SDL_Rect draw_rect; + SDL_Surface * draw_surface_nonpaletted; // Needed for SDL_BlitScaled SDL_Surface * surface; SDL_Surface * draw_surface; bool exit; @@ -1277,7 +1103,7 @@ void CBindGroup::DeactivateBindList(CBindList * list,bool ev_trigger) { } static void DrawText(Bitu x,Bitu y,const char * text,Bit8u color) { - Bit8u * draw=((Bit8u *)mapper.surface->pixels)+(y*mapper.surface->pitch)+x; + Bit8u * draw=((Bit8u *)mapper.draw_surface->pixels)+(y*mapper.draw_surface->w)+x; while (*text) { Bit8u * font=&int10_font_14[(*text)*14]; Bitu i,j;Bit8u * draw_line=draw; @@ -1288,7 +1114,7 @@ static void DrawText(Bitu x,Bitu y,const char * text,Bit8u color) { else *(draw_line+j)=CLR_BLACK; map<<=1; } - draw_line+=mapper.surface->pitch; + draw_line+=mapper.draw_surface->w; } text++;draw+=8; } @@ -1305,14 +1131,14 @@ public: } virtual void Draw(void) { if (!enabled) return; - Bit8u * point=((Bit8u *)mapper.surface->pixels)+(y*mapper.surface->pitch)+x; + Bit8u * point=((Bit8u *)mapper.draw_surface->pixels)+(y*mapper.draw_surface->w)+x; for (Bitu lines=0;linespitch; + point+=mapper.draw_surface->w; } } virtual bool OnTop(Bitu _x,Bitu _y) { @@ -1343,13 +1169,21 @@ protected: const char * text; }; +class CClickableTextButton : public CTextButton { +public: + CClickableTextButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text) : CTextButton(_x,_y,_dx,_dy,_text) {} + void BindColor(void) { + this->SetColor(CLR_WHITE); + } +}; + class CEventButton; static CEventButton * last_clicked = NULL; -class CEventButton : public CTextButton { +class CEventButton : public CClickableTextButton { public: CEventButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text,CEvent * _event) - : CTextButton(_x,_y,_dx,_dy,_text) { + : CClickableTextButton(_x,_y,_dx,_dy,_text) { event=_event; } void BindColor(void) { @@ -1391,10 +1225,10 @@ void CCaptionButton::Change(const char * format,...) { static void change_action_text(const char* text,Bit8u col); static void MAPPER_SaveBinds(void); -class CBindButton : public CTextButton { +class CBindButton : public CClickableTextButton { public: CBindButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text,BB_Types _type) - : CTextButton(_x,_y,_dx,_dy,_text) { + : CClickableTextButton(_x,_y,_dx,_dy,_text) { type=_type; } void Click(void) { @@ -1433,10 +1267,10 @@ protected: BB_Types type; }; -class CCheckButton : public CTextButton { +class CCheckButton : public CClickableTextButton { public: CCheckButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text,BC_Types _type) - : CTextButton(_x,_y,_dx,_dy,_text) { + : CClickableTextButton(_x,_y,_dx,_dy,_text) { type=_type; } void Draw(void) { @@ -1457,13 +1291,13 @@ public: break; } if (checked) { - Bit8u * point=((Bit8u *)mapper.surface->pixels)+((y+2)*mapper.surface->pitch)+x+dx-dy+2; + Bit8u * point=((Bit8u *)mapper.draw_surface->pixels)+((y+2)*mapper.draw_surface->w)+x+dx-dy+2; for (Bitu lines=0;lines<(dy-4);lines++) { memset(point,color,dy-4); - point+=mapper.surface->pitch; + point+=mapper.draw_surface->w; } } - CTextButton::Draw(); + CClickableTextButton::Draw(); } void Click(void) { switch (type) { @@ -1589,25 +1423,25 @@ public: case MK_f1:case MK_f2:case MK_f3:case MK_f4: case MK_f5:case MK_f6:case MK_f7:case MK_f8: case MK_f9:case MK_f10:case MK_f11:case MK_f12: - key=SDLK_F1+(defkey-MK_f1); + key=SDL_SCANCODE_F1+(defkey-MK_f1); break; case MK_return: - key=SDLK_RETURN; + key=SDL_SCANCODE_RETURN; break; case MK_kpminus: - key=SDLK_KP_MINUS; + key=SDL_SCANCODE_KP_MINUS; break; case MK_scrolllock: - key=SDLK_SCROLLOCK; + key=SDL_SCANCODE_SCROLLLOCK; break; case MK_pause: - key=SDLK_PAUSE; + key=SDL_SCANCODE_PAUSE; break; case MK_printscreen: - key=SDLK_PRINT; + key=SDL_SCANCODE_PRINTSCREEN; break; case MK_home: - key=SDLK_HOME; + key=SDL_SCANCODE_HOME; break; } sprintf(buf,"%s \"key %d%s%s%s\"", @@ -1689,14 +1523,20 @@ static void SetActiveEvent(CEvent * event) { } } +extern SDL_Window * GFX_SetSDLSurfaceWindow(Bit16u width, Bit16u height); +extern SDL_Rect GFX_GetSDLSurfaceSubwindowDims(Bit16u width, Bit16u height); +extern void GFX_UpdateDisplayDimensions(int width, int height); + static void DrawButtons(void) { - SDL_FillRect(mapper.surface,0,CLR_BLACK); - SDL_LockSurface(mapper.surface); + SDL_FillRect(mapper.draw_surface,0,CLR_BLACK); for (CButton_it but_it = buttons.begin();but_it!=buttons.end();but_it++) { (*but_it)->Draw(); } - SDL_UnlockSurface(mapper.surface); - SDL_Flip(mapper.surface); + // We can't just use SDL_BlitScaled (say for Android) in one step + SDL_BlitSurface(mapper.draw_surface, NULL, mapper.draw_surface_nonpaletted, NULL); + SDL_BlitScaled(mapper.draw_surface_nonpaletted, NULL, mapper.surface, &mapper.draw_rect); + //SDL_BlitSurface(mapper.draw_surface, NULL, mapper.surface, NULL); + SDL_UpdateWindowSurface(mapper.window); } static CKeyEvent * AddKeyButtonEvent(Bitu x,Bitu y,Bitu dx,Bitu dy,char const * const title,char const * const entry,KBD_KEYS key) { @@ -2003,7 +1843,7 @@ static void CreateLayout(void) { bind_but.bind_title->Change("Bind Title"); } -static SDL_Color map_pal[6]={ +static SDL_Color map_pal[CLR_LAST]={ {0x00,0x00,0x00,0x00}, //0=black {0x7f,0x7f,0x7f,0x00}, //1=grey {0xff,0xff,0xff,0x00}, //2=white @@ -2042,46 +1882,44 @@ static struct { const char * eventend; Bitu key; } DefaultKeys[]={ - {"f1",SDLK_F1}, {"f2",SDLK_F2}, {"f3",SDLK_F3}, {"f4",SDLK_F4}, - {"f5",SDLK_F5}, {"f6",SDLK_F6}, {"f7",SDLK_F7}, {"f8",SDLK_F8}, - {"f9",SDLK_F9}, {"f10",SDLK_F10}, {"f11",SDLK_F11}, {"f12",SDLK_F12}, - {"1",SDLK_1}, {"2",SDLK_2}, {"3",SDLK_3}, {"4",SDLK_4}, - {"5",SDLK_5}, {"6",SDLK_6}, {"7",SDLK_7}, {"8",SDLK_8}, - {"9",SDLK_9}, {"0",SDLK_0}, + {"f1",SDL_SCANCODE_F1}, {"f2",SDL_SCANCODE_F2}, {"f3",SDL_SCANCODE_F3}, {"f4",SDL_SCANCODE_F4}, + {"f5",SDL_SCANCODE_F5}, {"f6",SDL_SCANCODE_F6}, {"f7",SDL_SCANCODE_F7}, {"f8",SDL_SCANCODE_F8}, + {"f9",SDL_SCANCODE_F9}, {"f10",SDL_SCANCODE_F10}, {"f11",SDL_SCANCODE_F11}, {"f12",SDL_SCANCODE_F12}, - {"a",SDLK_a}, {"b",SDLK_b}, {"c",SDLK_c}, {"d",SDLK_d}, - {"e",SDLK_e}, {"f",SDLK_f}, {"g",SDLK_g}, {"h",SDLK_h}, - {"i",SDLK_i}, {"j",SDLK_j}, {"k",SDLK_k}, {"l",SDLK_l}, - {"m",SDLK_m}, {"n",SDLK_n}, {"o",SDLK_o}, {"p",SDLK_p}, - {"q",SDLK_q}, {"r",SDLK_r}, {"s",SDLK_s}, {"t",SDLK_t}, - {"u",SDLK_u}, {"v",SDLK_v}, {"w",SDLK_w}, {"x",SDLK_x}, - {"y",SDLK_y}, {"z",SDLK_z}, {"space",SDLK_SPACE}, - {"esc",SDLK_ESCAPE}, {"equals",SDLK_EQUALS}, {"grave",SDLK_BACKQUOTE}, - {"tab",SDLK_TAB}, {"enter",SDLK_RETURN}, {"bspace",SDLK_BACKSPACE}, - {"lbracket",SDLK_LEFTBRACKET}, {"rbracket",SDLK_RIGHTBRACKET}, - {"minus",SDLK_MINUS}, {"capslock",SDLK_CAPSLOCK}, {"semicolon",SDLK_SEMICOLON}, - {"quote", SDLK_QUOTE}, {"backslash",SDLK_BACKSLASH}, {"lshift",SDLK_LSHIFT}, - {"rshift",SDLK_RSHIFT}, {"lalt",SDLK_LALT}, {"ralt",SDLK_RALT}, - {"lctrl",SDLK_LCTRL}, {"rctrl",SDLK_RCTRL}, {"comma",SDLK_COMMA}, - {"period",SDLK_PERIOD}, {"slash",SDLK_SLASH}, {"printscreen",SDLK_PRINT}, - {"scrolllock",SDLK_SCROLLOCK}, {"pause",SDLK_PAUSE}, {"pagedown",SDLK_PAGEDOWN}, - {"pageup",SDLK_PAGEUP}, {"insert",SDLK_INSERT}, {"home",SDLK_HOME}, - {"delete",SDLK_DELETE}, {"end",SDLK_END}, {"up",SDLK_UP}, - {"left",SDLK_LEFT}, {"down",SDLK_DOWN}, {"right",SDLK_RIGHT}, - {"kp_0",SDLK_KP0}, {"kp_1",SDLK_KP1}, {"kp_2",SDLK_KP2}, {"kp_3",SDLK_KP3}, - {"kp_4",SDLK_KP4}, {"kp_5",SDLK_KP5}, {"kp_6",SDLK_KP6}, {"kp_7",SDLK_KP7}, - {"kp_8",SDLK_KP8}, {"kp_9",SDLK_KP9}, {"numlock",SDLK_NUMLOCK}, - {"kp_divide",SDLK_KP_DIVIDE}, {"kp_multiply",SDLK_KP_MULTIPLY}, - {"kp_minus",SDLK_KP_MINUS}, {"kp_plus",SDLK_KP_PLUS}, - {"kp_period",SDLK_KP_PERIOD}, {"kp_enter",SDLK_KP_ENTER}, + {"1",SDL_SCANCODE_1}, {"2",SDL_SCANCODE_2}, {"3",SDL_SCANCODE_3}, {"4",SDL_SCANCODE_4}, + {"5",SDL_SCANCODE_5}, {"6",SDL_SCANCODE_6}, {"7",SDL_SCANCODE_7}, {"8",SDL_SCANCODE_8}, + {"9",SDL_SCANCODE_9}, {"0",SDL_SCANCODE_0}, -#if defined (MACOSX) - /* Intl Mac keyboards in US layout actually put U+00A7 SECTION SIGN here */ - {"lessthan",SDLK_WORLD_0}, -#else - {"lessthan",SDLK_LESS}, -#endif + {"a",SDL_SCANCODE_A}, {"b",SDL_SCANCODE_B}, {"c",SDL_SCANCODE_C}, {"d",SDL_SCANCODE_D}, + {"e",SDL_SCANCODE_E}, {"f",SDL_SCANCODE_F}, {"g",SDL_SCANCODE_G}, {"h",SDL_SCANCODE_H}, + {"i",SDL_SCANCODE_I}, {"j",SDL_SCANCODE_J}, {"k",SDL_SCANCODE_K}, {"l",SDL_SCANCODE_L}, + {"m",SDL_SCANCODE_M}, {"n",SDL_SCANCODE_N}, {"o",SDL_SCANCODE_O}, {"p",SDL_SCANCODE_P}, + {"q",SDL_SCANCODE_Q}, {"r",SDL_SCANCODE_R}, {"s",SDL_SCANCODE_S}, {"t",SDL_SCANCODE_T}, + {"u",SDL_SCANCODE_U}, {"v",SDL_SCANCODE_V}, {"w",SDL_SCANCODE_W}, {"x",SDL_SCANCODE_X}, + {"y",SDL_SCANCODE_Y}, {"z",SDL_SCANCODE_Z}, {"space",SDL_SCANCODE_SPACE}, + {"esc",SDL_SCANCODE_ESCAPE}, {"equals",SDL_SCANCODE_EQUALS}, {"grave",SDL_SCANCODE_GRAVE}, + {"tab",SDL_SCANCODE_TAB}, {"enter",SDL_SCANCODE_RETURN}, {"bspace",SDL_SCANCODE_BACKSPACE}, + {"lbracket",SDL_SCANCODE_LEFTBRACKET}, {"rbracket",SDL_SCANCODE_RIGHTBRACKET}, + {"minus",SDL_SCANCODE_MINUS}, {"capslock",SDL_SCANCODE_CAPSLOCK}, {"semicolon",SDL_SCANCODE_SEMICOLON}, + {"quote", SDL_SCANCODE_APOSTROPHE}, {"backslash",SDL_SCANCODE_BACKSLASH}, {"lshift",SDL_SCANCODE_LSHIFT}, + {"rshift",SDL_SCANCODE_RSHIFT}, {"lalt",SDL_SCANCODE_LALT}, {"ralt",SDL_SCANCODE_RALT}, + {"lctrl",SDL_SCANCODE_LCTRL}, {"rctrl",SDL_SCANCODE_RCTRL}, {"comma",SDL_SCANCODE_COMMA}, + {"period",SDL_SCANCODE_PERIOD}, {"slash",SDL_SCANCODE_SLASH}, {"printscreen",SDL_SCANCODE_PRINTSCREEN}, + {"scrolllock",SDL_SCANCODE_SCROLLLOCK}, {"pause",SDL_SCANCODE_PAUSE}, {"pagedown",SDL_SCANCODE_PAGEDOWN}, + {"pageup",SDL_SCANCODE_PAGEUP}, {"insert",SDL_SCANCODE_INSERT}, {"home",SDL_SCANCODE_HOME}, + {"delete",SDL_SCANCODE_DELETE}, {"end",SDL_SCANCODE_END}, {"up",SDL_SCANCODE_UP}, + {"left",SDL_SCANCODE_LEFT}, {"down",SDL_SCANCODE_DOWN}, {"right",SDL_SCANCODE_RIGHT}, + {"kp_0",SDL_SCANCODE_KP_0}, {"kp_1",SDL_SCANCODE_KP_1}, {"kp_2",SDL_SCANCODE_KP_2}, {"kp_3",SDL_SCANCODE_KP_3}, + {"kp_4",SDL_SCANCODE_KP_4}, {"kp_5",SDL_SCANCODE_KP_5}, {"kp_6",SDL_SCANCODE_KP_6}, {"kp_7",SDL_SCANCODE_KP_7}, + {"kp_8",SDL_SCANCODE_KP_8}, {"kp_9",SDL_SCANCODE_KP_9}, {"numlock",SDL_SCANCODE_NUMLOCKCLEAR}, + {"kp_divide",SDL_SCANCODE_KP_DIVIDE}, {"kp_multiply",SDL_SCANCODE_KP_MULTIPLY}, + {"kp_minus",SDL_SCANCODE_KP_MINUS}, {"kp_plus",SDL_SCANCODE_KP_PLUS}, + {"kp_period",SDL_SCANCODE_KP_PERIOD}, {"kp_enter",SDL_SCANCODE_KP_ENTER}, + + /* Is that the extra backslash key ("less than" key) */ + /* on some keyboards with the 102-keys layout?? */ + {"lessthan",SDL_SCANCODE_NONUSBACKSLASH}, {0,0} }; @@ -2094,10 +1932,10 @@ static void CreateDefaultBinds(void) { CreateStringBind(buffer); i++; } - sprintf(buffer,"mod_1 \"key %d\"",SDLK_RCTRL);CreateStringBind(buffer); - sprintf(buffer,"mod_1 \"key %d\"",SDLK_LCTRL);CreateStringBind(buffer); - sprintf(buffer,"mod_2 \"key %d\"",SDLK_RALT);CreateStringBind(buffer); - sprintf(buffer,"mod_2 \"key %d\"",SDLK_LALT);CreateStringBind(buffer); + sprintf(buffer,"mod_1 \"key %d\"",SDL_SCANCODE_RCTRL);CreateStringBind(buffer); + sprintf(buffer,"mod_1 \"key %d\"",SDL_SCANCODE_LCTRL);CreateStringBind(buffer); + sprintf(buffer,"mod_2 \"key %d\"",SDL_SCANCODE_RALT);CreateStringBind(buffer); + sprintf(buffer,"mod_2 \"key %d\"",SDL_SCANCODE_LALT);CreateStringBind(buffer); for (CHandlerEventVector_it hit=handlergroup.begin();hit!=handlergroup.end();hit++) { (*hit)->MakeDefaultBind(buffer); CreateStringBind(buffer); @@ -2190,17 +2028,86 @@ void MAPPER_CheckEvent(SDL_Event * event) { void BIND_MappingEvents(void) { SDL_Event event; + static bool isButtonPressed = false; + static CButton *lastHoveredButton = NULL; while (SDL_PollEvent(&event)) { switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + isButtonPressed = true; + /* Further check where are we pointing at right now */ + case SDL_MOUSEMOTION: + if (!isButtonPressed) + break; + /* Normalize position in case a scaled sub-window is used (say on Android) */ + event.button.x=(event.button.x-mapper.draw_rect.x)*mapper.draw_surface->w/mapper.draw_rect.w; + if ((event.button.x<0) || (event.button.x>=mapper.draw_surface->w)) + break; + event.button.y=(event.button.y-mapper.draw_rect.y)*mapper.draw_surface->h/mapper.draw_rect.h; + if ((event.button.y<0) || (event.button.y>=mapper.draw_surface->h)) + break; + /* Maybe we have been pointing at a specific button for a little while */ + if (lastHoveredButton) { + /* Check if there's any change */ + if (lastHoveredButton->OnTop(event.button.x,event.button.y)) + break; + /* Not pointing at given button anymore */ + if (lastHoveredButton == last_clicked) + lastHoveredButton->Click(); + else + lastHoveredButton->BindColor(); + mapper.redraw=true; + lastHoveredButton=NULL; + } + /* Check which button are we currently pointing at */ + for (CButton_it but_it = buttons.begin();but_it!=buttons.end();but_it++) { + if (dynamic_cast(*but_it) && (*but_it)->OnTop(event.button.x,event.button.y)) { + (*but_it)->SetColor(CLR_RED); + mapper.redraw=true; + lastHoveredButton=*but_it; + break; + } + } + break; case SDL_MOUSEBUTTONUP: + isButtonPressed = false; + if (lastHoveredButton) { + /* For most buttons the actual new color is going to be green; But not for a few others. */ + lastHoveredButton->BindColor(); + mapper.redraw=true; + lastHoveredButton = NULL; + } + /* Normalize position in case a scaled sub-window is used (say on Android) */ + event.button.x=(event.button.x-mapper.draw_rect.x)*mapper.draw_surface->w/mapper.draw_rect.w; + if ((event.button.x<0) || (event.button.x>=mapper.draw_surface->w)) + break; + event.button.y=(event.button.y-mapper.draw_rect.y)*mapper.draw_surface->h/mapper.draw_rect.h; + if ((event.button.y<0) || (event.button.y>=mapper.draw_surface->h)) + break; /* Check the press */ for (CButton_it but_it = buttons.begin();but_it!=buttons.end();but_it++) { - if ((*but_it)->OnTop(event.button.x,event.button.y)) { + if (dynamic_cast(*but_it) && (*but_it)->OnTop(event.button.x,event.button.y)) { (*but_it)->Click(); + break; } - } + } + break; + case SDL_WINDOWEVENT: + /* The resize event MAY arrive e.g. when the mapper is + * toggled, at least on X11. Furthermore, the restore + * event should be handled on Android. + */ + if ((event.window.event == SDL_WINDOWEVENT_RESIZED) + || (event.window.event == SDL_WINDOWEVENT_RESTORED)) { + mapper.surface = SDL_GetWindowSurface(mapper.window); + if (mapper.surface == NULL) E_Exit("Couldn't refresh mapper window surface after resize or restoration: %s",SDL_GetError()); + GFX_UpdateDisplayDimensions(event.window.data1, event.window.data2); + mapper.draw_rect=GFX_GetSDLSurfaceSubwindowDims(640,480); + DrawButtons(); + } break; case SDL_QUIT: + isButtonPressed = false; + lastHoveredButton = NULL; mapper.exit=true; break; default: @@ -2275,7 +2182,7 @@ static void InitializeJoysticks(void) { static void CreateBindGroups(void) { bindgroups.clear(); - new CKeyBindGroup(SDLK_LAST); + new CKeyBindGroup(SDL_NUM_SCANCODES); if (joytype != JOY_NONE) { #if defined (REDUCE_JOYSTICK_POLLING) // direct access to the SDL joystick, thus removed from the event handling @@ -2358,11 +2265,20 @@ void MAPPER_RunInternal() { /* Be sure that there is no update in progress */ GFX_EndUpdate( 0 ); - mapper.surface=SDL_SetVideoMode_Wrap(640,480,8,0); - if (mapper.surface == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError()); + mapper.window=GFX_SetSDLSurfaceWindow(640,480); + if (mapper.window == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError()); + mapper.surface=SDL_GetWindowSurface(mapper.window); + if (mapper.surface == NULL) E_Exit("Could not retrieve window surface for mapper: %s",SDL_GetError()); /* Set some palette entries */ - SDL_SetPalette(mapper.surface, SDL_LOGPAL|SDL_PHYSPAL, map_pal, 0, 6); + mapper.draw_surface=SDL_CreateRGBSurface(0,640,480,8,0,0,0,0); + // Needed for SDL_BlitScaled + mapper.draw_surface_nonpaletted=SDL_CreateRGBSurface(0,640,480,32,0x0000ff00,0x00ff0000,0xff000000,0); + mapper.draw_rect=GFX_GetSDLSurfaceSubwindowDims(640,480); + // Sorry, but SDL_SetSurfacePalette requires a full palette. + SDL_Palette *sdl2_map_pal_ptr = SDL_AllocPalette(256); + SDL_SetPaletteColors(sdl2_map_pal_ptr, map_pal, 0, CLR_LAST); + SDL_SetSurfacePalette(mapper.draw_surface, sdl2_map_pal_ptr); if (last_clicked) { last_clicked->BindColor(); last_clicked=NULL; @@ -2378,10 +2294,17 @@ void MAPPER_RunInternal() { if (mapper.redraw) { mapper.redraw=false; DrawButtons(); + } else { + SDL_UpdateWindowSurface(mapper.window); } BIND_MappingEvents(); SDL_Delay(1); } + /* ONE SHOULD NOT FORGET TO DO THIS! + Unless a memory leak is desired... */ + SDL_FreeSurface(mapper.draw_surface); + SDL_FreeSurface(mapper.draw_surface_nonpaletted); + SDL_FreePalette(sdl2_map_pal_ptr); #if defined (REDUCE_JOYSTICK_POLLING) SDL_JoystickEventState(SDL_DISABLE); #endif @@ -2400,22 +2323,14 @@ void MAPPER_Init(void) { } if (SDL_GetModState()&KMOD_CAPS) { for (CBindList_it bit=caps_lock_event->bindlist.begin();bit!=caps_lock_event->bindlist.end();bit++) { -#if SDL_VERSION_ATLEAST(1, 2, 14) (*bit)->ActivateBind(32767,true,false); (*bit)->DeActivateBind(false); -#else - (*bit)->ActivateBind(32767,true,true); //Skip the action itself as bios_keyboard.cpp handles the startup state. -#endif } } if (SDL_GetModState()&KMOD_NUM) { for (CBindList_it bit=num_lock_event->bindlist.begin();bit!=num_lock_event->bindlist.end();bit++) { -#if SDL_VERSION_ATLEAST(1, 2, 14) (*bit)->ActivateBind(32767,true,false); (*bit)->DeActivateBind(false); -#else - (*bit)->ActivateBind(32767,true,true); -#endif } } } @@ -2429,114 +2344,7 @@ void MAPPER_StartUp(Section * sec) { mapper.sticks.num=0; mapper.sticks.num_groups=0; memset(&virtual_joysticks,0,sizeof(virtual_joysticks)); - - usescancodes = false; - - if (section->Get_bool("usescancodes")) { - usescancodes=true; - - /* Note: table has to be tested/updated for various OSs */ -#if defined (MACOSX) - /* nothing */ -#elif !defined (WIN32) /* => Linux & BSDs */ - bool evdev_input = false; -#ifdef SDL_VIDEO_DRIVER_X11 -//SDL needs to be compiled to use it, else the next makes no sense. -#ifdef C_X11_XKB - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if (SDL_GetWMInfo(&info)) { - XkbDescPtr desc = NULL; - if((desc = XkbGetMap(info.info.x11.display,XkbAllComponentsMask,XkbUseCoreKbd))) { - if(XkbGetNames(info.info.x11.display,XkbAllNamesMask,desc) == 0) { - const char* keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes); -// const char* geom = XGetAtomName(info.info.x11.display, desc->names->geometry); - if(keycodes) { - LOG(LOG_MISC,LOG_NORMAL)("keyboard type %s",keycodes); - if (strncmp(keycodes,"evdev",5) == 0) evdev_input = true; - } - XkbFreeNames(desc,XkbAllNamesMask,True); - } - XkbFreeClientMap(desc,0,True); - } - } -#endif -#endif - if (evdev_input) { - sdlkey_map[0x67]=SDLK_UP; - sdlkey_map[0x6c]=SDLK_DOWN; - sdlkey_map[0x69]=SDLK_LEFT; - sdlkey_map[0x6a]=SDLK_RIGHT; - sdlkey_map[0x66]=SDLK_HOME; - sdlkey_map[0x6b]=SDLK_END; - sdlkey_map[0x68]=SDLK_PAGEUP; - sdlkey_map[0x6d]=SDLK_PAGEDOWN; - sdlkey_map[0x6e]=SDLK_INSERT; - sdlkey_map[0x6f]=SDLK_DELETE; - sdlkey_map[0x62]=SDLK_KP_DIVIDE; - sdlkey_map[0x60]=SDLK_KP_ENTER; - sdlkey_map[0x61]=SDLK_RCTRL; - sdlkey_map[0x77]=SDLK_PAUSE; - sdlkey_map[0x63]=SDLK_PRINT; - sdlkey_map[0x64]=SDLK_RALT; - - //Win-keys - sdlkey_map[0x7d]=SDLK_LSUPER; - sdlkey_map[0x7e]=SDLK_RSUPER; - sdlkey_map[0x7f]=SDLK_MENU; - } else { - sdlkey_map[0x5a]=SDLK_UP; - sdlkey_map[0x60]=SDLK_DOWN; - sdlkey_map[0x5c]=SDLK_LEFT; - sdlkey_map[0x5e]=SDLK_RIGHT; - sdlkey_map[0x59]=SDLK_HOME; - sdlkey_map[0x5f]=SDLK_END; - sdlkey_map[0x5b]=SDLK_PAGEUP; - sdlkey_map[0x61]=SDLK_PAGEDOWN; - sdlkey_map[0x62]=SDLK_INSERT; - sdlkey_map[0x63]=SDLK_DELETE; - sdlkey_map[0x68]=SDLK_KP_DIVIDE; - sdlkey_map[0x64]=SDLK_KP_ENTER; - sdlkey_map[0x65]=SDLK_RCTRL; - sdlkey_map[0x66]=SDLK_PAUSE; - sdlkey_map[0x67]=SDLK_PRINT; - sdlkey_map[0x69]=SDLK_RALT; - } -#else - sdlkey_map[0xc8]=SDLK_UP; - sdlkey_map[0xd0]=SDLK_DOWN; - sdlkey_map[0xcb]=SDLK_LEFT; - sdlkey_map[0xcd]=SDLK_RIGHT; - sdlkey_map[0xc7]=SDLK_HOME; - sdlkey_map[0xcf]=SDLK_END; - sdlkey_map[0xc9]=SDLK_PAGEUP; - sdlkey_map[0xd1]=SDLK_PAGEDOWN; - sdlkey_map[0xd2]=SDLK_INSERT; - sdlkey_map[0xd3]=SDLK_DELETE; - sdlkey_map[0xb5]=SDLK_KP_DIVIDE; - sdlkey_map[0x9c]=SDLK_KP_ENTER; - sdlkey_map[0x9d]=SDLK_RCTRL; - sdlkey_map[0xc5]=SDLK_PAUSE; - sdlkey_map[0xb7]=SDLK_PRINT; - sdlkey_map[0xb8]=SDLK_RALT; - - //Win-keys - sdlkey_map[0xdb]=SDLK_LMETA; - sdlkey_map[0xdc]=SDLK_RMETA; - sdlkey_map[0xdd]=SDLK_MENU; - -#endif - - Bitu i; - for (i=0; iGet_path("mapperfile"); mapper.filename = pp->realpath; MAPPER_AddHandler(&MAPPER_Run,MK_f1,MMOD1,"mapper","Mapper"); } - diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 940a66b1..709dcc2d 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -50,7 +50,7 @@ #include "cross.h" #include "control.h" -#define MAPPERFILE "mapper-" VERSION ".map" +#define MAPPERFILE "mapper-sdl2-" VERSION ".map" //#define DISABLE_JOYSTICK #if C_OPENGL @@ -124,8 +124,7 @@ struct private_hwdata { enum SCREEN_TYPES { SCREEN_SURFACE, - SCREEN_SURFACE_DDRAW, - SCREEN_OVERLAY, + SCREEN_TEXTURE, SCREEN_OPENGL }; @@ -143,10 +142,11 @@ struct SDL_Block { bool inited; bool active; //If this isn't set don't draw bool updating; + bool update_display_contents; + bool resizing_window; struct { Bit32u width; Bit32u height; - Bit32u bpp; Bitu flags; double scalex,scaley; GFX_CallBack_t callback; @@ -156,22 +156,25 @@ struct SDL_Block { struct { Bit16u width, height; bool fixed; + bool display_res; } full; struct { Bit16u width, height; } window; Bit8u bpp; + Bit32u sdl2pixelFormat; bool fullscreen; bool lazy_fullscreen; bool lazy_fullscreen_req; - bool doublebuf; + bool vsync; SCREEN_TYPES type; SCREEN_TYPES want_type; } desktop; #if C_OPENGL struct { + SDL_GLContext context; Bitu pitch; - void * framebuf; + void * framebuf; // TODO Use unique_ptr to prevent leak GLuint buffer; GLuint texture; GLuint displaylist; @@ -181,20 +184,21 @@ struct SDL_Block { bool paletted_texture; bool pixel_buffer_object; } opengl; -#endif - struct { - SDL_Surface * surface; -#if C_DDRAW - RECT rect; -#endif - } blit; +#endif // C_OPENGL struct { PRIORITY_LEVELS focus; PRIORITY_LEVELS nofocus; } priority; SDL_Rect clip; - SDL_Surface * surface; - SDL_Overlay * overlay; + SDL_Surface *surface; + SDL_Window *window; + SDL_Renderer *renderer; + const char *rendererDriver; + int displayNumber; + struct { + SDL_Texture *texture; + SDL_PixelFormat *pixelFormat; + } texture; SDL_cond *cond; struct { bool autolock; @@ -203,6 +207,7 @@ struct SDL_Block { bool locked; int xsensitivity; int ysensitivity; + Bitu sensitivity; } mouse; SDL_Rect updateRects[1024]; Bitu num_joysticks; @@ -212,67 +217,23 @@ struct SDL_Block { Bit32u focus_ticks; #endif // state of alt-keys for certain special handlings - Bit8u laltstate; - Bit8u raltstate; + SDL_EventType laltstate; + SDL_EventType raltstate; }; static SDL_Block sdl; -#define SETMODE_SAVES 1 //Don't set Video Mode if nothing changes. -#define SETMODE_SAVES_CLEAR 1 //Clear the screen, when the Video Mode is reused -SDL_Surface* SDL_SetVideoMode_Wrap(int width,int height,int bpp,Bit32u flags){ -#if SETMODE_SAVES - static int i_height = 0; - static int i_width = 0; - static int i_bpp = 0; - static Bit32u i_flags = 0; - if (sdl.surface != NULL && height == i_height && width == i_width && bpp == i_bpp && flags == i_flags) { - // I don't see a difference, so disabled for now, as the code isn't finished either -#if SETMODE_SAVES_CLEAR - //TODO clear it. -#if C_OPENGL - if ((flags & SDL_OPENGL)==0) - SDL_FillRect(sdl.surface,NULL,SDL_MapRGB(sdl.surface->format,0,0,0)); - else { - glClearColor (0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - SDL_GL_SwapBuffers(); - } -#else //C_OPENGL - SDL_FillRect(sdl.surface,NULL,SDL_MapRGB(sdl.surface->format,0,0,0)); -#endif //C_OPENGL -#endif //SETMODE_SAVES_CLEAR - return sdl.surface; - } +static int SDL_Init_Wrapper(void) +{ + // Don't init timers, GetTicks seems to work fine and they can use + // a fair amount of power (Macs again). + // Please report problems with audio and other things. + return SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO); +} - -#ifdef WIN32 - //SDL seems to crash if we are in OpenGL mode currently and change to exactly the same size without OpenGL. - //This happens when DOSBox is in textmode with aspect=true and output=opengl and the mapper is started. - //The easiest solution is to change the size. The mapper doesn't care. (PART PXX) - - //Also we have to switch back to windowed mode first, as else it may crash as well. - //Bug: we end up with a locked mouse cursor, but at least that beats crashing. (output=opengl,aspect=true,fullscreen=true) - if((i_flags&SDL_OPENGL) && !(flags&SDL_OPENGL) && (i_flags&SDL_FULLSCREEN) && !(flags&SDL_FULLSCREEN)){ - GFX_SwitchFullScreen(); - return SDL_SetVideoMode_Wrap(width,height,bpp,flags); - } - - //PXX - if ((i_flags&SDL_OPENGL) && !(flags&SDL_OPENGL) && height==i_height && width==i_width && height==480) { - height++; - } -#endif //WIN32 -#endif //SETMODE_SAVES - SDL_Surface* s = SDL_SetVideoMode(width,height,bpp,flags); -#if SETMODE_SAVES - if (s == NULL) return s; //Only store when successful - i_height = height; - i_width = width; - i_bpp = bpp; - i_flags = flags; -#endif - return s; +static void SDL_Quit_Wrapper(void) +{ + SDL_Quit(); } extern const char* RunningProgram; @@ -294,7 +255,7 @@ void GFX_SetTitle(Bit32s cycles,int frameskip,bool paused){ } if (paused) strcat(title," PAUSED"); - SDL_WM_SetCaption(title,VERSION); + SDL_SetWindowTitle(sdl.window,title); } static unsigned char logo[32*32*4]= { @@ -310,8 +271,9 @@ static void GFX_SetIcon() { #else SDL_Surface* logos= SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0x000000ff,0x0000ff00,0x00ff0000,0); #endif - SDL_WM_SetIcon(logos,NULL); -#endif + + SDL_SetWindowIcon(sdl.window, logos); +#endif // !defined(MACOSX) } @@ -332,12 +294,18 @@ static void PauseDOSBox(bool pressed) { while (SDL_PollEvent(&event)) { // flush event queue. } - + /* NOTE: This is one of the few places where we use SDL key codes + with SDL 2.0, rather than scan codes. Is that the correct behavior? */ while (paused) { SDL_WaitEvent(&event); // since we're not polling, cpu usage drops to 0. switch (event.type) { - case SDL_QUIT: KillSwitch(true); break; + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_RESTORED) { + // We may need to re-create a texture and more + GFX_ResetScreen(); + } + break; case SDL_KEYDOWN: // Must use Pause/Break Key to resume. case SDL_KEYUP: if(event.key.keysym.sym == SDLK_PAUSE) { @@ -347,7 +315,8 @@ static void PauseDOSBox(bool pressed) { break; } #if defined (MACOSX) - if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) { + if (event.key.keysym.sym == SDLK_q && + (event.key.keysym.mod == KMOD_RGUI || event.key.keysym.mod == KMOD_LGUI)) { /* On macs, all aps exit when pressing cmd-q */ KillSwitch(true); break; @@ -357,32 +326,14 @@ static void PauseDOSBox(bool pressed) { } } -#if defined (WIN32) -bool GFX_SDLUsingWinDIB(void) { - return sdl.using_windib; -} -#endif - /* Reset the screen with current values in the sdl structure */ Bitu GFX_GetBestMode(Bitu flags) { - Bitu testbpp,gotbpp; switch (sdl.desktop.want_type) { case SCREEN_SURFACE: check_surface: flags &= ~GFX_LOVE_8; //Disable love for 8bpp modes - /* Check if we can satisfy the depth it loves */ - if (flags & GFX_LOVE_8) testbpp=8; - else if (flags & GFX_LOVE_15) testbpp=15; - else if (flags & GFX_LOVE_16) testbpp=16; - else if (flags & GFX_LOVE_32) testbpp=32; - else testbpp=0; -#if C_DDRAW -check_gotbpp: -#endif - if (sdl.desktop.fullscreen) gotbpp=SDL_VideoModeOK(640,480,testbpp,SDL_FULLSCREEN|SDL_HWSURFACE|SDL_HWPALETTE); - else gotbpp=sdl.desktop.bpp; - /* If we can't get our favorite mode check for another working one */ - switch (gotbpp) { + switch (sdl.desktop.bpp) + { case 8: if (flags & GFX_CAN_8) flags&=~(GFX_CAN_15|GFX_CAN_16|GFX_CAN_32); break; @@ -399,31 +350,15 @@ check_gotbpp: } flags |= GFX_CAN_RANDOM; break; -#if C_DDRAW - case SCREEN_SURFACE_DDRAW: - if (!(flags&(GFX_CAN_15|GFX_CAN_16|GFX_CAN_32))) goto check_surface; - if (flags & GFX_LOVE_15) testbpp=15; - else if (flags & GFX_LOVE_16) testbpp=16; - else if (flags & GFX_LOVE_32) testbpp=32; - else testbpp=0; - flags|=GFX_SCALING; - goto check_gotbpp; -#endif - case SCREEN_OVERLAY: - //We only accept 32bit output from the scalers here - //Can't handle true color inputs - if (flags & GFX_RGBONLY || !(flags&GFX_CAN_32)) goto check_surface; - flags|=GFX_SCALING; - flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); - break; #if C_OPENGL case SCREEN_OPENGL: - //We only accept 32bit output from the scalers here +#endif + case SCREEN_TEXTURE: + // We only accept 32bit output from the scalers here if (!(flags&GFX_CAN_32)) goto check_surface; flags|=GFX_SCALING; flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); break; -#endif default: goto check_surface; break; @@ -457,20 +392,134 @@ static int int_log2 (int val) { return log; } +static SDL_Window * GFX_SetSDLWindowMode(Bit16u width, Bit16u height, bool fullscreen, SCREEN_TYPES screenType) +{ + static SCREEN_TYPES lastType = SCREEN_SURFACE; + if (sdl.renderer) { + SDL_DestroyRenderer(sdl.renderer); + sdl.renderer = 0; + } + if (sdl.texture.pixelFormat) { + SDL_FreeFormat(sdl.texture.pixelFormat); + sdl.texture.pixelFormat = 0; + } + if (sdl.texture.texture) { + SDL_DestroyTexture(sdl.texture.texture); + sdl.texture.texture = 0; + } +#if C_OPENGL + if (sdl.opengl.context) { + SDL_GL_DeleteContext(sdl.opengl.context); + sdl.opengl.context = 0; + } +#endif + int currWidth, currHeight; + if (sdl.window && sdl.resizing_window) { + SDL_GetWindowSize(sdl.window, &currWidth, &currHeight); + sdl.update_display_contents = ((width <= currWidth) && (height <= currHeight)); + return sdl.window; + } + /* If we change screen type, recreate the window. Furthermore, if + * it is our very first time then we simply create a new window. + */ + if (!sdl.window || (lastType != screenType)) { + lastType = screenType; -static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags, Bit32u bpp) { + if (sdl.window) { + SDL_DestroyWindow(sdl.window); + } + + /* Don't create a fullscreen immediately. Reasons: + * 1. This theoretically allows us to set window resolution and + * then let SDL2 remember it for later (even if not actually done). + * 2. It's a bit less glitchy to set a custom display mode for a + * full screen, albeit it's still not perfect (at least on X11). + */ + sdl.window = SDL_CreateWindow( + "", + SDL_WINDOWPOS_UNDEFINED_DISPLAY(sdl.displayNumber), + SDL_WINDOWPOS_UNDEFINED_DISPLAY(sdl.displayNumber), + width, + height, + ((screenType == SCREEN_OPENGL) ? SDL_WINDOW_OPENGL : 0) | SDL_WINDOW_SHOWN + ); + + if (!sdl.window) { + return sdl.window; + } + + GFX_SetTitle(-1, -1, false); // refresh title. + + if (!fullscreen) { + goto finish; + } + } + /* Fullscreen mode switching has its limits, and is also problematic on + * some window managers. For now, the following may work up to some + * level. On X11, SDL_VIDEO_X11_LEGACY_FULLSCREEN=1 can also help, + * although it has its own issues. + * Suggestion: Use the desktop res if possible, with output=surface + * if one is not interested in scaling. + * On Android, desktop res is the only way. + */ + if (fullscreen) { + SDL_DisplayMode displayMode; + SDL_GetWindowDisplayMode(sdl.window, &displayMode); + displayMode.w = width; + displayMode.h = height; + SDL_SetWindowDisplayMode(sdl.window, &displayMode); + SDL_SetWindowFullscreen(sdl.window, + sdl.desktop.full.display_res ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN); + } else { + SDL_SetWindowFullscreen(sdl.window, 0); + SDL_SetWindowSize(sdl.window, width, height); + } + // Maybe some requested fullscreen resolution is unsupported? +finish: + SDL_GetWindowSize(sdl.window, &currWidth, &currHeight); + sdl.update_display_contents = ((width <= currWidth) && (height <= currHeight)); + return sdl.window; +} + +// Used for the mapper UI and more: Creates a fullscreen window with desktop res +// on Android, and a non-fullscreen window with the input dimensions otherwise. +SDL_Window * GFX_SetSDLSurfaceWindow(Bit16u width, Bit16u height) +{ + return GFX_SetSDLWindowMode(width, height, false, SCREEN_SURFACE); +} + +// Returns the rectangle in the current window to be used for scaling a +// sub-window with the given dimensions, like the mapper UI. +SDL_Rect GFX_GetSDLSurfaceSubwindowDims(Bit16u width, Bit16u height) +{ + SDL_Rect rect; + rect.x = rect.y = 0; + rect.w = width; + rect.h = height; + return rect; +} + +// Currently used for an initial test here +static SDL_Window * GFX_SetSDLOpenGLWindow(Bit16u width, Bit16u height) +{ + // Android part used: + // return GFX_SetSDLWindowMode(sdl.desktop.full.width, sdl.desktop.full.height, true, SCREEN_OPENGL); + return GFX_SetSDLWindowMode(width, height, false, SCREEN_OPENGL); +} + +static SDL_Window * GFX_SetupWindowScaled(SCREEN_TYPES screenType) +{ Bit16u fixedWidth; Bit16u fixedHeight; if (sdl.desktop.fullscreen) { fixedWidth = sdl.desktop.full.fixed ? sdl.desktop.full.width : 0; fixedHeight = sdl.desktop.full.fixed ? sdl.desktop.full.height : 0; - sdl_flags |= SDL_FULLSCREEN|SDL_HWSURFACE; } else { fixedWidth = sdl.desktop.window.width; fixedHeight = sdl.desktop.window.height; - sdl_flags |= SDL_HWSURFACE; } + if (fixedWidth && fixedHeight) { double ratio_w=(double)fixedWidth/(sdl.draw.width*sdl.draw.scalex); double ratio_h=(double)fixedHeight/(sdl.draw.height*sdl.draw.scaley); @@ -485,34 +534,37 @@ static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags, Bit32u bpp) { sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex*ratio_h + 0.4); sdl.clip.h=(Bit16u)fixedHeight; } - if (sdl.desktop.fullscreen) - sdl.surface = SDL_SetVideoMode_Wrap(fixedWidth,fixedHeight,bpp,sdl_flags); - else - sdl.surface = SDL_SetVideoMode_Wrap(sdl.clip.w,sdl.clip.h,bpp,sdl_flags); - if (sdl.surface && sdl.surface->flags & SDL_FULLSCREEN) { - sdl.clip.x=(Sint16)((sdl.surface->w-sdl.clip.w)/2); - sdl.clip.y=(Sint16)((sdl.surface->h-sdl.clip.h)/2); + + if (sdl.desktop.fullscreen) { + sdl.window = GFX_SetSDLWindowMode(fixedWidth, + fixedHeight, + sdl.desktop.fullscreen, + screenType); + } else { + sdl.window = GFX_SetSDLWindowMode(sdl.clip.w, + sdl.clip.h, + sdl.desktop.fullscreen, + screenType); + } + + if (sdl.window && SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_FULLSCREEN) { + int windowWidth; + SDL_GetWindowSize(sdl.window, &windowWidth, NULL); + sdl.clip.x = (Sint16)((windowWidth - sdl.clip.w) / 2); + sdl.clip.y = (Sint16)((fixedHeight - sdl.clip.h) / 2); } else { sdl.clip.x = 0; sdl.clip.y = 0; } - return sdl.surface; + + return sdl.window; + } else { sdl.clip.x=0;sdl.clip.y=0; sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex); sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley); - sdl.surface=SDL_SetVideoMode_Wrap(sdl.clip.w,sdl.clip.h,bpp,sdl_flags); - return sdl.surface; - } -} - -void GFX_TearDown(void) { - if (sdl.updating) - GFX_EndUpdate( 0 ); - - if (sdl.blit.surface) { - SDL_FreeSurface(sdl.blit.surface); - sdl.blit.surface=0; + sdl.window = GFX_SetSDLWindowMode(sdl.clip.w, sdl.clip.h, sdl.desktop.fullscreen, screenType); + return sdl.window; } } @@ -526,145 +578,136 @@ Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,G sdl.draw.scalex=scalex; sdl.draw.scaley=scaley; - int bpp=0; Bitu retFlags = 0; - - if (sdl.blit.surface) { - SDL_FreeSurface(sdl.blit.surface); - sdl.blit.surface=0; - } switch (sdl.desktop.want_type) { case SCREEN_SURFACE: dosurface: - if (flags & GFX_CAN_8) bpp=8; - if (flags & GFX_CAN_15) bpp=15; - if (flags & GFX_CAN_16) bpp=16; - if (flags & GFX_CAN_32) bpp=32; sdl.desktop.type=SCREEN_SURFACE; sdl.clip.w=width; sdl.clip.h=height; if (sdl.desktop.fullscreen) { if (sdl.desktop.full.fixed) { - sdl.clip.x=(Sint16)((sdl.desktop.full.width-width)/2); - sdl.clip.y=(Sint16)((sdl.desktop.full.height-height)/2); - sdl.surface=SDL_SetVideoMode_Wrap(sdl.desktop.full.width,sdl.desktop.full.height,bpp, - SDL_FULLSCREEN | ((flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE) | - (sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0) | SDL_HWPALETTE); - if (sdl.surface == NULL) E_Exit("Could not set fullscreen video mode %ix%i-%i: %s",sdl.desktop.full.width,sdl.desktop.full.height,bpp,SDL_GetError()); + sdl.clip.x = (Sint16)((sdl.desktop.full.width - width) / 2); + sdl.clip.y = (Sint16)((sdl.desktop.full.height - height) / 2); + sdl.window = GFX_SetSDLWindowMode(sdl.desktop.full.width, + sdl.desktop.full.height, + sdl.desktop.fullscreen, + sdl.desktop.type); + if (sdl.window == NULL) + E_Exit("Could not set fullscreen video mode %ix%i-%i: %s", + sdl.desktop.full.width, + sdl.desktop.full.height, + sdl.desktop.bpp, + SDL_GetError()); + + /* This may be required after an ALT-TAB leading to a window + minimize, which further effectively shrinks its size */ + if ((sdl.clip.x < 0) || (sdl.clip.y < 0)) { + sdl.update_display_contents = false; + } } else { - sdl.clip.x=0;sdl.clip.y=0; - sdl.surface=SDL_SetVideoMode_Wrap(width,height,bpp, - SDL_FULLSCREEN | ((flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE) | - (sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0)|SDL_HWPALETTE); - if (sdl.surface == NULL) - E_Exit("Could not set fullscreen video mode %ix%i-%i: %s",(int)width,(int)height,bpp,SDL_GetError()); + sdl.clip.x = 0; + sdl.clip.y = 0; + sdl.window = GFX_SetSDLWindowMode(width, + height, + sdl.desktop.fullscreen, + sdl.desktop.type); + if (sdl.window == NULL) + E_Exit("Could not set fullscreen video mode %ix%i-%i: %s", + (int)width, + (int)height, + sdl.desktop.bpp, + SDL_GetError()); } } else { - sdl.clip.x=0;sdl.clip.y=0; - sdl.surface=SDL_SetVideoMode_Wrap(width,height,bpp,(flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE); -#ifdef WIN32 - if (sdl.surface == NULL) { - SDL_QuitSubSystem(SDL_INIT_VIDEO); - if (!sdl.using_windib) { - LOG_MSG("Failed to create hardware surface.\nRestarting video subsystem with windib enabled."); - putenv("SDL_VIDEODRIVER=windib"); - sdl.using_windib=true; - } else { - LOG_MSG("Failed to create hardware surface.\nRestarting video subsystem with directx enabled."); - putenv("SDL_VIDEODRIVER=directx"); - sdl.using_windib=false; - } - SDL_InitSubSystem(SDL_INIT_VIDEO); - GFX_SetIcon(); //Set Icon again - sdl.surface = SDL_SetVideoMode_Wrap(width,height,bpp,SDL_HWSURFACE); - if(sdl.surface) GFX_SetTitle(-1,-1,false); //refresh title. - } -#endif - if (sdl.surface == NULL) - E_Exit("Could not set windowed video mode %ix%i-%i: %s",(int)width,(int)height,bpp,SDL_GetError()); + sdl.clip.x = 0; + sdl.clip.y = 0; + sdl.window = GFX_SetSDLWindowMode(width, + height, + sdl.desktop.fullscreen, + sdl.desktop.type); + if (sdl.window == NULL) + E_Exit("Could not set windowed video mode %ix%i-%i: %s", + (int)width, + (int)height, + sdl.desktop.bpp, + SDL_GetError()); } - if (sdl.surface) { - switch (sdl.surface->format->BitsPerPixel) { + sdl.surface = SDL_GetWindowSurface(sdl.window); + if (sdl.surface == NULL) + E_Exit("Could not retrieve window surface: %s",SDL_GetError()); + switch (sdl.surface->format->BitsPerPixel) { case 8: retFlags = GFX_CAN_8; - break; + break; case 15: retFlags = GFX_CAN_15; break; case 16: retFlags = GFX_CAN_16; - break; + break; case 32: retFlags = GFX_CAN_32; - break; - } - if (retFlags && (sdl.surface->flags & SDL_HWSURFACE)) - retFlags |= GFX_HARDWARE; - if (retFlags && (sdl.surface->flags & SDL_DOUBLEBUF)) { - sdl.blit.surface=SDL_CreateRGBSurface(SDL_HWSURFACE, - sdl.draw.width, sdl.draw.height, - sdl.surface->format->BitsPerPixel, - sdl.surface->format->Rmask, - sdl.surface->format->Gmask, - sdl.surface->format->Bmask, - 0); - /* If this one fails be ready for some flickering... */ - } + break; } + /* Fix a glitch with aspect=true occuring when + changing between modes with different dimensions */ + SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0)); + SDL_UpdateWindowSurface(sdl.window); break; -#if C_DDRAW - case SCREEN_SURFACE_DDRAW: - if (flags & GFX_CAN_15) bpp=15; - if (flags & GFX_CAN_16) bpp=16; - if (flags & GFX_CAN_32) bpp=32; - if (!GFX_SetupSurfaceScaled((sdl.desktop.doublebuf && sdl.desktop.fullscreen) ? SDL_DOUBLEBUF : 0,bpp)) goto dosurface; - sdl.blit.rect.top=sdl.clip.y; - sdl.blit.rect.left=sdl.clip.x; - sdl.blit.rect.right=sdl.clip.x+sdl.clip.w; - sdl.blit.rect.bottom=sdl.clip.y+sdl.clip.h; - sdl.blit.surface=SDL_CreateRGBSurface(SDL_HWSURFACE,sdl.draw.width,sdl.draw.height, - sdl.surface->format->BitsPerPixel, - sdl.surface->format->Rmask, - sdl.surface->format->Gmask, - sdl.surface->format->Bmask, - 0); - if (!sdl.blit.surface || (!sdl.blit.surface->flags&SDL_HWSURFACE)) { - if (sdl.blit.surface) { - SDL_FreeSurface(sdl.blit.surface); - sdl.blit.surface=0; - } - LOG_MSG("Failed to create ddraw surface, back to normal surface."); + case SCREEN_TEXTURE: + { + if (!GFX_SetupWindowScaled(sdl.desktop.want_type)) { + LOG_MSG("SDL:Can't set video mode, falling back to surface"); goto dosurface; } - switch (sdl.surface->format->BitsPerPixel) { - case 15: - retFlags = GFX_CAN_15 | GFX_SCALING | GFX_HARDWARE; - break; - case 16: - retFlags = GFX_CAN_16 | GFX_SCALING | GFX_HARDWARE; - break; - case 32: - retFlags = GFX_CAN_32 | GFX_SCALING | GFX_HARDWARE; - break; - } - sdl.desktop.type=SCREEN_SURFACE_DDRAW; - break; -#endif - case SCREEN_OVERLAY: - if (sdl.overlay) { - SDL_FreeYUVOverlay(sdl.overlay); - sdl.overlay=0; - } - if (!(flags&GFX_CAN_32) || (flags & GFX_RGBONLY)) goto dosurface; - if (!GFX_SetupSurfaceScaled(0,0)) goto dosurface; - sdl.overlay=SDL_CreateYUVOverlay(width*2,height,SDL_UYVY_OVERLAY,sdl.surface); - if (!sdl.overlay) { - LOG_MSG("SDL: Failed to create overlay, switching back to surface"); + if (strcmp(sdl.rendererDriver, "auto")) + SDL_SetHint(SDL_HINT_RENDER_DRIVER, sdl.rendererDriver); + sdl.renderer = SDL_CreateRenderer(sdl.window, -1, + SDL_RENDERER_ACCELERATED | + (sdl.desktop.vsync ? SDL_RENDERER_PRESENTVSYNC : 0)); + if (!sdl.renderer) { + LOG_MSG("%s\n", SDL_GetError()); + LOG_MSG("SDL:Can't create renderer, falling back to surface"); goto dosurface; } - sdl.desktop.type=SCREEN_OVERLAY; - retFlags = GFX_CAN_32 | GFX_SCALING | GFX_HARDWARE; + /* SDL_PIXELFORMAT_ARGB8888 is possible with most + rendering drivers, "opengles" being a notable exception */ + sdl.texture.texture = SDL_CreateTexture(sdl.renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + /* SDL_PIXELFORMAT_ABGR8888 (not RGB) is the + only supported format for the "opengles" driver */ + if (!sdl.texture.texture) { + if (flags & GFX_RGBONLY) goto dosurface; + sdl.texture.texture = SDL_CreateTexture(sdl.renderer, SDL_PIXELFORMAT_ABGR8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + } + if (!sdl.texture.texture) { + SDL_DestroyRenderer(sdl.renderer); + sdl.renderer = NULL; + LOG_MSG("SDL:Can't create texture, falling back to surface"); + goto dosurface; + } + SDL_SetRenderDrawColor(sdl.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + sdl.desktop.type=SCREEN_TEXTURE; + Uint32 pixelFormat; + SDL_QueryTexture(sdl.texture.texture, &pixelFormat, NULL, NULL, NULL); + sdl.texture.pixelFormat = SDL_AllocFormat(pixelFormat); + switch (SDL_BITSPERPIXEL(pixelFormat)) { + case 8: retFlags = GFX_CAN_8; break; + case 15: retFlags = GFX_CAN_15; break; + case 16: retFlags = GFX_CAN_16; break; + case 24: /* SDL_BYTESPERPIXEL is probably 4, though. */ + case 32: retFlags = GFX_CAN_32; break; + } + retFlags |= GFX_SCALING; + SDL_RendererInfo rendererInfo; + SDL_GetRendererInfo(sdl.renderer, &rendererInfo); + LOG_MSG("Using driver \"%s\" for renderer", rendererInfo.name); + if (rendererInfo.flags & SDL_RENDERER_ACCELERATED) + retFlags |= GFX_HARDWARE; break; + } #if C_OPENGL case SCREEN_OPENGL: { @@ -675,21 +718,28 @@ dosurface: free(sdl.opengl.framebuf); } sdl.opengl.framebuf=0; - if (!(flags&GFX_CAN_32)) goto dosurface; - int texsize=2 << int_log2(width > height ? width : height); + if (!(flags & GFX_CAN_32)) + goto dosurface; + int texsize = 2 << int_log2(width > height ? width : height); if (texsize>sdl.opengl.max_texsize) { LOG_MSG("SDL:OPENGL: No support for texturesize of %d, falling back to surface",texsize); goto dosurface; } - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); -#if SDL_VERSION_ATLEAST(1, 2, 11) - SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 ); -#endif - GFX_SetupSurfaceScaled(SDL_OPENGL,0); - if (!sdl.surface || sdl.surface->format->BitsPerPixel<15) { - LOG_MSG("SDL:OPENGL: Can't open drawing surface, are you running in 16bpp (or higher) mode?"); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + GFX_SetupWindowScaled(sdl.desktop.want_type); + /* We may simply use SDL_BYTESPERPIXEL + here rather than SDL_BITSPERPIXEL */ + if (!sdl.window || SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(sdl.window))<2) { + LOG_MSG("SDL:OPENGL:Can't open drawing window, are you running in 16bpp(or higher) mode?"); goto dosurface; } + sdl.opengl.context = SDL_GL_CreateContext(sdl.window); + if (sdl.opengl.context == NULL) { + LOG_MSG("SDL:OPENGL:Can't create OpenGL context, falling back to surface"); + goto dosurface; + } + /* Sync to VBlank if desired */ + SDL_GL_SetSwapInterval(sdl.desktop.vsync ? 1 : 0); /* Create the texture and display list */ if (sdl.opengl.pixel_buffer_object) { glGenBuffersARB(1, &sdl.opengl.buffer); @@ -697,16 +747,30 @@ dosurface: glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, width*height*4, NULL, GL_STREAM_DRAW_ARB); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0); } else { - sdl.opengl.framebuf=malloc(width*height*4); //32 bit color + sdl.opengl.framebuf = malloc(width * height * 4); // 32 bit color } sdl.opengl.pitch=width*4; - if(sdl.clip.x ==0 && sdl.clip.y ==0 && sdl.desktop.fullscreen && !sdl.desktop.full.fixed && (sdl.clip.w != sdl.surface->w || sdl.clip.h != sdl.surface->h)) { -// LOG_MSG("attempting to fix the centering to %d %d %d %d",(sdl.surface->w-sdl.clip.w)/2,(sdl.surface->h-sdl.clip.h)/2,sdl.clip.w,sdl.clip.h); - glViewport((sdl.surface->w-sdl.clip.w)/2,(sdl.surface->h-sdl.clip.h)/2,sdl.clip.w,sdl.clip.h); + int windowWidth, windowHeight; + SDL_GetWindowSize(sdl.window, &windowWidth, &windowHeight); + if (sdl.clip.x == 0 && sdl.clip.y == 0 && + sdl.desktop.fullscreen && + !sdl.desktop.full.fixed && + (sdl.clip.w != windowWidth || sdl.clip.h != windowHeight)) { + // LOG_MSG("attempting to fix the centering to %d %d %d %d",(windowWidth-sdl.clip.w)/2,(windowHeight-sdl.clip.h)/2,sdl.clip.w,sdl.clip.h); + glViewport((windowWidth - sdl.clip.w) / 2, + (windowHeight - sdl.clip.h) / 2, + sdl.clip.w, + sdl.clip.h); } else { - glViewport(sdl.clip.x,sdl.clip.y,sdl.clip.w,sdl.clip.h); - } + /* We don't just pass sdl.clip.y as-is, so we cover the case of non-vertical + * centering on Android (in order to leave room for the on-screen keyboard) + */ + glViewport(sdl.clip.x, + windowHeight - (sdl.clip.y + sdl.clip.h), + sdl.clip.w, + sdl.clip.h); + } glMatrixMode (GL_PROJECTION); glDeleteTextures(1,&sdl.opengl.texture); @@ -729,9 +793,6 @@ dosurface: delete [] emptytex; glClearColor (0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - SDL_GL_SwapBuffers(); - glClear(GL_COLOR_BUFFER_BIT); glShadeModel (GL_FLAT); glDisable (GL_DEPTH_TEST); glDisable (GL_LIGHTING); @@ -746,6 +807,7 @@ dosurface: if (glIsList(sdl.opengl.displaylist)) glDeleteLists(sdl.opengl.displaylist, 1); sdl.opengl.displaylist = glGenLists(1); glNewList(sdl.opengl.displaylist, GL_COMPILE); + glClear(GL_COLOR_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture); glBegin(GL_TRIANGLES); @@ -775,30 +837,19 @@ dosurface: return retFlags; } + void GFX_CaptureMouse(void) { sdl.mouse.locked=!sdl.mouse.locked; if (sdl.mouse.locked) { - SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_SetRelativeMouseMode(SDL_TRUE); SDL_ShowCursor(SDL_DISABLE); } else { - SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_SetRelativeMouseMode(SDL_FALSE); if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE); } mouselocked=sdl.mouse.locked; } -void GFX_UpdateSDLCaptureState(void) { - if (sdl.mouse.locked) { - SDL_WM_GrabInput(SDL_GRAB_ON); - SDL_ShowCursor(SDL_DISABLE); - } else { - SDL_WM_GrabInput(SDL_GRAB_OFF); - if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE); - } - CPU_Reset_AutoAdjust(); - GFX_SetTitle(-1,-1,false); -} - bool mouselocked; //Global variable for mapper static void CaptureMouse(bool pressed) { if (!pressed) @@ -870,56 +921,38 @@ bool GFX_LazyFullscreenRequested(void) { return false; } -void GFX_RestoreMode(void) { - GFX_SetSize(sdl.draw.width,sdl.draw.height,sdl.draw.flags,sdl.draw.scalex,sdl.draw.scaley,sdl.draw.callback); - GFX_UpdateSDLCaptureState(); -} - - bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) { + if (!sdl.update_display_contents) + return false; if (!sdl.active || sdl.updating) return false; switch (sdl.desktop.type) { case SCREEN_SURFACE: - if (sdl.blit.surface) { - if (SDL_MUSTLOCK(sdl.blit.surface) && SDL_LockSurface(sdl.blit.surface)) - return false; - pixels=(Bit8u *)sdl.blit.surface->pixels; - pitch=sdl.blit.surface->pitch; - } else { - if (SDL_MUSTLOCK(sdl.surface) && SDL_LockSurface(sdl.surface)) - return false; - pixels=(Bit8u *)sdl.surface->pixels; - pixels+=sdl.clip.y*sdl.surface->pitch; - pixels+=sdl.clip.x*sdl.surface->format->BytesPerPixel; - pitch=sdl.surface->pitch; - } - sdl.updating=true; + pixels = (Bit8u *)sdl.surface->pixels; + pixels += sdl.clip.y * sdl.surface->pitch; + pixels += sdl.clip.x * sdl.surface->format->BytesPerPixel; + pitch = sdl.surface->pitch; + sdl.updating = true; return true; -#if C_DDRAW - case SCREEN_SURFACE_DDRAW: - if (SDL_LockSurface(sdl.blit.surface)) { -// LOG_MSG("SDL Lock failed"); + case SCREEN_TEXTURE: + { + void * texPixels; + int texPitch; + if (SDL_LockTexture(sdl.texture.texture, NULL, &texPixels, &texPitch) < 0) return false; - } - pixels=(Bit8u *)sdl.blit.surface->pixels; - pitch=sdl.blit.surface->pitch; - sdl.updating=true; - return true; -#endif - case SCREEN_OVERLAY: - if (SDL_LockYUVOverlay(sdl.overlay)) return false; - pixels=(Bit8u *)*(sdl.overlay->pixels); - pitch=*(sdl.overlay->pitches); + pixels = (Bit8u *)texPixels; + pitch = texPitch; sdl.updating=true; return true; + } #if C_OPENGL case SCREEN_OPENGL: if(sdl.opengl.pixel_buffer_object) { glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, sdl.opengl.buffer); pixels=(Bit8u *)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY); - } else + } else { pixels=(Bit8u *)sdl.opengl.framebuf; + } pitch=sdl.opengl.pitch; sdl.updating=true; return true; @@ -932,24 +965,14 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) { void GFX_EndUpdate( const Bit16u *changedLines ) { -#if C_DDRAW - int ret; -#endif + if (!sdl.update_display_contents) + return; if (!sdl.updating) return; sdl.updating=false; switch (sdl.desktop.type) { case SCREEN_SURFACE: - if (SDL_MUSTLOCK(sdl.surface)) { - if (sdl.blit.surface) { - SDL_UnlockSurface(sdl.blit.surface); - int Blit = SDL_BlitSurface( sdl.blit.surface, 0, sdl.surface, &sdl.clip ); - LOG(LOG_MISC,LOG_WARN)("BlitSurface returned %d",Blit); - } else { - SDL_UnlockSurface(sdl.surface); - } - SDL_Flip(sdl.surface); - } else if (changedLines) { + if (changedLines) { Bitu y = 0, index = 0, rectCount = 0; while (y < sdl.draw.height) { if (!(index & 1)) { @@ -960,42 +983,19 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { rect->y = sdl.clip.y + y; rect->w = (Bit16u)sdl.draw.width; rect->h = changedLines[index]; -#if 0 - if (rect->h + rect->y > sdl.surface->h) { - LOG_MSG("WTF %d + %d >%d",rect->h,rect->y,sdl.surface->h); - } -#endif y += changedLines[index]; } index++; } if (rectCount) - SDL_UpdateRects( sdl.surface, rectCount, sdl.updateRects ); + SDL_UpdateWindowSurfaceRects(sdl.window, sdl.updateRects, rectCount); } break; -#if C_DDRAW - case SCREEN_SURFACE_DDRAW: - SDL_UnlockSurface(sdl.blit.surface); - ret=IDirectDrawSurface3_Blt( - sdl.surface->hwdata->dd_writebuf,&sdl.blit.rect, - sdl.blit.surface->hwdata->dd_surface,0, - DDBLT_WAIT, NULL); - switch (ret) { - case DD_OK: - break; - case DDERR_SURFACELOST: - IDirectDrawSurface3_Restore(sdl.blit.surface->hwdata->dd_surface); - IDirectDrawSurface3_Restore(sdl.surface->hwdata->dd_surface); - break; - default: - LOG_MSG("DDRAW: Failed to blit, error %X",ret); - } - SDL_Flip(sdl.surface); - break; -#endif - case SCREEN_OVERLAY: - SDL_UnlockYUVOverlay(sdl.overlay); - SDL_DisplayYUVOverlay(sdl.overlay,&sdl.clip); + case SCREEN_TEXTURE: + SDL_UnlockTexture(sdl.texture.texture); + SDL_RenderClear(sdl.renderer); + SDL_RenderCopy(sdl.renderer, sdl.texture.texture, NULL, &sdl.clip); + SDL_RenderPresent(sdl.renderer); break; #if C_OPENGL case SCREEN_OPENGL: @@ -1011,7 +1011,7 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { GL_UNSIGNED_INT_8_8_8_8_REV, 0); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0); glCallList(sdl.opengl.displaylist); - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(sdl.window); } else if (changedLines) { Bitu y = 0, index = 0; glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture); @@ -1029,7 +1029,7 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { index++; } glCallList(sdl.opengl.displaylist); - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(sdl.window); } break; #endif @@ -1038,39 +1038,16 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { } } - void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) { - /* I should probably not change the GFX_PalEntry :) */ - if (sdl.surface->flags & SDL_HWPALETTE) { - if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,start,count)) { - E_Exit("SDL:Can't set palette"); - } - } else { - if (!SDL_SetPalette(sdl.surface,SDL_LOGPAL,(SDL_Color *)entries,start,count)) { - E_Exit("SDL:Can't set palette"); - } - } } Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue) { switch (sdl.desktop.type) { case SCREEN_SURFACE: - case SCREEN_SURFACE_DDRAW: return SDL_MapRGB(sdl.surface->format,red,green,blue); - case SCREEN_OVERLAY: - { - Bit8u y = ( 9797*(red) + 19237*(green) + 3734*(blue) ) >> 15; - Bit8u u = (18492*((blue)-(y)) >> 15) + 128; - Bit8u v = (23372*((red)-(y)) >> 15) + 128; -#ifdef WORDS_BIGENDIAN - return (y << 0) | (v << 8) | (y << 16) | (u << 24); -#else - return (u << 0) | (y << 8) | (v << 16) | (y << 24); -#endif - } + case SCREEN_TEXTURE: + return SDL_MapRGB(sdl.texture.pixelFormat, red, green, blue); case SCREEN_OPENGL: -// return ((red << 0) | (green << 8) | (blue << 16)) | (255 << 24); - //USE BGRA return ((blue << 0) | (green << 8) | (red << 16)) | (255 << 24); } return 0; @@ -1086,6 +1063,30 @@ void GFX_Start() { sdl.active=true; } +void GFX_ObtainDisplayDimensions() { + SDL_Rect displayDimensions; + SDL_GetDisplayBounds(sdl.displayNumber, &displayDimensions); + sdl.desktop.full.width = displayDimensions.w; + sdl.desktop.full.height = displayDimensions.h; +} + +/* Manually update display dimensions in case of a window resize, + * IF there is the need for that ("yes" on Android, "no" otherwise). + * Used for the mapper UI on Android. + * Reason is the usage of GFX_GetSDLSurfaceSubwindowDims, as well as a + * mere notification of the fact that the window's dimensions are modified. + */ +void GFX_UpdateDisplayDimensions(int width, int height) +{ + if (sdl.desktop.full.display_res && sdl.desktop.fullscreen) { + /* Note: We should not use GFX_ObtainDisplayDimensions + (SDL_GetDisplayBounds) on Android after a screen rotation: + The older values from application startup are returned. */ + sdl.desktop.full.width = width; + sdl.desktop.full.height = height; + } +} + static void GUI_ShutDown(Section * /*sec*/) { GFX_Stop(); if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop ); @@ -1176,6 +1177,8 @@ static void GUI_StartUp(Section * sec) { Section_prop * section=static_cast(sec); sdl.active=false; sdl.updating=false; + sdl.resizing_window = false; + sdl.update_display_contents = true; GFX_SetIcon(); @@ -1231,7 +1234,6 @@ static void GUI_StartUp(Section * sec) { } } } - sdl.desktop.window.width = 0; sdl.desktop.window.height = 0; const char* windowresolution=section->Get_string("windowresolution"); @@ -1248,47 +1250,18 @@ static void GUI_StartUp(Section * sec) { } } } - sdl.desktop.doublebuf=section->Get_bool("fulldouble"); -#if SDL_VERSION_ATLEAST(1, 2, 10) -#ifdef WIN32 - const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo(); - if (vidinfo) { - int sdl_w = vidinfo->current_w; - int sdl_h = vidinfo->current_h; - int win_w = GetSystemMetrics(SM_CXSCREEN); - int win_h = GetSystemMetrics(SM_CYSCREEN); - if (sdl_w != win_w && sdl_h != win_h) - LOG_MSG("Windows dpi/blurry apps scaling detected! The screen might be too large or not\n" - "show properly, please see the DOSBox options file (fullresolution) for details.\n"); - } -#else - if (!sdl.desktop.full.width || !sdl.desktop.full.height){ - //Can only be done on the very first call! Not restartable. - //On windows don't use it as SDL returns the values without taking in account the dpi scaling - const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo(); - if (vidinfo) { - sdl.desktop.full.width = vidinfo->current_w; - sdl.desktop.full.height = vidinfo->current_h; - } - } -#endif -#endif - if (!sdl.desktop.full.width) { -#ifdef WIN32 - sdl.desktop.full.width=(Bit16u)GetSystemMetrics(SM_CXSCREEN); -#else - LOG_MSG("Your fullscreen resolution can NOT be determined, it's assumed to be 1024x768.\nPlease edit the configuration file if this value is wrong."); - sdl.desktop.full.width=1024; -#endif + sdl.desktop.vsync = section->Get_bool("vsync"); + sdl.displayNumber = section->Get_int("display"); + if ((sdl.displayNumber < 0) || (sdl.displayNumber >= SDL_GetNumVideoDisplays())) { + sdl.displayNumber = 0; + LOG_MSG("SDL:Display number out of bounds, switching back to 0"); } - if (!sdl.desktop.full.height) { -#ifdef WIN32 - sdl.desktop.full.height=(Bit16u)GetSystemMetrics(SM_CYSCREEN); -#else - sdl.desktop.full.height=768; -#endif + sdl.desktop.full.display_res = sdl.desktop.full.fixed && (!sdl.desktop.full.width || !sdl.desktop.full.height); + if (sdl.desktop.full.display_res) { + GFX_ObtainDisplayDimensions(); } + sdl.mouse.autoenable=section->Get_bool("autolock"); if (!sdl.mouse.autoenable) SDL_ShowCursor(SDL_DISABLE); sdl.mouse.autolock=false; @@ -1303,12 +1276,13 @@ static void GUI_StartUp(Section * sec) { if (output == "surface") { sdl.desktop.want_type=SCREEN_SURFACE; -#if C_DDRAW - } else if (output == "ddraw") { - sdl.desktop.want_type=SCREEN_SURFACE_DDRAW; -#endif - } else if (output == "overlay") { - sdl.desktop.want_type=SCREEN_OVERLAY; + } else if (output == "texture") { + sdl.desktop.want_type=SCREEN_TEXTURE; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + } else if (output == "texturenb") { + sdl.desktop.want_type=SCREEN_TEXTURE; + // Currently the default, but... oh well + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); #if C_OPENGL } else if (output == "opengl") { sdl.desktop.want_type=SCREEN_OPENGL; @@ -1322,18 +1296,30 @@ static void GUI_StartUp(Section * sec) { sdl.desktop.want_type=SCREEN_SURFACE;//SHOULDN'T BE POSSIBLE anymore } - sdl.overlay=0; + sdl.texture.texture = 0; + sdl.texture.pixelFormat = 0; + sdl.window = 0; + sdl.renderer = 0; + sdl.rendererDriver = section->Get_string("renderer"); + #if C_OPENGL if(sdl.desktop.want_type==SCREEN_OPENGL){ /* OPENGL is requested */ - sdl.surface=SDL_SetVideoMode_Wrap(640,400,0,SDL_OPENGL); - if (sdl.surface == NULL) { - LOG_MSG("Could not initialize OpenGL, switching back to surface"); + if (!GFX_SetSDLOpenGLWindow(640, 400)) { + LOG_MSG("Could not create OpenGL window, switching back to surface"); sdl.desktop.want_type=SCREEN_SURFACE; } else { + sdl.opengl.context = SDL_GL_CreateContext(sdl.window); + if (sdl.opengl.context == 0) { + LOG_MSG("Could not create OpenGL context, switching back to surface"); + sdl.desktop.want_type=SCREEN_SURFACE; + } + } + if (sdl.desktop.want_type==SCREEN_OPENGL) { sdl.opengl.buffer=0; sdl.opengl.framebuf=0; sdl.opengl.texture=0; sdl.opengl.displaylist=0; + glGetIntegerv (GL_MAX_TEXTURE_SIZE, &sdl.opengl.max_texsize); glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)SDL_GL_GetProcAddress("glGenBuffersARB"); glBindBufferARB = (PFNGLBINDBUFFERARBPROC)SDL_GL_GetProcAddress("glBindBufferARB"); @@ -1356,14 +1342,24 @@ static void GUI_StartUp(Section * sec) { #endif //OPENGL /* Initialize screen for first time */ - sdl.surface=SDL_SetVideoMode_Wrap(640,400,0,0); - if (sdl.surface == NULL) E_Exit("Could not initialize video: %s",SDL_GetError()); - sdl.desktop.bpp=sdl.surface->format->BitsPerPixel; + if (!GFX_SetSDLSurfaceWindow(640, 400)) + E_Exit("Could not initialize video: %s", SDL_GetError()); + sdl.surface = SDL_GetWindowSurface(sdl.window); + if (sdl.surface == NULL) + E_Exit("Could not retrieve window surface: %s", SDL_GetError()); + SDL_Rect splash_rect = GFX_GetSDLSurfaceSubwindowDims(640, 400); + sdl.desktop.sdl2pixelFormat = sdl.surface->format->format; + LOG_MSG("SDL:Current window pixel format: %s", + SDL_GetPixelFormatName(sdl.desktop.sdl2pixelFormat)); + /* Do NOT use SDL_BITSPERPIXEL here - It returns 24 for + SDL_PIXELFORMAT_RGB888, while SDL_BYTESPERPIXEL returns 4. + To compare, with SDL 1.2 the detected desktop color depth is 32 bpp. */ + sdl.desktop.bpp=8*SDL_BYTESPERPIXEL(sdl.desktop.sdl2pixelFormat); if (sdl.desktop.bpp==24) { LOG_MSG("SDL: You are running in 24 bpp mode, this will slow down things!"); } GFX_Stop(); - SDL_WM_SetCaption("DOSBox",VERSION); + SDL_SetWindowTitle(sdl.window, "DOSBox"); /* The endian part is intentionally disabled as somehow it produces correct results without according to rhoenie*/ //#if SDL_BYTEORDER == SDL_BIG_ENDIAN @@ -1379,6 +1375,7 @@ static void GUI_StartUp(Section * sec) { /* Please leave the Splash screen stuff in working order in DOSBox. We spend a lot of time making DOSBox. */ SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 400, 32, rmask, gmask, bmask, 0); if (splash_surf) { + SDL_SetSurfaceBlendMode(splash_surf, SDL_BLENDMODE_BLEND); SDL_FillRect(splash_surf, NULL, SDL_MapRGB(splash_surf->format, 0, 0, 0)); Bit8u* tmpbufp = new Bit8u[640*400*3]; @@ -1414,23 +1411,24 @@ static void GUI_StartUp(Section * sec) { if (ct<1) { SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0)); - SDL_SetAlpha(splash_surf, SDL_SRCALPHA,255); - SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL); - SDL_Flip(sdl.surface); + SDL_SetSurfaceAlphaMod(splash_surf, 255); + SDL_BlitScaled(splash_surf, NULL, sdl.surface, &splash_rect); + SDL_UpdateWindowSurface(sdl.window); } else if (ct>=max_splash_loop-splash_fade) { if (use_fadeout) { SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0)); - SDL_SetAlpha(splash_surf, SDL_SRCALPHA, (Bit8u)((max_splash_loop-1-ct)*255/(splash_fade-1))); - SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL); - SDL_Flip(sdl.surface); + SDL_SetSurfaceAlphaMod(splash_surf, (Bit8u)((max_splash_loop-1-ct)*255/(splash_fade-1))); + SDL_BlitScaled(splash_surf, NULL, sdl.surface, &splash_rect); + SDL_UpdateWindowSurface(sdl.window); } + } else { // Fix a possible glitch + SDL_UpdateWindowSurface(sdl.window); } - } if (use_fadeout) { SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0)); - SDL_Flip(sdl.surface); + SDL_UpdateWindowSurface(sdl.window); } SDL_FreeSurface(splash_surf); delete [] tmpbufp; @@ -1448,7 +1446,7 @@ static void GUI_StartUp(Section * sec) { MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD2, "pause", "Pause DBox"); #endif /* Get Keyboard state of numlock and capslock */ - SDLMod keystate = SDL_GetModState(); + SDL_Keymod keystate = SDL_GetModState(); if(keystate&KMOD_NUM) startup_state_numlock = true; if(keystate&KMOD_CAPS) startup_state_capslock = true; } @@ -1528,11 +1526,32 @@ bool GFX_IsFullscreen(void) { #define DB_POLLSKIP 1 #endif -#if defined(LINUX) -#define SDL_XORG_FIX 1 -#else -#define SDL_XORG_FIX 0 -#endif +void GFX_HandleVideoResize(int width, int height) +{ + /* Maybe a screen rotation has just occurred, so we simply resize. + There may be a different cause for a forced resized, though. */ + if (sdl.desktop.full.display_res && sdl.desktop.fullscreen) { + /* Note: We should not use GFX_ObtainDisplayDimensions + (SDL_GetDisplayBounds) on Android after a screen rotation: + The older values from application startup are returned. */ + sdl.desktop.full.width = width; + sdl.desktop.full.height = height; + } + /* Even if the new window's dimensions are actually the desired ones + * we may still need to re-obtain a new window surface or do + * a different thing. So we basically reset the screen, but without + * touching the window itself (or else we may end in an infinite loop). + * + * Furthermore, if the new dimensions are *not* the desired ones, we + * don't fight it. Rather than attempting to resize it back, we simply + * keep the window as-is and disable screen updates. This is done + * in SDL_SetSDLWindowSurface by setting sdl.update_display_contents + * to false. + */ + sdl.resizing_window = true; + GFX_ResetScreen(); + sdl.resizing_window = false; +} void GFX_Events() { //Don't poll too often. This can be heavy on the OS, especially Macs. @@ -1557,31 +1576,29 @@ void GFX_Events() { } #endif while (SDL_PollEvent(&event)) { -#if SDL_XORG_FIX - // Special code for broken SDL with Xorg 1.20.1, where pairs of inputfocus gain and loss events are generated - // when locking the mouse in windowed mode. - if (event.type == SDL_ACTIVEEVENT && event.active.state == SDL_APPINPUTFOCUS && event.active.gain == 0) { - SDL_Event test; //Check if the next event would undo this one. - if (SDL_PeepEvents(&test,1,SDL_PEEKEVENT,SDL_ACTIVEEVENTMASK) == 1 && test.active.state == SDL_APPINPUTFOCUS && test.active.gain == 1) { - // Skip both events. - SDL_PeepEvents(&test,1,SDL_GETEVENT,SDL_ACTIVEEVENTMASK); - continue; - } - } -#endif - switch (event.type) { - case SDL_ACTIVEEVENT: - if (event.active.state & SDL_APPINPUTFOCUS) { - if (event.active.gain) { -#ifdef WIN32 - if (!sdl.desktop.fullscreen) sdl.focus_ticks = GetTicks(); -#endif + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_RESTORED: + /* We may need to re-create a texture + * and more on Android. Another case: + * Update surface while using X11. + */ + GFX_ResetScreen(); + continue; + case SDL_WINDOWEVENT_RESIZED: + GFX_HandleVideoResize(event.window.data1, event.window.data2); + continue; + case SDL_WINDOWEVENT_EXPOSED: + if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw ); + continue; + case SDL_WINDOWEVENT_FOCUS_GAINED: if (sdl.desktop.fullscreen && !sdl.mouse.locked) GFX_CaptureMouse(); SetPriority(sdl.priority.focus); CPU_Disable_SkipAutoAdjust(); - } else { + break; + case SDL_WINDOWEVENT_FOCUS_LOST: if (sdl.mouse.locked) { #ifdef WIN32 if (sdl.desktop.fullscreen) { @@ -1594,14 +1611,15 @@ void GFX_Events() { SetPriority(sdl.priority.nofocus); GFX_LosingFocus(); CPU_Enable_SkipAutoAdjust(); - } + break; + default: ; } /* Non-focus priority is set to pause; check to see if we've lost window or input focus * i.e. has the window been minimised or made inactive? */ if (sdl.priority.nofocus == PRIORITY_LEVEL_PAUSE) { - if ((event.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) && (!event.active.gain)) { + if ((event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) || (event.window.event == SDL_WINDOWEVENT_MINIMIZED)) { /* Window has lost focus, pause the emulator. * This is similar to what PauseDOSBox() does, but the exit criteria is different. * Instead of waiting for the user to hit Alt-Break, we wait for the window to @@ -1623,10 +1641,10 @@ void GFX_Events() { switch (ev.type) { case SDL_QUIT: throw(0); break; // a bit redundant at linux at least as the active events gets before the quit event. - case SDL_ACTIVEEVENT: // wait until we get window focus back - if (ev.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) { + case SDL_WINDOWEVENT: // wait until we get window focus back + if ((ev.window.event == SDL_WINDOWEVENT_FOCUS_LOST) || (ev.window.event == SDL_WINDOWEVENT_MINIMIZED) || (ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) || (ev.window.event == SDL_WINDOWEVENT_RESTORED) || (ev.window.event == SDL_WINDOWEVENT_EXPOSED)) { // We've got focus back, so unpause and break out of the loop - if (ev.active.gain) { + if ((ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) || (ev.window.event == SDL_WINDOWEVENT_RESTORED) || (ev.window.event == SDL_WINDOWEVENT_EXPOSED)) { paused = false; GFX_SetTitle(-1,-1,false); } @@ -1637,6 +1655,10 @@ void GFX_Events() { */ KEYBOARD_AddKey(KBD_leftalt, false); KEYBOARD_AddKey(KBD_rightalt, false); + if (ev.window.event == SDL_WINDOWEVENT_RESTORED) { + // We may need to re-create a texture and more + GFX_ResetScreen(); + } } break; } @@ -1651,23 +1673,19 @@ void GFX_Events() { case SDL_MOUSEBUTTONUP: HandleMouseButton(&event.button); break; - case SDL_VIDEORESIZE: -// HandleVideoResize(&event.resize); - break; case SDL_QUIT: throw(0); break; - case SDL_VIDEOEXPOSE: - if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw ); - break; #ifdef WIN32 case SDL_KEYDOWN: case SDL_KEYUP: // ignore event alt+tab - if (event.key.keysym.sym==SDLK_LALT) sdl.laltstate = event.key.type; - if (event.key.keysym.sym==SDLK_RALT) sdl.raltstate = event.key.type; - if (((event.key.keysym.sym==SDLK_TAB)) && - ((sdl.laltstate==SDL_KEYDOWN) || (sdl.raltstate==SDL_KEYDOWN))) break; + if (event.key.keysym.sym == SDLK_LALT) + sdl.laltstate = (SDL_EventType)event.key.type; + if (event.key.keysym.sym == SDLK_RALT) + sdl.raltstate = (SDL_EventType)event.key.type; + if (((event.key.keysym.sym==SDLK_TAB)) && ((sdl.laltstate==SDL_KEYDOWN) || (sdl.raltstate==SDL_KEYDOWN))) + break; // This can happen as well. if (((event.key.keysym.sym == SDLK_TAB )) && (event.key.keysym.mod & KMOD_ALT)) break; // ignore tab events that arrive just after regaining focus. (likely the result of alt-tab) @@ -1677,7 +1695,8 @@ void GFX_Events() { case SDL_KEYDOWN: case SDL_KEYUP: /* On macs CMD-Q is the default key to close an application */ - if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) { + if (event.key.keysym.sym == SDLK_q && + (event.key.keysym.mod == KMOD_RGUI || event.key.keysym.mod == KMOD_LGUI)) { KillSwitch(true); break; } @@ -1733,13 +1752,14 @@ void Config_Add_SDL() { Pbool = sdl_sec->Add_bool("fullscreen",Property::Changeable::Always,false); Pbool->Set_help("Start dosbox directly in fullscreen. (Press ALT-Enter to go back)"); - Pbool = sdl_sec->Add_bool("fulldouble",Property::Changeable::Always,false); - Pbool->Set_help("Use double buffering in fullscreen. It can reduce screen flickering, but it can also result in a slow DOSBox."); + Pbool = sdl_sec->Add_bool("vsync", Property::Changeable::Always, false); + Pbool->Set_help("Sync to Vblank IF supported by the output device and renderer.\n" + "It can reduce screen flickering, but it can also result in a slow DOSBox."); - Pstring = sdl_sec->Add_string("fullresolution",Property::Changeable::Always,"original"); + Pstring = sdl_sec->Add_string("fullresolution", Property::Changeable::Always, "0x0"); Pstring->Set_help("What resolution to use for fullscreen: original, desktop or a fixed size (e.g. 1024x768).\n" "Using your monitor's native resolution with aspect=true might give the best results.\n" - "If you end up with small window on a large screen, try an output different from surface." + "If you end up with small window on a large screen, try an output different from surface." "On Windows 10 with display scaling (Scale and layout) set to a value above 100%, it is recommended\n" "to use a lower full/windowresolution, in order to avoid window size problems."); @@ -1747,19 +1767,36 @@ void Config_Add_SDL() { Pstring->Set_help("Scale the window to this size IF the output device supports hardware scaling.\n" "(output=surface does not!)"); - const char* outputs[] = { - "surface", "overlay", + const char *outputs[] = { + "surface", + "texture", + "texturenb", #if C_OPENGL - "opengl", "openglnb", + "opengl", + "openglnb", #endif -#if C_DDRAW - "ddraw", -#endif - 0 }; - Pstring = sdl_sec->Add_string("output",Property::Changeable::Always,"surface"); + 0 + }; + Pstring = sdl_sec->Add_string("output",Property::Changeable::Always,"texture"); Pstring->Set_help("What video system to use for output."); Pstring->Set_values(outputs); + const char *renderers[] = { + "auto", +#ifdef WIN32 + "direct3d", +#endif + "opengl", +#ifdef MACOSX + "metal", +#endif + "software", + 0 + }; + Pstring = sdl_sec->Add_string("renderer",Property::Changeable::Always,"auto"); + Pstring->Set_help("Choose a renderer driver if output=texture or output=texturenb. Use output=auto for an automatic choice."); + Pstring->Set_values(renderers); + Pbool = sdl_sec->Add_bool("autolock",Property::Changeable::Always,true); Pbool->Set_help("Mouse will automatically lock, if you click on the screen. (Press CTRL-F10 to unlock)"); @@ -1789,9 +1826,6 @@ void Config_Add_SDL() { Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,MAPPERFILE); Pstring->Set_help("File used to load/save the key/event mappings from. Resetmapper only works with the default value."); - - Pbool = sdl_sec->Add_bool("usescancodes",Property::Changeable::Always,true); - Pbool->Set_help("Avoid usage of symkeys, might not work on all operating systems."); } static void show_warning(char const * const message) { @@ -1803,8 +1837,13 @@ static void show_warning(char const * const message) { #endif printf("%s",message); if(textonly) return; - if(!sdl.surface) sdl.surface = SDL_SetVideoMode_Wrap(640,400,0,0); - if(!sdl.surface) return; + if (!sdl.window) + if (!GFX_SetSDLSurfaceWindow(640, 400)) + return; + sdl.surface = SDL_GetWindowSurface(sdl.window); + if(!sdl.surface) + return; + #if SDL_BYTEORDER == SDL_BIG_ENDIAN Bit32u rmask = 0xff000000; Bit32u gmask = 0x00ff0000; @@ -1832,7 +1871,7 @@ static void show_warning(char const * const message) { } SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL); - SDL_Flip(sdl.surface); + SDL_UpdateWindowSurface(sdl.window); SDL_Delay(12000); } @@ -1862,6 +1901,8 @@ static void launcheditor() { extern void DEBUG_ShutDown(Section * /*sec*/); #endif +void MIXER_CloseAudioDevice(void); + void restart_program(std::vector & parameters) { char** newargs = new char* [parameters.size() + 1]; // parameter 0 is the executable path @@ -1869,9 +1910,9 @@ void restart_program(std::vector & parameters) { // last one is NULL for(Bitu i = 0; i < parameters.size(); i++) newargs[i] = (char*)parameters[i].c_str(); newargs[parameters.size()] = NULL; - SDL_CloseAudio(); + MIXER_CloseAudioDevice(); SDL_Delay(50); - SDL_Quit(); + SDL_Quit_Wrapper(); #if C_DEBUG // shutdown curses DEBUG_ShutDown(NULL); @@ -2040,17 +2081,13 @@ int main(int argc, char* argv[]) { LOG_MSG("---"); /* Init SDL */ -#if SDL_VERSION_ATLEAST(1, 2, 14) /* Or debian/ubuntu with older libsdl version as they have done this themselves, but then differently. * with this variable they will work correctly. I've only tested the 1.2.14 behaviour against the windows version * of libsdl */ putenv(const_cast("SDL_DISABLE_LOCK_KEYS=1")); -#endif - // Don't init timers, GetTicks seems to work fine and they can use a fair amount of power (Macs again) - // Please report problems with audio and other things. - if ( SDL_Init( SDL_INIT_AUDIO|SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE - ) < 0 ) E_Exit("Can't init SDL %s",SDL_GetError()); + if (SDL_Init_Wrapper() < 0) + E_Exit("Can't init SDL %s", SDL_GetError()); sdl.inited = true; #ifndef DISABLE_JOYSTICK @@ -2062,35 +2099,6 @@ int main(int argc, char* argv[]) { sdl.laltstate = SDL_KEYUP; sdl.raltstate = SDL_KEYUP; -#if defined (WIN32) -#if SDL_VERSION_ATLEAST(1, 2, 10) - sdl.using_windib=true; -#else - sdl.using_windib=false; -#endif - char sdl_drv_name[128]; - if (getenv("SDL_VIDEODRIVER")==NULL) { - if (SDL_VideoDriverName(sdl_drv_name,128)!=NULL) { - sdl.using_windib=false; - if (strcmp(sdl_drv_name,"directx")!=0) { - SDL_QuitSubSystem(SDL_INIT_VIDEO); - putenv("SDL_VIDEODRIVER=directx"); - if (SDL_InitSubSystem(SDL_INIT_VIDEO)<0) { - putenv("SDL_VIDEODRIVER=windib"); - if (SDL_InitSubSystem(SDL_INIT_VIDEO)<0) E_Exit("Can't init SDL Video %s",SDL_GetError()); - sdl.using_windib=true; - } - } - } - } else { - char* sdl_videodrv = getenv("SDL_VIDEODRIVER"); - if (strcmp(sdl_videodrv,"directx")==0) sdl.using_windib = false; - else if (strcmp(sdl_videodrv,"windib")==0) sdl.using_windib = true; - } - if (SDL_VideoDriverName(sdl_drv_name,128)!=NULL) { - if (strcmp(sdl_drv_name,"windib")==0) LOG_MSG("SDL_Init: Starting up with SDL windib video driver.\n Try to update your video card and directx drivers!"); - } -#endif sdl.num_joysticks=SDL_NumJoysticks(); /* Parse configuration files */ @@ -2203,10 +2211,10 @@ int main(int argc, char* argv[]) { sticky_keys(true); //Might not be needed if the shutdown function switches to windowed mode, but it doesn't hurt #endif //Force visible mouse to end user. Somehow this sometimes doesn't happen - SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_SetRelativeMouseMode(SDL_FALSE); SDL_ShowCursor(SDL_ENABLE); - SDL_Quit();//Let's hope sdl will quit as well when it catches an exception + SDL_Quit_Wrapper(); // Let's hope sdl will quit as well when it catches an exception return 0; } diff --git a/src/hardware/mixer.cpp b/src/hardware/mixer.cpp index f51a2722..132d335f 100644 --- a/src/hardware/mixer.cpp +++ b/src/hardware/mixer.cpp @@ -89,6 +89,8 @@ static struct { bool nosound; Bit32u freq; Bit32u blocksize; + //Note: As stated earlier, all sdl code shall rather be in sdlmain + SDL_AudioDeviceID sdldevice; } mixer; Bit8u MixTemp[MIXER_BUFSIZE]; @@ -149,6 +151,14 @@ void MIXER_DelChannel(MixerChannel* delchan) { } } +static void MIXER_LockAudioDevice(void) { + SDL_LockAudioDevice(mixer.sdldevice); +} + +static void MIXER_UnlockAudioDevice(void) { + SDL_UnlockAudioDevice(mixer.sdldevice); +} + void MixerChannel::UpdateVolume(void) { volmul[0]=(Bits)((1 << MIXER_VOLSHIFT)*scale[0]*volmain[0]*mixer.mastervol[0]); volmul[1]=(Bits)((1 << MIXER_VOLSHIFT)*scale[1]*volmain[1]*mixer.mastervol[1]); @@ -205,9 +215,9 @@ void MixerChannel::Enable(bool _yesno) { enabled=_yesno; if (enabled) { freq_counter = 0; - SDL_LockAudio(); + MIXER_LockAudioDevice(); if (done> TICK_SHIFT); mixer.tick_counter &= TICK_MASK; - SDL_UnlockAudio(); + MIXER_UnlockAudioDevice(); } static void MIXER_Mix_NoSound(void) { @@ -536,6 +546,7 @@ static void MIXER_Mix_NoSound(void) { } static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { + memset(stream, 0, len); Bitu need=(Bitu)len/MIXER_SSIZE; Bit16s * output=(Bit16s *)stream; Bitu reduce; @@ -763,7 +774,7 @@ void MIXER_Init(Section* sec) { LOG_MSG("MIXER: No Sound Mode Selected."); mixer.tick_add=calc_tickadd(mixer.freq); TIMER_AddTickHandler(MIXER_Mix_NoSound); - } else if (SDL_OpenAudio(&spec, &obtained) <0 ) { + } else if ((mixer.sdldevice = SDL_OpenAudioDevice(NULL, 0, &spec, &obtained, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE)) ==0 ) { mixer.nosound = true; LOG_MSG("MIXER: Can't open audio: %s , running in nosound mode.",SDL_GetError()); mixer.tick_add=calc_tickadd(mixer.freq); @@ -775,7 +786,7 @@ void MIXER_Init(Section* sec) { mixer.blocksize=obtained.samples; mixer.tick_add=calc_tickadd(mixer.freq); TIMER_AddTickHandler(MIXER_Mix); - SDL_PauseAudio(0); + SDL_PauseAudioDevice(mixer.sdldevice, 0); } mixer.min_needed=section->Get_int("prebuffer"); if (mixer.min_needed>100) mixer.min_needed=100; @@ -784,3 +795,12 @@ void MIXER_Init(Section* sec) { mixer.needed=mixer.min_needed+1; PROGRAMS_MakeFile("MIXER.COM",MIXER_ProgramStart); } + +void MIXER_CloseAudioDevice(void) { + if (!mixer.nosound) { + if (mixer.sdldevice != 0) { + SDL_CloseAudioDevice(mixer.sdldevice); + mixer.sdldevice = 0; + } + } +} diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index ef14570f..6463f8b5 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -27,15 +27,6 @@ #include "dos_inc.h" #include "SDL.h" -/* SDL by default treats numlock and scrolllock different from all other keys. - * In recent versions this can disabled by a environment variable which we set in sdlmain.cpp - * Define the following if this is the case */ -#if SDL_VERSION_ATLEAST(1, 2, 14) -#define CAN_USE_LOCK 1 -/* For lower versions of SDL we also use a slight hack to get the startup states of numclock and capslock right. - * The proper way is in the mapper, but the repeating key is an unwanted side effect for lower versions of SDL */ -#endif - static Bitu call_int16,call_irq1,call_irq6; /* Nice table from BOCHS i should feel bad for ripping this */ @@ -241,11 +232,6 @@ static Bitu IRQ1_Handler(void) { flags2=mem_readb(BIOS_KEYBOARD_FLAGS2); flags3=mem_readb(BIOS_KEYBOARD_FLAGS3); leds =mem_readb(BIOS_KEYBOARD_LEDS); -#ifdef CAN_USE_LOCK - /* No hack anymore! */ -#else - flags2&=~(0x40+0x20);//remove numlock/capslock pressed (hack for sdl only reporting states) -#endif if (DOS_LayoutKey(scancode,flags1,flags2,flags3)) return CBRET_NONE; //LOG_MSG("key input %d %d %d %d",scancode,flags1,flags2,flags3); switch (scancode) { @@ -308,14 +294,8 @@ static Bitu IRQ1_Handler(void) { } } break; - -#ifdef CAN_USE_LOCK case 0x3a:flags2 |=0x40;break;//CAPSLOCK case 0xba:flags1 ^=0x40;flags2 &=~0x40;leds ^=0x04;break; -#else - case 0x3a:flags2 |=0x40;flags1 |=0x40;leds |=0x04;break; //SDL gives only the state instead of the toggle /* Caps Lock */ - case 0xba:flags1 &=~0x40;leds &=~0x04;break; -#endif case 0x45: if (flags3 &0x01) { /* last scancode of pause received; first remove 0xe1-prefix */ @@ -336,13 +316,7 @@ static Bitu IRQ1_Handler(void) { } } else { /* Num Lock */ -#ifdef CAN_USE_LOCK flags2 |=0x20; -#else - flags2 |=0x20; - flags1 |=0x20; - leds |=0x02; -#endif } break; case 0xc5: @@ -350,15 +324,9 @@ static Bitu IRQ1_Handler(void) { /* pause released */ flags3 &=~0x01; } else { -#ifdef CAN_USE_LOCK flags1^=0x20; leds^=0x02; flags2&=~0x20; -#else - /* Num Lock released */ - flags1 &=~0x20; - leds &=~0x02; -#endif } break; case 0x46:flags2 |=0x10;break; /* Scroll Lock SDL Seems to do this one fine (so break and make codes) */ @@ -605,14 +573,6 @@ static void InitBiosSegment(void) { mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e); Bit8u flag1 = 0; Bit8u leds = 16; /* Ack received */ - -#if SDL_VERSION_ATLEAST(1, 2, 14) -//Nothing, mapper handles all. -#else - if (startup_state_capslock) { flag1|=0x40; leds|=0x04;} - if (startup_state_numlock) { flag1|=0x20; leds|=0x02;} -#endif - mem_writeb(BIOS_KEYBOARD_FLAGS1,flag1); mem_writeb(BIOS_KEYBOARD_FLAGS2,0); mem_writeb(BIOS_KEYBOARD_FLAGS3,16); /* Enhanced keyboard installed */