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 */