| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre - Romain Bouqueau | |
| * Copyright (c) Telecom ParisTech 2000-2026 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / SDL audio and video module | |
| * | |
| * GPAC is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * GPAC is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; see the file COPYING. If not, write to | |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include "sdl_out.h" | |
| #ifdef WIN32 | |
| #include <windows.h> | |
| #endif | |
| #ifdef GPAC_CONFIG_IOS | |
| #include <OpenGLES/ES1/gl.h> | |
| #include <OpenGLES/ES1/glext.h> | |
| #endif | |
| #ifndef _WIN32_WCE | |
| #include <locale.h> | |
| #endif | |
| /*cursors data*/ | |
| static char hand_data[] = | |
| { | |
| 0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,2,2,1,2,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,1,2,2,1,2,2,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 1,1,1,0,1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 1,2,2,1,1,2,2,2,2,2,2,2,2,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 1,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,1,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,1,2,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,1,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,1,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | |
| }; | |
| static char collide_data[] = | |
| { | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | |
| }; | |
| #define SDLVID() SDLVidCtx *ctx = (SDLVidCtx *)dr->opaque | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| void SDLVid_SetCaption(SDL_Window* window) | |
| { | |
| if (SDL_GetCurrentVideoDriver()) { | |
| char szCap[1024]; | |
| sprintf(szCap, "SDL Video Output (%s)", SDL_GetCurrentVideoDriver()); | |
| SDL_SetWindowTitle(window, szCap); | |
| } else { | |
| SDL_SetWindowTitle(window, "SDL Video Output"); | |
| } | |
| } | |
| #else | |
| #define SDLK_KP_0 SDLK_KP0 | |
| #define SDLK_KP_1 SDLK_KP1 | |
| #define SDLK_KP_2 SDLK_KP2 | |
| #define SDLK_KP_3 SDLK_KP3 | |
| #define SDLK_KP_4 SDLK_KP4 | |
| #define SDLK_KP_5 SDLK_KP5 | |
| #define SDLK_KP_6 SDLK_KP6 | |
| #define SDLK_KP_7 SDLK_KP7 | |
| #define SDLK_KP_8 SDLK_KP8 | |
| #define SDLK_KP_9 SDLK_KP9 | |
| #define SDLK_NUMLOCKCLEAR SDLK_NUMLOCK | |
| #define SDLK_SCROLLLOCK SDLK_SCROLLOCK | |
| #define SDLK_APPLICATION SDLK_COMPOSE | |
| #define SDLK_PRINTSCREEN SDLK_PRINT | |
| #define SDL_WINDOW_RESIZABLE SDL_RESIZABLE | |
| static u32 video_modes[] = | |
| { | |
| 320, 200, | |
| 320, 240, | |
| 400, 300, | |
| 600, 400, | |
| 800, 600, | |
| 1024, 768, | |
| 1152, 864, | |
| 1280, 1024 | |
| }; | |
| static const u32 nb_video_modes = 8; | |
| void SDLVid_SetCaption() | |
| { | |
| char szName[100]; | |
| if (SDL_VideoDriverName(szName, 100)) { | |
| char szCap[1024]; | |
| sprintf(szCap, "SDL Video Output (%s)", szName); | |
| SDL_WM_SetCaption(szCap, NULL); | |
| } else { | |
| SDL_WM_SetCaption("SDL Video Output", NULL); | |
| } | |
| } | |
| #endif | |
| SDL_Cursor *SDLVid_LoadCursor(char *maskdata) | |
| { | |
| s32 ind, i, j; | |
| u8 data[4*32]; | |
| u8 mask[4*32]; | |
| ind = -1; | |
| for (i=0; i<32; i++) { | |
| for (j=0; j<32; j++) { | |
| if (j%8) { | |
| data[ind] <<= 1; | |
| mask[ind] <<= 1; | |
| } else { | |
| ind++; | |
| data[ind] = mask[ind] = 0; | |
| } | |
| switch (maskdata[j+32*i]) { | |
| /*black*/ | |
| case 1: | |
| data[ind] |= 0x01; | |
| /*white*/ | |
| case 2: | |
| mask[ind] |= 0x01; | |
| break; | |
| } | |
| } | |
| } | |
| return SDL_CreateCursor(data, mask, 32, 32, 0, 0); | |
| } | |
| typedef struct | |
| { | |
| u32 sdl_key; | |
| u32 gf_key; | |
| u32 gf_flags; | |
| } SDLKeyToGPAC; | |
| static SDLKeyToGPAC SDLKeys[] = | |
| { | |
| {SDLK_BACKSPACE, GF_KEY_BACKSPACE, 0}, | |
| {SDLK_TAB, GF_KEY_TAB, 0}, | |
| {SDLK_CLEAR, GF_KEY_CLEAR, 0}, | |
| {SDLK_PAUSE, GF_KEY_PAUSE, 0}, | |
| {SDLK_ESCAPE, GF_KEY_ESCAPE, 0}, | |
| {SDLK_SPACE, GF_KEY_SPACE, 0}, | |
| {SDLK_KP_ENTER, GF_KEY_EXT_NUMPAD, 0}, | |
| {SDLK_RETURN, GF_KEY_ENTER, 0}, | |
| {SDLK_KP_MULTIPLY, GF_KEY_EXT_NUMPAD, 0}, | |
| {SDLK_ASTERISK, GF_KEY_STAR, 0}, | |
| {SDLK_KP_PLUS, GF_KEY_EXT_NUMPAD, 0}, | |
| {SDLK_PLUS, GF_KEY_PLUS, 0}, | |
| {SDLK_KP_MINUS, GF_KEY_EXT_NUMPAD, 0}, | |
| {SDLK_MINUS, GF_KEY_HYPHEN, 0}, | |
| {SDLK_KP_DIVIDE, GF_KEY_EXT_NUMPAD, 0}, | |
| {SDLK_SLASH, GF_KEY_SLASH, 0}, | |
| {SDLK_KP_0, GF_KEY_0, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_0, GF_KEY_0, 0}, | |
| {SDLK_KP_1, GF_KEY_1, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_1, GF_KEY_1, 0}, | |
| {SDLK_KP_2, GF_KEY_2, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_2, GF_KEY_2, 0}, | |
| {SDLK_KP_3, GF_KEY_3, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_3, GF_KEY_3, 0}, | |
| {SDLK_KP_4, GF_KEY_4, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_4, GF_KEY_4, 0}, | |
| {SDLK_KP_5, GF_KEY_5, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_5, GF_KEY_5, 0}, | |
| {SDLK_KP_6, GF_KEY_6, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_6, GF_KEY_6, 0}, | |
| {SDLK_KP_7, GF_KEY_7, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_7, GF_KEY_7, 0}, | |
| {SDLK_KP_8, GF_KEY_8, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_8, GF_KEY_8, 0}, | |
| {SDLK_KP_9, GF_KEY_9, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_9, GF_KEY_9, 0}, | |
| {SDLK_KP_PERIOD, GF_KEY_FULLSTOP, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_PERIOD, GF_KEY_FULLSTOP, 0}, | |
| {SDLK_KP_EQUALS, GF_KEY_EQUALS, GF_KEY_EXT_NUMPAD}, | |
| {SDLK_EQUALS, GF_KEY_EQUALS, 0}, | |
| {SDLK_EXCLAIM, GF_KEY_EXCLAMATION, 0}, | |
| {SDLK_QUOTEDBL, GF_KEY_QUOTATION, 0}, | |
| {SDLK_HASH, GF_KEY_NUMBER, 0}, | |
| {SDLK_DOLLAR, GF_KEY_DOLLAR, 0}, | |
| {SDLK_AMPERSAND, GF_KEY_AMPERSAND, 0}, | |
| {SDLK_QUOTE, GF_KEY_APOSTROPHE, 0}, | |
| {SDLK_LEFTPAREN, GF_KEY_LEFTPARENTHESIS, 0}, | |
| {SDLK_RIGHTPAREN, GF_KEY_RIGHTPARENTHESIS, 0}, | |
| {SDLK_COMMA, GF_KEY_COMMA, 0}, | |
| {SDLK_COLON, GF_KEY_COLON, 0}, | |
| {SDLK_SEMICOLON, GF_KEY_SEMICOLON, 0}, | |
| {SDLK_LESS, GF_KEY_LESSTHAN, 0}, | |
| {SDLK_GREATER, GF_KEY_GREATERTHAN, 0}, | |
| {SDLK_QUESTION, GF_KEY_QUESTION, 0}, | |
| {SDLK_AT, GF_KEY_AT, 0}, | |
| {SDLK_LEFTBRACKET, GF_KEY_LEFTSQUAREBRACKET, 0}, | |
| {SDLK_RIGHTBRACKET, GF_KEY_RIGHTSQUAREBRACKET, 0}, | |
| {SDLK_BACKSLASH, GF_KEY_BACKSLASH, 0}, | |
| {SDLK_UNDERSCORE, GF_KEY_UNDERSCORE, 0}, | |
| {SDLK_BACKQUOTE, GF_KEY_GRAVEACCENT, 0}, | |
| {SDLK_DELETE, GF_KEY_DEL, 0}, | |
| {SDLK_UNDO, GF_KEY_UNDO, 0}, | |
| {SDLK_UP, GF_KEY_UP, 0}, | |
| {SDLK_DOWN, GF_KEY_DOWN, 0}, | |
| {SDLK_RIGHT, GF_KEY_RIGHT, 0}, | |
| {SDLK_LEFT, GF_KEY_LEFT, 0}, | |
| {SDLK_INSERT, GF_KEY_INSERT, 0}, | |
| {SDLK_HOME, GF_KEY_HOME, 0}, | |
| {SDLK_END, GF_KEY_END, 0}, | |
| {SDLK_PAGEUP, GF_KEY_PAGEUP, 0}, | |
| {SDLK_PAGEDOWN, GF_KEY_PAGEDOWN, 0}, | |
| {SDLK_F1, GF_KEY_F1, 0}, | |
| {SDLK_F2, GF_KEY_F2, 0}, | |
| {SDLK_F3, GF_KEY_F3, 0}, | |
| {SDLK_F4, GF_KEY_F4, 0}, | |
| {SDLK_F5, GF_KEY_F5, 0}, | |
| {SDLK_F6, GF_KEY_F6, 0}, | |
| {SDLK_F7, GF_KEY_F7, 0}, | |
| {SDLK_F8, GF_KEY_F8, 0}, | |
| {SDLK_F9, GF_KEY_F9, 0}, | |
| {SDLK_F10, GF_KEY_F10, 0}, | |
| {SDLK_F11, GF_KEY_F11, 0}, | |
| {SDLK_F12, GF_KEY_F12, 0}, | |
| {SDLK_F13, GF_KEY_F13, 0}, | |
| {SDLK_F14, GF_KEY_F14, 0}, | |
| {SDLK_F15, GF_KEY_F15, 0}, | |
| {SDLK_NUMLOCKCLEAR, GF_KEY_NUMLOCK, 0}, | |
| {SDLK_CAPSLOCK, GF_KEY_CAPSLOCK, 0}, | |
| {SDLK_SCROLLLOCK, GF_KEY_SCROLL, 0}, | |
| {SDLK_RSHIFT, GF_KEY_SHIFT, GF_KEY_EXT_RIGHT}, | |
| {SDLK_LSHIFT, GF_KEY_SHIFT, GF_KEY_EXT_LEFT}, | |
| {SDLK_LCTRL, GF_KEY_CONTROL, GF_KEY_EXT_LEFT}, | |
| {SDLK_RCTRL, GF_KEY_CONTROL, GF_KEY_EXT_RIGHT}, | |
| {SDLK_LALT, GF_KEY_ALT, GF_KEY_EXT_LEFT}, | |
| {SDLK_RALT, GF_KEY_ALT, GF_KEY_EXT_RIGHT}, | |
| #if (SDL_MAJOR_VERSION<=1) && (SDL_MINOR_VERSION<3) | |
| {SDLK_LMETA, GF_KEY_META, GF_KEY_EXT_LEFT}, | |
| {SDLK_LSUPER, GF_KEY_META, GF_KEY_EXT_LEFT}, | |
| #else | |
| {SDLK_LGUI, GF_KEY_META, GF_KEY_EXT_LEFT}, | |
| #endif | |
| #if (SDL_MAJOR_VERSION<=1) && (SDL_MINOR_VERSION<3) | |
| {SDLK_RMETA, GF_KEY_META, GF_KEY_EXT_RIGHT}, | |
| {SDLK_RSUPER, GF_KEY_META, GF_KEY_EXT_RIGHT}, | |
| #else | |
| {SDLK_RGUI, GF_KEY_META, GF_KEY_EXT_RIGHT}, | |
| #endif | |
| {SDLK_MODE, GF_KEY_MODECHANGE, 0}, | |
| {SDLK_APPLICATION, GF_KEY_COMPOSE, 0}, | |
| {SDLK_HELP, GF_KEY_HELP, 0}, | |
| {SDLK_PRINTSCREEN, GF_KEY_PRINTSCREEN, 0} | |
| }; | |
| static u32 num_sdl_keys = sizeof(SDLKeys) / sizeof(SDLKeyToGPAC); | |
| static void sdl_translate_key(u32 SDLkey, GF_EventKey *evt) | |
| { | |
| u32 i; | |
| evt->flags = 0; | |
| evt->hw_code = SDLkey; | |
| for (i=0; i<num_sdl_keys; i++) { | |
| if (SDLKeys[i].sdl_key == SDLkey) { | |
| evt->key_code = SDLKeys[i].gf_key; | |
| evt->flags = SDLKeys[i].gf_flags; | |
| return; | |
| } | |
| } | |
| if ((SDLkey>=0x30) && (SDLkey<=0x39)) | |
| evt->key_code = GF_KEY_0 + SDLkey-0x30; | |
| else if ((SDLkey>=0x41) && (SDLkey<=0x5A)) | |
| evt->key_code = GF_KEY_A + SDLkey-0x41; | |
| else if ((SDLkey>=0x61) && (SDLkey<=0x7A)) | |
| evt->key_code = GF_KEY_A + SDLkey-0x61; | |
| else { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[SDL] Unrecognized key %X\n", SDLkey)); | |
| evt->key_code = GF_KEY_UNIDENTIFIED; | |
| } | |
| } | |
| #if 0 | |
| void SDLVid_SetHack(void *os_handle, Bool set_on) | |
| { | |
| char buf[50]; | |
| if (set_on && os_handle) { | |
| sprintf(buf, "SDL_WINDOWID=%u", (u32) os_handle); | |
| } else { | |
| gf_strcpy(buf, "SDL_WINDOWID="); | |
| } | |
| #ifdef WIN32 | |
| putenv(buf); | |
| #else | |
| if (set_on) unsetenv("SDL_WINDOWID="); | |
| else putenv(buf); | |
| #endif | |
| } | |
| #endif | |
| static void SDLVid_DestroyObjects(SDLVidCtx *ctx) | |
| { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->pool_rgb) SDL_DestroyTexture(ctx->pool_rgb); | |
| ctx->pool_rgb = NULL; | |
| if (ctx->pool_rgba) SDL_DestroyTexture(ctx->pool_rgba); | |
| ctx->pool_rgba = NULL; | |
| if (ctx->pool_yuv) SDL_DestroyTexture(ctx->pool_yuv); | |
| ctx->pool_yuv = NULL; | |
| if (ctx->tx_back_buffer) SDL_DestroyTexture(ctx->tx_back_buffer); | |
| ctx->tx_back_buffer = NULL; | |
| if (ctx->back_buffer_pixels) gf_free(ctx->back_buffer_pixels); | |
| ctx->back_buffer_pixels = NULL; | |
| #else | |
| if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer); | |
| ctx->back_buffer = NULL; | |
| if (ctx->pool_rgb) SDL_FreeSurface(ctx->pool_rgb); | |
| ctx->pool_rgb = NULL; | |
| if (ctx->pool_rgba) SDL_FreeSurface(ctx->pool_rgba); | |
| ctx->pool_rgba = NULL; | |
| SDL_FreeYUVOverlay(ctx->yuv_overlay); | |
| ctx->yuv_overlay=NULL; | |
| #endif | |
| } | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| #ifdef GPAC_CONFIG_IOS | |
| #define SDL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | |
| #define SDL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | |
| #define SDL_GL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | |
| #define SDL_GL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | |
| #else | |
| #define SDL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | |
| #define SDL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | |
| #define SDL_GL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | |
| #define SDL_GL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | |
| #endif | |
| #else | |
| #ifdef GPAC_CONFIG_IOS | |
| #define SDL_WINDOW_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_NOFRAME | |
| #define SDL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_FULLSCREEN | SDL_NOFRAME | |
| #define SDL_GL_WINDOW_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_RESIZABLE | SDL_NOFRAME | |
| #define SDL_GL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_FULLSCREEN | SDL_NOFRAME | |
| #else | |
| #define SDL_WINDOW_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | |
| #define SDL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_FULLSCREEN | |
| #define SDL_GL_WINDOW_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_RESIZABLE | |
| #define SDL_GL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_FULLSCREEN | |
| #endif | |
| #endif | |
| #include <gpac/media_tools.h> | |
| void SDLVid_SetIcon(SDLVidCtx *ctx) | |
| { | |
| #if SDL_VERSION_ATLEAST(2,0,0) && !defined(GPAC_CONFIG_IOS) && !defined(GPAC_DISABLE_AV_PARSERS) | |
| u8 *buffer, *dec_buf; | |
| u32 size, w, h, pf, Bpp, dst_size=0; | |
| char cfg[GF_MAX_PATH]; | |
| if (!gf_opts_default_shared_directory((char *) cfg)) | |
| return; | |
| gf_strcat(cfg, "/res/gpac.png"); | |
| if (gf_file_load_data(cfg, &buffer, &size) != GF_OK) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDLOut] failed to load icon file %s\n", cfg )); | |
| return; | |
| } | |
| gf_img_png_dec(buffer, size, &w, &h, &pf, NULL, &dst_size); | |
| Bpp = gf_pixel_get_bytes_per_pixel(pf); | |
| dec_buf = gf_malloc(sizeof(char)*dst_size); | |
| gf_img_png_dec(buffer, size, &w, &h, &pf, dec_buf, &dst_size); | |
| //RGBA only | |
| SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(dec_buf, w, h, Bpp*8, w*Bpp, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); | |
| if (!surface) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDLOut] failed to create surface from icon: %s\n", SDL_GetError() )); | |
| } else { | |
| SDL_SetWindowIcon(ctx->screen, surface); | |
| SDL_FreeSurface(surface); | |
| } | |
| gf_free(buffer); | |
| gf_free(dec_buf); | |
| #endif | |
| } | |
| GF_Err SDLVid_ResizeWindow(GF_VideoOutput *dr, u32 width, u32 height) | |
| { | |
| Bool hw_reset; | |
| SDLVID(); | |
| GF_Event evt; | |
| if (!width || !height) return GF_BAD_PARAM; | |
| /*lock X mutex to make sure the event queue is not being processed*/ | |
| gf_mx_p(ctx->evt_mx); | |
| GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Resizing window %dx%d\n", width, height)); | |
| if (ctx->output_3d) { | |
| u32 flags, nb_bits; | |
| const char *opt; | |
| if (ctx->screen && (ctx->width==width) && (ctx->height==height) ) { | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_OK; | |
| } | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| flags = SDL_GL_WINDOW_FLAGS; | |
| if (ctx->os_handle) flags &= ~SDL_WINDOW_RESIZABLE; | |
| if (ctx->fullscreen) flags |= SDL_FULLSCREEN_FLAGS; | |
| #ifdef GPAC_CONFIG_IOS | |
| flags |= SDL_FULLSCREEN_FLAGS | SDL_WINDOW_ALLOW_HIGHDPI; | |
| #endif | |
| #else | |
| flags = SDL_GL_WINDOW_FLAGS; | |
| if (ctx->os_handle) flags &= ~SDL_RESIZABLE; | |
| if (ctx->fullscreen) flags |= SDL_FULLSCREEN_FLAGS; | |
| if (!ctx->screen) ctx->screen = SDL_SetVideoMode(width, height, 0, flags); | |
| #endif | |
| SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | |
| opt = gf_opts_get_key("core", "gl-bits-depth"); | |
| nb_bits = opt ? atoi(opt) : 16; | |
| SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, nb_bits); | |
| SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); | |
| opt = gf_opts_get_key("core", "gl-bits-comp"); | |
| nb_bits = opt ? atoi(opt) : 8; | |
| SDL_GL_SetAttribute(SDL_GL_RED_SIZE, nb_bits); | |
| SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, nb_bits); | |
| SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, nb_bits); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->hidden) | |
| flags |= SDL_WINDOW_HIDDEN; | |
| hw_reset = GF_FALSE; | |
| #ifdef GPAC_USE_GLES2 | |
| /* Set the correct attributes for MASK and MAJOR version */ | |
| SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); | |
| SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); | |
| #ifdef GPAC_CONFIG_EMSCRIPTEN | |
| SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); | |
| #endif | |
| #endif | |
| if (!ctx->screen) { | |
| if (!(ctx->screen = SDL_CreateWindow("", 0, 0, width, height, flags))) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError())); | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_IO_ERR; | |
| } | |
| GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Window created\n")); | |
| dr->window_id = SDL_GetWindowID(ctx->screen); | |
| SDLVid_SetIcon(ctx); | |
| /*creating a window, at least on OSX, changes the locale and screws up float parsing !! | |
| force setting the local back and pray that it will be changed before any other atof/strtod is called | |
| !! it also looks like the locale is not enforced synchronously on OSX: adding | |
| assert(strtod(0.5)) in gf_malloc proto would lead to random crashes | |
| */ | |
| #ifndef _WIN32_WCE | |
| setlocale( LC_NUMERIC, "C" ); | |
| #endif | |
| } | |
| if ( !ctx->gl_context ) { | |
| //in case we created a headless context before loading vout, create a shared context | |
| SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); | |
| if (!(ctx->gl_context = SDL_GL_CreateContext(ctx->screen))) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot initialize gl context: %s\n", SDL_GetError())); | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_IO_ERR; | |
| } | |
| if (SDL_GL_MakeCurrent(ctx->screen, ctx->gl_context)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot make context current: %s\n", SDL_GetError())); | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_IO_ERR; | |
| } | |
| hw_reset = GF_TRUE; | |
| } | |
| if (flags & SDL_WINDOW_ALLOW_HIGHDPI) { | |
| int w, h; | |
| SDL_GL_GetDrawableSize(ctx->screen, &w, &h); | |
| #if SDL_VERSION_ATLEAST(2,0,9) | |
| int _h; | |
| switch (SDL_GetDisplayOrientation(0)) { | |
| case SDL_ORIENTATION_LANDSCAPE: | |
| case SDL_ORIENTATION_LANDSCAPE_FLIPPED: | |
| break; | |
| default: | |
| _h = h; | |
| h = w; | |
| w = _h; | |
| break; | |
| } | |
| #endif | |
| if ((u32) w > dr->max_screen_width) dr->max_screen_width = w; | |
| if ((u32) h > dr->max_screen_height) dr->max_screen_height = h; | |
| } | |
| if (!ctx->disable_vsync) | |
| ctx->disable_vsync = !gf_module_get_bool((GF_BaseInterface *)dr, "vsync"); | |
| if (ctx->disable_vsync) { | |
| #if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS) | |
| #else | |
| SDL_GL_SetSwapInterval(0); | |
| #endif | |
| } | |
| SDL_SetWindowSize(ctx->screen, width, height); | |
| #else | |
| hw_reset = GF_TRUE; | |
| ctx->screen = SDL_SetVideoMode(width, height, 0, flags); | |
| if (!ctx->screen) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError())); | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_IO_ERR; | |
| } | |
| #endif | |
| ctx->width = width; | |
| ctx->height = height; | |
| memset(&evt, 0, sizeof(GF_Event)); | |
| evt.type = GF_EVENT_VIDEO_SETUP; | |
| evt.setup.hw_reset = hw_reset; | |
| dr->on_event(dr->evt_cbk_hdl, &evt); | |
| GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] 3D Setup done\n")); | |
| } else { | |
| u32 flags; | |
| #ifdef GPAC_CONFIG_IOS | |
| flags = SDL_FULLSCREEN_FLAGS; | |
| //SDL readme says it would make us faster | |
| SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); | |
| #else | |
| flags = SDL_WINDOW_FLAGS | SDL_WINDOW_RESIZABLE; | |
| if (ctx->os_handle) flags &= ~SDL_WINDOW_RESIZABLE; | |
| #endif | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| #ifdef GPAC_CONFIG_IOS | |
| //still some issues with render to tager and landscape orientation, we need to reset everything ... | |
| if (ctx->enable_defer_mode) { | |
| if (ctx->renderer) SDL_DestroyRenderer(ctx->renderer); | |
| ctx->renderer=NULL; | |
| if (ctx->screen) SDL_DestroyWindow(ctx->screen); | |
| ctx->screen=NULL; | |
| } | |
| #endif | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->hidden) | |
| flags |= SDL_WINDOW_HIDDEN; | |
| #endif | |
| if (!ctx->screen) { | |
| ctx->screen = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); | |
| if (!ctx->screen) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError())); | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_IO_ERR; | |
| } | |
| dr->window_id = SDL_GetWindowID(ctx->screen); | |
| SDLVid_SetIcon(ctx); | |
| /*see above note*/ | |
| #ifndef _WIN32_WCE | |
| setlocale( LC_NUMERIC, "C" ); | |
| #endif | |
| GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Window created\n")); | |
| SDL_RaiseWindow(ctx->screen); | |
| } | |
| if ( !ctx->renderer ) { | |
| u32 flags = SDL_RENDERER_ACCELERATED; | |
| if (gf_module_get_bool((GF_BaseInterface *)dr, "vsync")) { | |
| flags |= SDL_RENDERER_PRESENTVSYNC; | |
| } | |
| if (!(ctx->renderer = SDL_CreateRenderer(ctx->screen, -1, flags))) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create renderer: %s\n", SDL_GetError())); | |
| gf_mx_v(ctx->evt_mx); | |
| return GF_IO_ERR; | |
| } | |
| } | |
| #ifndef GPAC_CONFIG_IOS | |
| SDL_SetWindowSize(ctx->screen, width, height); | |
| #endif | |
| SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255); | |
| SDL_RenderClear(ctx->renderer); | |
| #else | |
| ctx->screen = SDL_SetVideoMode(width, height, 0, flags); | |
| #endif | |
| GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] 2D Setup done\n")); | |
| } | |
| gf_mx_v(ctx->evt_mx); | |
| return ctx->screen ? GF_OK : GF_IO_ERR; | |
| } | |
| static void SDLVid_SetCursor(GF_VideoOutput *dr, u32 cursor_type) | |
| { | |
| #ifndef GPAC_CONFIG_IOS | |
| SDLVID(); | |
| switch (cursor_type) { | |
| case GF_CURSOR_ANCHOR: | |
| case GF_CURSOR_TOUCH: | |
| case GF_CURSOR_ROTATE: | |
| case GF_CURSOR_PROXIMITY: | |
| case GF_CURSOR_PLANE: | |
| SDL_SetCursor(ctx->curs_hand); | |
| break; | |
| case GF_CURSOR_COLLIDE: | |
| SDL_SetCursor(ctx->curs_collide); | |
| break; | |
| default: | |
| SDL_SetCursor(ctx->curs_def); | |
| break; | |
| } | |
| #endif | |
| } | |
| #include <gpac/list.h> | |
| static GF_List *video_outputs = NULL; | |
| static u32 nb_video_outputs=0; | |
| static Bool SDLVid_InitializeWindow(SDLVidCtx *ctx, GF_VideoOutput *dr) | |
| { | |
| u32 flags; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_DisplayMode vinf; | |
| #else | |
| #if SDL_VERSION_ATLEAST(1, 2, 10) | |
| const SDL_VideoInfo *vinf; | |
| #endif | |
| #endif | |
| #ifdef WIN32 | |
| putenv("directx"); | |
| #endif | |
| if (!video_outputs) { | |
| flags = SDL_WasInit(SDL_INIT_VIDEO); | |
| if (!(flags & SDL_INIT_VIDEO)) { | |
| if (SDL_InitSubSystem(SDL_INIT_VIDEO)) { | |
| return GF_FALSE; | |
| } | |
| } | |
| video_outputs = gf_list_new(); | |
| } | |
| if (gf_list_find(video_outputs, dr)<0) { | |
| gf_list_add(video_outputs, dr); | |
| nb_video_outputs = gf_list_count(video_outputs); | |
| } | |
| ctx->curs_def = SDL_GetCursor(); | |
| ctx->curs_hand = SDLVid_LoadCursor(hand_data); | |
| ctx->curs_collide = SDLVid_LoadCursor(collide_data); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| #else | |
| SDL_EnableUNICODE(1); | |
| SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); | |
| #endif | |
| ctx->last_mouse_move = SDL_GetTicks(); | |
| ctx->cursor_on = GF_TRUE; | |
| /*save display resolution - SDL seems to get the screen resolution if asked for video info before | |
| changing the video mode - to check on other platforms*/ | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_GetDesktopDisplayMode(0,&vinf); | |
| dr->max_screen_width = vinf.w; | |
| dr->max_screen_height = vinf.h; | |
| dr->max_screen_bpp = 8; | |
| #else | |
| #if SDL_VERSION_ATLEAST(1, 2, 10) | |
| vinf = SDL_GetVideoInfo(); | |
| if (vinf) { | |
| dr->max_screen_width = vinf->current_w; | |
| dr->max_screen_height = vinf->current_h; | |
| } | |
| dr->max_screen_bpp = 8; | |
| #else | |
| { | |
| SDL_Rect** modes; | |
| modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); | |
| if ( modes == (SDL_Rect**)-1 ) { | |
| fprintf(stderr, "SDL : DONT KNOW WHICH MODE TO USE, using 640x480\n"); | |
| dr->max_screen_width = 640; | |
| dr->max_screen_height = 480; | |
| } else if (modes) { | |
| int i; | |
| dr->max_screen_width = 0; | |
| for (i=0; modes[i]; ++i) { | |
| int w = modes[i]->w; | |
| if (w > dr->max_screen_width) { | |
| dr->max_screen_width = w; | |
| dr->max_screen_height = modes[i]->h; | |
| } | |
| } | |
| } | |
| } | |
| dr->max_screen_bpp = 8; | |
| #endif /* versions prior to 1.2.10 do not have the size of screen */ | |
| #endif | |
| if (!ctx->os_handle) | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDLVid_SetCaption(ctx->screen); | |
| #else | |
| SDLVid_SetCaption(); | |
| #endif | |
| GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Video output initialized - screen resolution %d %d\n", dr->max_screen_width, dr->max_screen_height)); | |
| return GF_TRUE; | |
| } | |
| static void SDLVid_ResetWindow(SDLVidCtx *ctx) | |
| { | |
| SDLVid_DestroyObjects(ctx); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if ( ctx->gl_context ) { | |
| SDL_GL_DeleteContext(ctx->gl_context); | |
| ctx->gl_context = NULL; | |
| } | |
| if ( ctx->renderer ) { | |
| SDL_DestroyRenderer(ctx->renderer); | |
| ctx->renderer = NULL; | |
| } | |
| /*iOS SDL2 has a nasty bug that breaks switching between 2D and GL context if we don't re-init the video subsystem*/ | |
| #ifdef GPAC_CONFIG_IOS | |
| if ( ctx->screen ) { | |
| SDL_DestroyWindow(ctx->screen); | |
| ctx->screen=NULL; | |
| } | |
| SDL_QuitSubSystem(SDL_INIT_VIDEO); | |
| SDL_InitSubSystem(SDL_INIT_VIDEO); | |
| #endif | |
| #endif | |
| } | |
| static void SDLVid_ShutdownWindow(SDLVidCtx *ctx) | |
| { | |
| SDLVid_DestroyObjects(ctx); | |
| SDLVid_ResetWindow(ctx); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->screen) SDL_DestroyWindow(ctx->screen); | |
| ctx->screen = NULL; | |
| #endif | |
| } | |
| #if defined SDL_TEXTINPUTEVENT_TEXT_SIZE /*&& !defined GPAC_CONFIG_IOS*/ | |
| #include <gpac/utf.h> | |
| #endif | |
| Bool SDLVid_ProcessMessageQueue(SDLVidCtx *ctx, GF_VideoOutput *dr) | |
| { | |
| SDL_Event sdl_evt; | |
| GF_Event gpac_evt; | |
| #ifdef GPAC_CONFIG_IOS | |
| while (SDL_WaitEventTimeout(&sdl_evt, 1)) { | |
| #else | |
| while (1) { | |
| if (nb_video_outputs>1) { | |
| u32 win_id=0; | |
| if (!SDL_PollEvent(NULL)) return GF_TRUE; | |
| SDL_PeepEvents(&sdl_evt, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); | |
| switch (sdl_evt.type) { | |
| case SDL_WINDOWEVENT: win_id = sdl_evt.window.windowID; break; | |
| #ifdef SDL_TEXTINPUTEVENT_TEXT_SIZE | |
| case SDL_TEXTINPUT: /* Since SDL 1.3, text-input is handled in a specific event */ | |
| win_id = sdl_evt.text.windowID; break; | |
| #endif | |
| case SDL_KEYDOWN: | |
| case SDL_KEYUP: | |
| win_id = sdl_evt.key.windowID; break; | |
| case SDL_MOUSEMOTION: | |
| win_id = sdl_evt.motion.windowID; break; | |
| case SDL_MOUSEBUTTONDOWN: | |
| case SDL_MOUSEBUTTONUP: | |
| win_id = sdl_evt.button.windowID; break; | |
| case SDL_MOUSEWHEEL: | |
| win_id = sdl_evt.wheel.windowID; break; | |
| #if SDL_VERSION_ATLEAST(2,0,5) | |
| case SDL_DROPFILE: | |
| win_id = sdl_evt.drop.windowID; break; | |
| #endif | |
| } | |
| //we may get events from destroyed windows still in the queue, flush them | |
| if (win_id!=dr->window_id) { | |
| Bool found=GF_FALSE; | |
| u32 i; | |
| for (i=0; i<nb_video_outputs; i++) { | |
| GF_VideoOutput *dr2 = gf_list_get(video_outputs, i); | |
| if (win_id==dr2->window_id) { | |
| found=GF_TRUE; | |
| break; | |
| } | |
| } | |
| if (found) return GF_TRUE; | |
| else if (win_id) { | |
| fprintf(stderr, "Purging event from window id %d\n", win_id); | |
| } | |
| } | |
| } | |
| if (!SDL_PollEvent(&sdl_evt)) return GF_TRUE; | |
| #endif | |
| switch (sdl_evt.type) { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| case SDL_WINDOWEVENT: | |
| switch (sdl_evt.window.event) { | |
| case SDL_WINDOWEVENT_SIZE_CHANGED: | |
| gpac_evt.type = GF_EVENT_SIZE; | |
| #if SDL_VERSION_ATLEAST(2,0,10) && GPAC_CONFIG_IOS | |
| { | |
| int w, h; | |
| SDL_GL_GetDrawableSize(ctx->screen, &w, &h); | |
| gpac_evt.size.width = w; | |
| gpac_evt.size.height = h; | |
| ctx->high_dpi_w = w; | |
| ctx->low_dpi_w = sdl_evt.window.data1; | |
| ctx->high_dpi_h = h; | |
| ctx->low_dpi_h = sdl_evt.window.data2; | |
| } | |
| #else | |
| gpac_evt.size.width = sdl_evt.window.data1; | |
| gpac_evt.size.height = sdl_evt.window.data2; | |
| gpac_evt.size.window_id = dr->window_id; | |
| #endif | |
| #if SDL_VERSION_ATLEAST(2,0,9) | |
| switch (SDL_GetDisplayOrientation(0)) { | |
| case SDL_ORIENTATION_UNKNOWN: gpac_evt.size.orientation = GF_DISPLAY_MODE_UNKNOWN; break; | |
| case SDL_ORIENTATION_LANDSCAPE: gpac_evt.size.orientation = GF_DISPLAY_MODE_LANDSCAPE; break; | |
| case SDL_ORIENTATION_LANDSCAPE_FLIPPED: gpac_evt.size.orientation = GF_DISPLAY_MODE_LANDSCAPE_INV; break; | |
| case SDL_ORIENTATION_PORTRAIT: gpac_evt.size.orientation = GF_DISPLAY_MODE_PORTRAIT; break; | |
| case SDL_ORIENTATION_PORTRAIT_FLIPPED: gpac_evt.size.orientation = GF_DISPLAY_MODE_PORTRAIT_INV; break; | |
| } | |
| #endif | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_WINDOWEVENT_EXPOSED: | |
| case SDL_WINDOWEVENT_SHOWN: | |
| gpac_evt.type = GF_EVENT_REFRESH; | |
| gpac_evt.show.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_WINDOWEVENT_MOVED: | |
| gpac_evt.type = GF_EVENT_MOVE; | |
| gpac_evt.move.x = sdl_evt.window.data1; | |
| gpac_evt.move.y = sdl_evt.window.data2; | |
| gpac_evt.move.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_WINDOWEVENT_CLOSE: | |
| memset(&gpac_evt, 0, sizeof(GF_Event)); | |
| gpac_evt.type = GF_EVENT_QUIT; | |
| gpac_evt.show.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| return GF_FALSE; | |
| case SDL_WINDOWEVENT_MINIMIZED: | |
| memset(&gpac_evt, 0, sizeof(GF_Event)); | |
| gpac_evt.type = GF_EVENT_SHOWHIDE; | |
| gpac_evt.show.show_type = 0; | |
| gpac_evt.show.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| return GF_FALSE; | |
| } | |
| break; | |
| #else | |
| case SDL_VIDEORESIZE: | |
| gpac_evt.type = GF_EVENT_SIZE; | |
| gpac_evt.size.width = sdl_evt.resize.w; | |
| gpac_evt.size.height = sdl_evt.resize.h; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_VIDEOEXPOSE: | |
| gpac_evt.type = GF_EVENT_REFRESH; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| #endif | |
| case SDL_QUIT: | |
| memset(&gpac_evt, 0, sizeof(GF_Event)); | |
| gpac_evt.type = GF_EVENT_QUIT; | |
| gpac_evt.show.window_id = 0; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| return GF_FALSE; | |
| #ifdef SDL_TEXTINPUTEVENT_TEXT_SIZE | |
| /*keyboard*/ | |
| case SDL_TEXTINPUT: /* Since SDL 1.3, text-input is handled in a specific event */ | |
| { | |
| u32 len = (u32) strlen( sdl_evt.text.text); | |
| if (len < 5 ) { | |
| gpac_evt.character.window_id = dr->window_id; | |
| u32 ucs4_len = utf8_to_ucs4 (&(gpac_evt.character.unicode_char), len, (unsigned char*)(sdl_evt.text.text)); | |
| if (ucs4_len) { | |
| gpac_evt.type = GF_EVENT_TEXTINPUT; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| } | |
| } | |
| break; | |
| } | |
| #endif /* SDL_TEXTINPUTEVENT_TEXT_SIZE */ | |
| case SDL_KEYDOWN: | |
| case SDL_KEYUP: | |
| sdl_translate_key(sdl_evt.key.keysym.sym, &gpac_evt.key); | |
| gpac_evt.type = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_EVENT_KEYDOWN : GF_EVENT_KEYUP; | |
| gpac_evt.key.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| if (gpac_evt.key.key_code==GF_KEY_CONTROL) ctx->ctrl_down = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_TRUE : GF_FALSE; | |
| else if (gpac_evt.key.key_code==GF_KEY_ALT) ctx->alt_down = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_TRUE : GF_FALSE; | |
| else if (gpac_evt.key.key_code==GF_KEY_META) ctx->meta_down = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_TRUE : GF_FALSE; | |
| #ifdef SDL_TEXTINPUTEVENT_TEXT_SIZE | |
| if (sdl_evt.type==SDL_KEYDOWN) { | |
| if ((gpac_evt.key.key_code==GF_KEY_ENTER) || (gpac_evt.key.key_code==GF_KEY_BACKSPACE)) { | |
| gpac_evt.type = GF_EVENT_TEXTINPUT; | |
| gpac_evt.character.unicode_char = (gpac_evt.key.key_code==GF_KEY_ENTER) ? '\r' : '\b'; | |
| gpac_evt.character.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| } | |
| } | |
| #endif | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if ((gpac_evt.type==GF_EVENT_KEYUP) && (gpac_evt.key.key_code==GF_KEY_V) | |
| #if defined(__DARWIN__) || defined(__APPLE__) | |
| && ctx->meta_down | |
| #else | |
| && ctx->ctrl_down | |
| #endif | |
| ) { | |
| gpac_evt.type = GF_EVENT_PASTE_TEXT; | |
| gpac_evt.clipboard.text = (char *) SDL_GetClipboardText(); | |
| gpac_evt.clipboard.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| SDL_free(gpac_evt.clipboard.text); | |
| } | |
| else if ((gpac_evt.type==GF_EVENT_KEYUP) && (gpac_evt.key.key_code==GF_KEY_C) | |
| #if defined(__DARWIN__) || defined(__APPLE__) | |
| && ctx->meta_down | |
| #else | |
| && ctx->ctrl_down | |
| #endif | |
| ) { | |
| gpac_evt.type = GF_EVENT_COPY_TEXT; | |
| if (dr->on_event(dr->evt_cbk_hdl, &gpac_evt) && gpac_evt.clipboard.text) { | |
| SDL_SetClipboardText(gpac_evt.clipboard.text ); | |
| gf_free(gpac_evt.clipboard.text); | |
| } | |
| } | |
| #endif | |
| #ifndef SDL_TEXTINPUTEVENT_TEXT_SIZE | |
| if ((sdl_evt.key.type==SDL_KEYDOWN) | |
| && sdl_evt.key.keysym.unicode | |
| && ((sdl_evt.key.keysym.unicode=='\r') || (sdl_evt.key.keysym.unicode=='\n') || (sdl_evt.key.keysym.unicode=='\b') || (sdl_evt.key.keysym.unicode=='\t') ) | |
| ) { | |
| gpac_evt.character.unicode_char = sdl_evt.key.keysym.unicode; | |
| gpac_evt.character.window_id = dr->window_id; | |
| gpac_evt.type = GF_EVENT_TEXTINPUT; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| } | |
| #else | |
| #endif | |
| break; | |
| /* rescale mouse event (not multitouch) to highDPI coords - not yet supported in SDL, see https://github.com/libsdl-org/SDL/issues/2999*/ | |
| /*mouse*/ | |
| case SDL_MOUSEMOTION: | |
| ctx->last_mouse_move = SDL_GetTicks(); | |
| gpac_evt.type = GF_EVENT_MOUSEMOVE; | |
| gpac_evt.mouse.window_id = dr->window_id; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->low_dpi_w && ctx->low_dpi_h) { | |
| gpac_evt.mouse.x = (u32) ( (u64) sdl_evt.motion.x * ctx->high_dpi_w / ctx->low_dpi_w); | |
| gpac_evt.mouse.y = (u32) ( (u64) sdl_evt.motion.y * ctx->high_dpi_h / ctx->low_dpi_h); | |
| } else | |
| #endif | |
| { | |
| gpac_evt.mouse.x = sdl_evt.motion.x; | |
| gpac_evt.mouse.y = sdl_evt.motion.y; | |
| } | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_MOUSEBUTTONDOWN: | |
| case SDL_MOUSEBUTTONUP: | |
| ctx->last_mouse_move = SDL_GetTicks(); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->low_dpi_w && ctx->low_dpi_h) { | |
| gpac_evt.mouse.x = (u32) ( (u64) sdl_evt.motion.x * ctx->high_dpi_w / ctx->low_dpi_w); | |
| gpac_evt.mouse.y = (u32) ( (u64) sdl_evt.motion.y * ctx->high_dpi_h / ctx->low_dpi_h); | |
| } else | |
| #endif | |
| { | |
| gpac_evt.mouse.x = sdl_evt.motion.x; | |
| gpac_evt.mouse.y = sdl_evt.motion.y; | |
| } | |
| gpac_evt.type = (sdl_evt.type==SDL_MOUSEBUTTONUP) ? GF_EVENT_MOUSEUP : GF_EVENT_MOUSEDOWN; | |
| gpac_evt.mouse.window_id = dr->window_id; | |
| switch (sdl_evt.button.button) { | |
| case SDL_BUTTON_LEFT: | |
| gpac_evt.mouse.button = GF_MOUSE_LEFT; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_BUTTON_MIDDLE: | |
| gpac_evt.mouse.button = GF_MOUSE_MIDDLE; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_BUTTON_RIGHT: | |
| gpac_evt.mouse.button = GF_MOUSE_RIGHT; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| #ifdef SDL_BUTTON_WHEELUP | |
| case SDL_BUTTON_WHEELUP: | |
| case SDL_BUTTON_WHEELDOWN: | |
| /*SDL handling is not perfect there, it just says up/down but no info on how much | |
| the wheel was rotated...*/ | |
| gpac_evt.mouse.wheel_pos = (sdl_evt.button.button==SDL_BUTTON_WHEELUP) ? FIX_ONE : -FIX_ONE; | |
| gpac_evt.type = GF_EVENT_MOUSEWHEEL; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| #endif | |
| } | |
| break; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| case SDL_MOUSEWHEEL: | |
| /*SDL handling is not perfect there, it just says up/down but no info on how much | |
| the wheel was rotated...*/ | |
| gpac_evt.mouse.wheel_pos = INT2FIX(sdl_evt.wheel.y); | |
| gpac_evt.type = GF_EVENT_MOUSEWHEEL; | |
| gpac_evt.mouse.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_MULTIGESTURE: | |
| gpac_evt.mtouch.x = FLT2FIX(sdl_evt.mgesture.x); | |
| gpac_evt.mtouch.y = FLT2FIX(sdl_evt.mgesture.y); | |
| gpac_evt.mtouch.num_fingers = sdl_evt.mgesture.numFingers; | |
| gpac_evt.mtouch.rotation = sdl_evt.mgesture.dTheta; | |
| gpac_evt.mtouch.pinch = sdl_evt.mgesture.dDist; | |
| gpac_evt.mtouch.window_id = dr->window_id; | |
| gpac_evt.type = GF_EVENT_MULTITOUCH; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| break; | |
| case SDL_DROPFILE: | |
| gpac_evt.type = GF_EVENT_DROPFILE; | |
| gpac_evt.open_file.nb_files = 1; | |
| gpac_evt.open_file.files = &sdl_evt.drop.file; | |
| gpac_evt.open_file.window_id = dr->window_id; | |
| dr->on_event(dr->evt_cbk_hdl, &gpac_evt); | |
| #endif | |
| } | |
| } | |
| return GF_TRUE; | |
| } | |
| #ifdef SDL_WINDOW_THREAD | |
| u32 SDLVid_EventProc(void *par) | |
| { | |
| #if 0 | |
| u32 last_mouse_move; | |
| #endif | |
| Bool ret; | |
| GF_VideoOutput *dr = (GF_VideoOutput *)par; | |
| SDLVID(); | |
| if (!SDLVid_InitializeWindow(ctx, dr)) { | |
| ctx->sdl_th_state = SDL_STATE_STOP_REQ; | |
| return 1; | |
| } | |
| ctx->sdl_th_state = SDL_STATE_RUNNING; | |
| while (ctx->sdl_th_state==SDL_STATE_RUNNING) { | |
| /*after much testing: we must ensure nothing is using the event queue when resizing window. | |
| -- under X, it throws Xlib "unexpected async reply" under linux, therefore we don't wait events, | |
| we check for events and execute them if any | |
| -- under Win32, the SDL_SetVideoMode deadlocks, so we don't force exclusive access to events | |
| */ | |
| #ifndef WIN32 | |
| gf_mx_p(ctx->evt_mx); | |
| #endif | |
| ret = SDLVid_ProcessMessageQueue(ctx, dr); | |
| #ifndef WIN32 | |
| gf_mx_v(ctx->evt_mx); | |
| #endif | |
| /*looks like this hides the cursor for ever when switching back from FS*/ | |
| #if 0 | |
| if (ctx->fullscreen && (last_mouse_move + 2000 < SDL_GetTicks()) ) { | |
| if (cursor_on) SDL_ShowCursor(0); | |
| cursor_on = 0; | |
| } else if (!cursor_on) { | |
| SDL_ShowCursor(1); | |
| cursor_on = 1; | |
| } | |
| #endif | |
| /*QUIT message has been processed*/ | |
| if (!ret) { | |
| ctx->sdl_th_state = SDL_STATE_STOP_REQ; | |
| break; | |
| } | |
| gf_sleep(2); | |
| } | |
| while (ctx->sdl_th_state == SDL_STATE_STOP_REQ) | |
| gf_sleep(10); | |
| SDLVid_ShutdownWindow(ctx); | |
| ctx->sdl_th_state = SDL_STATE_STOPPED; | |
| return 0; | |
| } | |
| #endif /*SDL_WINDOW_THREAD*/ | |
| GF_Err SDLVid_Setup(struct _video_out *dr, void *os_handle, void *os_display, u32 init_flags) | |
| { | |
| Bool show_window = GF_TRUE; | |
| SDLVID(); | |
| /*we don't allow SDL hack, not stable enough*/ | |
| //if (os_handle) SDLVid_SetHack(os_handle, 1); | |
| ctx->os_handle = os_handle; | |
| if (!ctx->is_init) { | |
| ctx->output_3d = GF_FALSE; | |
| show_window = GF_TRUE; | |
| } | |
| ctx->force_alpha = (init_flags & GF_VOUT_WINDOW_TRANSPARENT) ? GF_TRUE : GF_FALSE; | |
| ctx->hidden = (init_flags & GF_VOUT_INIT_HIDE) ? GF_TRUE : GF_FALSE; | |
| if (!ctx->hidden && show_window) { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_ShowWindow(ctx->screen); | |
| #else | |
| #endif | |
| } | |
| if (!SDLOUT_InitSDL()) | |
| return GF_IO_ERR; | |
| #ifdef SDL_WINDOW_THREAD | |
| ctx->sdl_th_state = SDL_STATE_STOPPED; | |
| gf_th_run(ctx->sdl_th, SDLVid_EventProc, dr); | |
| while (!ctx->sdl_th_state) | |
| gf_sleep(10); | |
| if (ctx->sdl_th_state==SDL_STATE_STOP_REQ) { | |
| SDLOUT_CloseSDL(); | |
| ctx->sdl_th_state = SDL_STATE_STOPPED; | |
| return GF_IO_ERR; | |
| } | |
| #else | |
| if (!SDLVid_InitializeWindow(ctx, dr)) { | |
| if (!gf_list_count(video_outputs)) { | |
| SDL_QuitSubSystem(SDL_INIT_VIDEO); | |
| gf_list_del(video_outputs); | |
| video_outputs=NULL; | |
| } | |
| SDLOUT_CloseSDL(); | |
| return GF_IO_ERR; | |
| } | |
| #endif | |
| //coverage | |
| #ifdef GPAC_ENABLE_COVERAGE | |
| if (gf_sys_is_cov_mode()) { | |
| GF_Event evt; | |
| sdl_translate_key(SDLK_BACKSPACE, &evt.key); | |
| SDLVid_SetCursor(dr, GF_CURSOR_NORMAL); | |
| } | |
| #endif | |
| ctx->is_init = GF_TRUE; | |
| return GF_OK; | |
| } | |
| static void SDLVid_Shutdown(GF_VideoOutput *dr) | |
| { | |
| SDLVID(); | |
| /*remove all surfaces*/ | |
| if (!ctx->is_init) return; | |
| #ifdef SDL_WINDOW_THREAD | |
| if (ctx->sdl_th_state==SDL_STATE_RUNNING) { | |
| SDL_Event evt; | |
| evt.type = SDL_QUIT; | |
| SDL_PushEvent(&evt); | |
| } | |
| /*wait until thread say it is stopped*/ | |
| ctx->sdl_th_state = SDL_STATE_WAIT_FOR_THREAD_TERMINATION; | |
| while (ctx->sdl_th_state != SDL_STATE_STOPPED) | |
| gf_sleep(10); | |
| #else | |
| SDLVid_ShutdownWindow(ctx); | |
| #endif | |
| SDLOUT_CloseSDL(); | |
| ctx->is_init = GF_FALSE; | |
| dr->window_id = 0; | |
| } | |
| GF_Err SDLVid_SetFullScreen(GF_VideoOutput *dr, Bool bFullScreenOn, u32 *screen_width, u32 *screen_height) | |
| { | |
| int bpp; | |
| u32 pref_bpp; | |
| SDLVID(); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_DisplayMode goodMode; | |
| u32 numDisplayModes; | |
| u32 mask; | |
| #endif | |
| if (ctx->fullscreen==bFullScreenOn) return GF_OK; | |
| /*lock to get sure the event queue is not processed under X*/ | |
| gf_mx_p(ctx->evt_mx); | |
| ctx->fullscreen = bFullScreenOn; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_GetCurrentDisplayMode(0, &goodMode); | |
| SDL_PixelFormatEnumToMasks(goodMode.format, &bpp, &mask, &mask, &mask, &mask); | |
| pref_bpp = bpp; | |
| #else | |
| pref_bpp = bpp = ctx->screen->format->BitsPerPixel; | |
| #endif | |
| if (ctx->fullscreen) { | |
| #if ! ( SDL_VERSION_ATLEAST(2,0,0) ) | |
| u32 flags = ctx->output_3d ? SDL_GL_FULLSCREEN_FLAGS : SDL_FULLSCREEN_FLAGS; | |
| #endif | |
| Bool switch_res = gf_module_get_bool((GF_BaseInterface*)dr, "switch-vres"); | |
| if (!dr->max_screen_width || !dr->max_screen_height) switch_res = GF_TRUE; | |
| ctx->store_width = *screen_width; | |
| ctx->store_height = *screen_height; | |
| if (switch_res) { | |
| u32 i; | |
| ctx->fs_width = *screen_width; | |
| ctx->fs_height = *screen_height; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| numDisplayModes = SDL_GetNumDisplayModes(0); | |
| for(i=0; i<numDisplayModes; i++) { | |
| SDL_GetDisplayMode(0, i, &goodMode); | |
| if ((ctx->fs_width <= (u32) goodMode.w) && (ctx->fs_height <= (u32) goodMode.h)) { | |
| s32 bppDisp; | |
| ctx->fs_width = goodMode.w; | |
| ctx->fs_height = goodMode.h; | |
| SDL_PixelFormatEnumToMasks(goodMode.format, &bppDisp, &mask, &mask, &mask, &mask); | |
| pref_bpp = bppDisp; | |
| break; | |
| } | |
| } | |
| #else | |
| for(i=0; i<nb_video_modes; i++) { | |
| if (ctx->fs_width<=video_modes[2*i] && ctx->fs_height<=video_modes[2*i + 1]) { | |
| if ((pref_bpp = SDL_VideoModeOK(video_modes[2*i], video_modes[2*i+1], bpp, flags))) { | |
| ctx->fs_width = video_modes[2*i]; | |
| ctx->fs_height = video_modes[2*i + 1]; | |
| break; | |
| } | |
| } | |
| } | |
| #endif | |
| } else { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_GetCurrentDisplayMode(0, &goodMode); | |
| #endif | |
| ctx->fs_width = dr->max_screen_width; | |
| ctx->fs_height = dr->max_screen_height; | |
| } | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_SetWindowDisplayMode(ctx->screen, &goodMode); | |
| SDL_SetWindowFullscreen(ctx->screen, SDL_WINDOW_FULLSCREEN_DESKTOP); | |
| #else | |
| ctx->screen = SDL_SetVideoMode(ctx->fs_width, ctx->fs_height, pref_bpp, flags); | |
| #endif | |
| /*we switched bpp, clean all objects*/ | |
| if (bpp != pref_bpp) SDLVid_DestroyObjects(ctx); | |
| *screen_width = ctx->fs_width; | |
| *screen_height = ctx->fs_height; | |
| /*GL has changed*/ | |
| if (ctx->output_3d) { | |
| GF_Event evt; | |
| memset(&evt, 0, sizeof(GF_Event)); | |
| evt.type = GF_EVENT_VIDEO_SETUP; | |
| evt.setup.use_opengl = GF_TRUE; | |
| dr->on_event(dr->evt_cbk_hdl, &evt); | |
| } | |
| } else { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDL_SetWindowFullscreen(ctx->screen, 0); | |
| #endif | |
| SDLVid_ResizeWindow(dr, ctx->store_width, ctx->store_height); | |
| *screen_width = ctx->store_width; | |
| *screen_height = ctx->store_height; | |
| } | |
| gf_mx_v(ctx->evt_mx); | |
| if (!ctx->screen) return GF_IO_ERR; | |
| return GF_OK; | |
| } | |
| GF_Err SDLVid_SetBackbufferSize(GF_VideoOutput *dr, u32 newWidth, u32 newHeight, Bool system_mem) | |
| { | |
| const char *opt; | |
| SDLVID(); | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| #else | |
| u32 col; | |
| #endif | |
| if (ctx->output_3d) return GF_BAD_PARAM; | |
| opt = gf_module_get_key((GF_BaseInterface*)dr, "hwvmem"); | |
| if (system_mem) { | |
| if (opt && !strcmp(opt, "always")) system_mem = GF_FALSE; | |
| } else { | |
| if (opt && !strcmp(opt, "never")) system_mem = GF_TRUE; | |
| } | |
| ctx->use_systems_memory = system_mem; | |
| /*clear screen*/ | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| if (ctx->tx_back_buffer) SDL_DestroyTexture(ctx->tx_back_buffer); | |
| if (ctx->back_buffer_pixels) gf_free(ctx->back_buffer_pixels); | |
| ctx->tx_back_buffer = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, newWidth, newHeight); | |
| ctx->back_buffer_pixels = gf_malloc(sizeof(char)*3*newWidth*newHeight); | |
| SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255); | |
| SDL_RenderClear(ctx->renderer); | |
| SDL_RenderPresent(ctx->renderer); | |
| #else | |
| if(ctx->screen) { | |
| col = SDL_MapRGB(ctx->screen->format, 0, 0, 0); | |
| SDL_FillRect(ctx->screen, NULL, col); | |
| SDL_Flip(ctx->screen); | |
| } | |
| if (ctx->back_buffer && ((u32) ctx->back_buffer->w==newWidth) && ((u32) ctx->back_buffer->h==newHeight)) { | |
| return GF_OK; | |
| } | |
| if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer); | |
| if (ctx->screen) ctx->back_buffer = SDL_CreateRGBSurface(ctx->use_systems_memory ? SDL_SWSURFACE : SDL_HWSURFACE, newWidth, newHeight, ctx->screen->format->BitsPerPixel, ctx->screen->format->Rmask, ctx->screen->format->Gmask, ctx->screen->format->Bmask, 0); | |
| if (!ctx->back_buffer) return GF_IO_ERR; | |
| #endif | |
| ctx->width = newWidth; | |
| ctx->height = newHeight; | |
| return GF_OK; | |
| } | |
| u32 SDLVid_MapPixelFormat(SDL_PixelFormat *format, Bool force_alpha) | |
| { | |
| if (!format || format->palette) return 0; | |
| switch (format->BitsPerPixel) { | |
| case 16: | |
| if ((format->Rmask==0x7c00) && (format->Gmask==0x03e0) && (format->Bmask==0x001f) ) return GF_PIXEL_RGB_555; | |
| if ((format->Rmask==0xf800) && (format->Gmask==0x07e0) && (format->Bmask==0x001f) ) return GF_PIXEL_RGB_565; | |
| return 0; | |
| case 24: | |
| if (format->Rmask==0x00FF0000) return GF_PIXEL_RGB; | |
| if (format->Rmask==0x000000FF) return GF_PIXEL_BGR; | |
| return 0; | |
| case 32: | |
| if (format->Amask==0xFF000000) return GF_PIXEL_ARGB; | |
| if (format->Rmask==0x00FF0000) return force_alpha ? GF_PIXEL_ARGB : GF_PIXEL_RGBX; | |
| if (format->Rmask==0x000000FF) return force_alpha ? GF_PIXEL_RGBA : GF_PIXEL_BGRX; | |
| return 0; | |
| default: | |
| return 0; | |
| } | |
| } | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_info, Bool do_lock) | |
| { | |
| SDLVID(); | |
| if (do_lock) { | |
| memset(video_info, 0, sizeof(GF_VideoSurface)); | |
| video_info->width = ctx->width; | |
| video_info->height = ctx->height; | |
| video_info->pitch_x = 0; | |
| video_info->pitch_y = ctx->width*3; | |
| video_info->video_buffer = ctx->back_buffer_pixels; | |
| video_info->pixel_format = GF_PIXEL_RGB; | |
| video_info->is_hardware_memory = 0; | |
| if (ctx->needs_bb_grab) { | |
| SDL_RenderReadPixels(ctx->renderer, NULL, SDL_PIXELFORMAT_RGB24, video_info->video_buffer, video_info->pitch_y); | |
| ctx->needs_bb_grab = 0; | |
| } | |
| } else { | |
| SDL_UpdateTexture(ctx->tx_back_buffer, NULL, video_info->video_buffer, video_info->pitch_y); | |
| SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); | |
| } | |
| return GF_OK; | |
| } | |
| #else | |
| static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_info, Bool do_lock) | |
| { | |
| SDLVID(); | |
| if (!ctx->back_buffer) return GF_BAD_PARAM; | |
| if (do_lock) { | |
| if (!video_info) return GF_BAD_PARAM; | |
| if (SDL_LockSurface(ctx->back_buffer)<0) return GF_IO_ERR; | |
| memset(video_info, 0, sizeof(GF_VideoSurface)); | |
| video_info->width = ctx->back_buffer->w; | |
| video_info->height = ctx->back_buffer->h; | |
| video_info->pitch_x = 0; | |
| video_info->pitch_y = ctx->back_buffer->pitch; | |
| video_info->video_buffer = (char*)ctx->back_buffer->pixels; | |
| video_info->pixel_format = SDLVid_MapPixelFormat(ctx->back_buffer->format, ctx->force_alpha); | |
| video_info->is_hardware_memory = !ctx->use_systems_memory; | |
| } else { | |
| SDL_UnlockSurface(ctx->back_buffer); | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| //for CGLSetParameter | |
| #if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS) | |
| #include <OpenGL/OpenGL.h> | |
| #endif | |
| static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) | |
| { | |
| SDLVID(); | |
| /*if resizing don't process otherwise we may deadlock*/ | |
| if (!ctx->screen) return GF_OK; | |
| GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] swapping video buffers\n")); | |
| if (ctx->output_3d) { | |
| //with SDL2 we have to disable vsync by overriding swap interval | |
| #if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS) && !defined(GPAC_DISABLE_3D) | |
| if (ctx->disable_vsync) { | |
| GLint sync = 0; | |
| CGLContextObj gl_ctx = CGLGetCurrentContext(); | |
| CGLSetParameter(gl_ctx, kCGLCPSwapInterval, &sync); | |
| } | |
| #endif | |
| #ifdef GPAC_CONFIG_EMSCRIPTEN | |
| void gpac_on_video_swap(); | |
| gpac_on_video_swap(); | |
| #endif | |
| SDL_GL_SwapWindow(ctx->screen); | |
| return GF_OK; | |
| } | |
| if (ctx->enable_defer_mode) { | |
| if (ctx->needs_bb_flush) { | |
| SDL_UpdateTexture(ctx->tx_back_buffer, NULL, ctx->back_buffer_pixels, 3*ctx->width); | |
| SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); | |
| } | |
| SDL_RenderReadPixels(ctx->renderer, NULL, SDL_PIXELFORMAT_RGB24, ctx->back_buffer_pixels, 3*ctx->width); | |
| ctx->needs_bb_grab = 0; | |
| ctx->needs_bb_flush = 0; | |
| SDL_RenderPresent(ctx->renderer); | |
| //push back texture after SDL flip | |
| SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); | |
| } else { | |
| ctx->needs_clear = 1; | |
| SDL_RenderPresent(ctx->renderer); | |
| } | |
| return GF_OK; | |
| } | |
| #else | |
| static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) | |
| { | |
| SDL_Rect rc; | |
| SDLVID(); | |
| /*if resizing don't process otherwise we may deadlock*/ | |
| if (!ctx->screen) return GF_OK; | |
| //GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Flush\n")); | |
| if (ctx->output_3d) { | |
| SDL_GL_SwapBuffers(); | |
| return GF_OK; | |
| } | |
| if (!ctx->back_buffer) return GF_BAD_PARAM; | |
| if ((dest->w != (u32) ctx->back_buffer->w) || (dest->h != (u32) ctx->back_buffer->h)) { | |
| GF_VideoSurface src, dst; | |
| SDL_LockSurface(ctx->back_buffer); | |
| memset(&src, 0, sizeof(GF_VideoSurface)); | |
| src.height = ctx->back_buffer->h; | |
| src.width = ctx->back_buffer->w; | |
| src.pitch_x = 0; | |
| src.pitch_y = ctx->back_buffer->pitch; | |
| src.pixel_format = SDLVid_MapPixelFormat(ctx->back_buffer->format, ctx->force_alpha); | |
| src.video_buffer = (char*)ctx->back_buffer->pixels; | |
| SDL_LockSurface(ctx->screen); | |
| dst.height = ctx->screen->h; | |
| dst.width = ctx->screen->w; | |
| dst.pitch_x = 0; | |
| dst.pitch_y = ctx->screen->pitch; | |
| dst.pixel_format = SDLVid_MapPixelFormat(ctx->screen->format, GF_FALSE); | |
| dst.video_buffer = (char*)ctx->screen->pixels; | |
| gf_stretch_bits(&dst, &src, dest, NULL, 0xFF, GF_FALSE, NULL, NULL); | |
| SDL_UnlockSurface(ctx->screen); | |
| SDL_UnlockSurface(ctx->back_buffer); | |
| } else { | |
| rc.x = dest->x; | |
| rc.y = dest->y; | |
| rc.w = dest->w; | |
| rc.h = dest->h; | |
| SDL_BlitSurface(ctx->back_buffer, NULL, ctx->screen, &rc); | |
| } | |
| SDL_Flip(ctx->screen); | |
| return GF_OK; | |
| } | |
| #endif | |
| #ifdef WIN32 | |
| static u32 get_sys_col(int idx) | |
| { | |
| u32 res; | |
| DWORD val = GetSysColor(idx); | |
| res = (val)&0xFF; | |
| res<<=8; | |
| res |= (val>>8)&0xFF; | |
| res<<=8; | |
| res |= (val>>16)&0xFF; | |
| return res; | |
| } | |
| #endif | |
| static GF_Err SDLVid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) | |
| { | |
| if (!evt) { | |
| #ifndef SDL_WINDOW_THREAD | |
| SDLVID(); | |
| SDLVid_ProcessMessageQueue(ctx, dr); | |
| #endif | |
| return GF_OK; | |
| } | |
| switch (evt->type) { | |
| case GF_EVENT_SET_CURSOR: | |
| #ifndef GPAC_CONFIG_IOS | |
| SDLVid_SetCursor(dr, evt->cursor.cursor_type); | |
| #endif | |
| break; | |
| case GF_EVENT_SET_CAPTION: | |
| #ifdef SDL_WINDOW_THREAD | |
| { | |
| SDLVID(); | |
| if (ctx->sdl_th_state != SDL_STATE_RUNNING) | |
| break; | |
| } | |
| #endif | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| { | |
| #if !defined(GPAC_CONFIG_IOS) | |
| SDLVID(); | |
| SDL_SetWindowTitle(ctx->screen, evt->caption.caption); | |
| SDLVid_ProcessEvent(dr, NULL); | |
| #endif | |
| } | |
| #else | |
| SDL_WM_SetCaption(evt->caption.caption, NULL); | |
| #endif | |
| break; | |
| case GF_EVENT_SHOWHIDE: | |
| /*the only way to have proper show/hide with SDL is to shutdown the video system and reset it up | |
| which we don't want to do since the setup MUST occur in the rendering thread for some configs (OpenGL)*/ | |
| return GF_NOT_SUPPORTED; | |
| case GF_EVENT_SIZE: | |
| { | |
| SDLVID(); | |
| #ifdef GPAC_CONFIG_IOS | |
| if (ctx->fullscreen) { | |
| } else { | |
| SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height); | |
| } | |
| #else | |
| if (ctx->fullscreen) { | |
| //ctx->store_width = evt->size.width; | |
| //ctx->store_height = evt->size.height; | |
| } else { | |
| SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height); | |
| } | |
| #endif | |
| } | |
| break; | |
| case GF_EVENT_MOVE: | |
| #if !defined(GPAC_CONFIG_IOS) && SDL_VERSION_ATLEAST(2,0,0) | |
| { | |
| SDLVID(); | |
| if (ctx->fullscreen) return GF_OK; | |
| if (evt->move.relative == 2) { | |
| } | |
| else if (evt->move.relative) { | |
| s32 x, y; | |
| x = y = 0; | |
| SDL_GetWindowPosition(ctx->screen, &x, &y); | |
| SDL_SetWindowPosition(ctx->screen, x + evt->move.x, y + evt->move.y); | |
| } else { | |
| SDL_SetWindowPosition(ctx->screen, evt->move.x, evt->move.y); | |
| } | |
| } | |
| #endif | |
| break; | |
| case GF_EVENT_VIDEO_SETUP: | |
| { | |
| SDLVID(); | |
| ctx->disable_vsync=evt->setup.disable_vsync; | |
| if (!evt->setup.use_opengl) { | |
| /*force a resetup of the window*/ | |
| if (ctx->output_3d) { | |
| ctx->width = ctx->height = 0; | |
| ctx->output_3d = GF_FALSE; | |
| SDLVid_ResetWindow(ctx); | |
| SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height); | |
| } else { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height); | |
| #endif | |
| } | |
| ctx->output_3d = GF_FALSE; | |
| return SDLVid_SetBackbufferSize(dr, evt->setup.width, evt->setup.height, evt->setup.system_memory); | |
| } else { | |
| /*force a resetup of the window*/ | |
| if (!ctx->output_3d) { | |
| ctx->width = ctx->height = 0; | |
| SDLVid_ResetWindow(ctx); | |
| } | |
| ctx->output_3d = GF_TRUE; | |
| GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Setting up 3D in SDL.\n")); | |
| #ifdef GPAC_CONFIG_IOS | |
| // return SDLVid_ResizeWindow(dr, dr->max_screen_width, dr->max_screen_height); | |
| return SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height); | |
| #else | |
| return SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height); | |
| #endif | |
| } | |
| } | |
| break; | |
| case GF_EVENT_SYS_COLORS: | |
| #ifdef WIN32 | |
| evt->sys_cols.sys_colors[0] = get_sys_col(COLOR_ACTIVEBORDER); | |
| evt->sys_cols.sys_colors[1] = get_sys_col(COLOR_ACTIVECAPTION); | |
| evt->sys_cols.sys_colors[2] = get_sys_col(COLOR_APPWORKSPACE); | |
| evt->sys_cols.sys_colors[3] = get_sys_col(COLOR_BACKGROUND); | |
| evt->sys_cols.sys_colors[4] = get_sys_col(COLOR_BTNFACE); | |
| evt->sys_cols.sys_colors[5] = get_sys_col(COLOR_BTNHIGHLIGHT); | |
| evt->sys_cols.sys_colors[6] = get_sys_col(COLOR_BTNSHADOW); | |
| evt->sys_cols.sys_colors[7] = get_sys_col(COLOR_BTNTEXT); | |
| evt->sys_cols.sys_colors[8] = get_sys_col(COLOR_CAPTIONTEXT); | |
| evt->sys_cols.sys_colors[9] = get_sys_col(COLOR_GRAYTEXT); | |
| evt->sys_cols.sys_colors[10] = get_sys_col(COLOR_HIGHLIGHT); | |
| evt->sys_cols.sys_colors[11] = get_sys_col(COLOR_HIGHLIGHTTEXT); | |
| evt->sys_cols.sys_colors[12] = get_sys_col(COLOR_INACTIVEBORDER); | |
| evt->sys_cols.sys_colors[13] = get_sys_col(COLOR_INACTIVECAPTION); | |
| evt->sys_cols.sys_colors[14] = get_sys_col(COLOR_INACTIVECAPTIONTEXT); | |
| evt->sys_cols.sys_colors[15] = get_sys_col(COLOR_INFOBK); | |
| evt->sys_cols.sys_colors[16] = get_sys_col(COLOR_INFOTEXT); | |
| evt->sys_cols.sys_colors[17] = get_sys_col(COLOR_MENU); | |
| evt->sys_cols.sys_colors[18] = get_sys_col(COLOR_MENUTEXT); | |
| evt->sys_cols.sys_colors[19] = get_sys_col(COLOR_SCROLLBAR); | |
| evt->sys_cols.sys_colors[20] = get_sys_col(COLOR_3DDKSHADOW); | |
| evt->sys_cols.sys_colors[21] = get_sys_col(COLOR_3DFACE); | |
| evt->sys_cols.sys_colors[22] = get_sys_col(COLOR_3DHIGHLIGHT); | |
| evt->sys_cols.sys_colors[23] = get_sys_col(COLOR_3DLIGHT); | |
| evt->sys_cols.sys_colors[24] = get_sys_col(COLOR_3DSHADOW); | |
| evt->sys_cols.sys_colors[25] = get_sys_col(COLOR_WINDOW); | |
| evt->sys_cols.sys_colors[26] = get_sys_col(COLOR_WINDOWFRAME); | |
| evt->sys_cols.sys_colors[27] = get_sys_col(COLOR_WINDOWTEXT); | |
| return GF_OK; | |
| #else | |
| return GF_NOT_SUPPORTED; | |
| #endif | |
| case GF_EVENT_TEXT_EDITING_START: | |
| case GF_EVENT_TEXT_EDITING_END: | |
| #if defined(GPAC_CONFIG_IOS) && SDL_VERSION_ATLEAST(2,0,0) | |
| if (evt->type==GF_EVENT_TEXT_EDITING_START) { | |
| SDL_StartTextInput(); | |
| } else { | |
| SDL_StopTextInput(); | |
| } | |
| return GF_OK; | |
| #else | |
| return GF_NOT_SUPPORTED; | |
| #endif | |
| case GF_EVENT_SET_GL: | |
| { | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| SDLVID(); | |
| if (SDL_GL_MakeCurrent(ctx->screen, ctx->gl_context)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot make context current: %s\n", SDL_GetError())); | |
| return GF_IO_ERR; | |
| } | |
| #endif | |
| } | |
| return GF_OK; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| case GF_EVENT_SET_ORIENTATION: | |
| { | |
| switch (evt->size.orientation) { | |
| case GF_DISPLAY_MODE_PORTRAIT: SDL_SetHint(SDL_HINT_ORIENTATIONS, "Portrait"); break; | |
| case GF_DISPLAY_MODE_PORTRAIT_INV: SDL_SetHint(SDL_HINT_ORIENTATIONS, "PortraitUpsideDown"); break; | |
| case GF_DISPLAY_MODE_LANDSCAPE: SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeRight"); break; | |
| case GF_DISPLAY_MODE_LANDSCAPE_INV: SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft"); break; | |
| case GF_DISPLAY_MODE_UNKNOWN: | |
| SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown"); | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| } | |
| return GF_OK; | |
| } | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type) | |
| { | |
| SDLVID(); | |
| Bool need_copy=0; | |
| u32 format; | |
| s32 acc, w, h; | |
| int res; | |
| Bool set_blend=0; | |
| SDL_Rect dstrc; | |
| SDL_Texture **pool; | |
| SDL_Rect srcrc, *src_ptr=NULL; | |
| GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] Bliting surface (overlay type %d)\n", overlay_type)); | |
| if (ctx->needs_bb_flush) { | |
| SDL_UpdateTexture(ctx->tx_back_buffer, NULL, ctx->back_buffer_pixels, 3*ctx->width); | |
| SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); | |
| ctx->needs_bb_grab = 1; | |
| } | |
| ctx->needs_bb_grab = 1; | |
| if (ctx->needs_clear) { | |
| SDL_RenderClear(ctx->renderer); | |
| ctx->needs_clear = 0; | |
| } | |
| dstrc.w = dst_wnd->w; | |
| dstrc.h = dst_wnd->h; | |
| dstrc.x = dst_wnd->x; | |
| dstrc.y = dst_wnd->y; | |
| if (src_wnd) { | |
| srcrc.x = src_wnd->x; | |
| srcrc.y = src_wnd->y; | |
| srcrc.w = src_wnd->w; | |
| srcrc.h = src_wnd->h; | |
| src_ptr = &srcrc; | |
| } | |
| //this is a clear (not very elegant ...) | |
| if ((video_src->width<=2) && (video_src->height<=2)) { | |
| u8 *pix =(u8 *) video_src->video_buffer; | |
| if (video_src->pixel_format == GF_PIXEL_RGB) { | |
| SDL_SetRenderDrawColor(ctx->renderer, pix[0], pix[1], pix[2], 0xFF); | |
| } else { | |
| SDL_SetRenderDrawColor(ctx->renderer, pix[0], pix[1], pix[2], pix[3]); | |
| } | |
| res = SDL_RenderFillRect(ctx->renderer, &dstrc); | |
| if (res<0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Clear error: %s\n", SDL_GetError())); | |
| return GF_IO_ERR; | |
| } | |
| return GF_OK; | |
| } | |
| switch (video_src->pixel_format) { | |
| case GF_PIXEL_RGB: | |
| pool = &ctx->pool_rgb; | |
| format=SDL_PIXELFORMAT_RGB24; | |
| break; | |
| case GF_PIXEL_XRGB: | |
| pool = &ctx->pool_rgb; | |
| format=SDL_PIXELFORMAT_BGRX8888; | |
| break; | |
| case GF_PIXEL_RGBX: | |
| pool = &ctx->pool_rgb; | |
| format=SDL_PIXELFORMAT_BGR888; | |
| break; | |
| case GF_PIXEL_XBGR: | |
| pool = &ctx->pool_rgb; | |
| format=SDL_PIXELFORMAT_RGBX8888; | |
| break; | |
| case GF_PIXEL_BGRX: | |
| pool = &ctx->pool_rgb; | |
| format=SDL_PIXELFORMAT_RGB888; | |
| break; | |
| case GF_PIXEL_RGBA: | |
| pool = &ctx->pool_rgba; | |
| format=SDL_PIXELFORMAT_ABGR8888; | |
| set_blend=1; | |
| break; | |
| case GF_PIXEL_YUV: | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_IYUV; | |
| break; | |
| case GF_PIXEL_YVU: | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_YV12; | |
| break; | |
| case GF_PIXEL_YUV422: | |
| case GF_PIXEL_YUV444: | |
| case GF_PIXEL_YUV444_10: | |
| case GF_PIXEL_YUV422_10: | |
| case GF_PIXEL_YUV_10: | |
| need_copy=1; | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_IYUV; | |
| break; | |
| /*FIXME we need to upgrade our SDL build*/ | |
| #if !defined(GPAC_CONFIG_IOS) && SDL_VERSION_ATLEAST(2,0,0) | |
| case GF_PIXEL_NV12: | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_NV12; | |
| break; | |
| case GF_PIXEL_NV21: | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_NV21; | |
| break; | |
| #endif | |
| case GF_PIXEL_UYVY: | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_UYVY; | |
| break; | |
| case GF_PIXEL_YUYV: | |
| pool = &ctx->pool_yuv; | |
| format=SDL_PIXELFORMAT_YUY2; | |
| break; | |
| default: | |
| return GF_NOT_SUPPORTED; | |
| } | |
| if (*pool ) { | |
| SDL_QueryTexture(*pool, &format, &acc, &w, &h); | |
| if ((w != video_src->width) || (h != video_src->height) ) { | |
| SDL_DestroyTexture(*pool); | |
| *pool = NULL; | |
| } | |
| } | |
| if (!(*pool)) { | |
| (*pool) = SDL_CreateTexture(ctx->renderer, format, SDL_TEXTUREACCESS_STREAMING, video_src->width, video_src->height); | |
| if (!(*pool)) return GF_NOT_SUPPORTED; | |
| } | |
| SDL_QueryTexture((*pool), &format, &acc, &w, &h); | |
| if (need_copy) { | |
| GF_VideoSurface dst_v; | |
| u8 *pixels; | |
| int pitch; | |
| GF_Window swnd; | |
| /*copy pixels*/ | |
| if (SDL_LockTexture(*pool, NULL, (void**)&pixels, &pitch) < 0) { | |
| return GF_NOT_SUPPORTED; | |
| } | |
| if (!src_wnd) { | |
| swnd.x = swnd.y=0; | |
| swnd.w = video_src->width; | |
| swnd.h = video_src->height; | |
| src_wnd = &swnd; | |
| } | |
| memset(&dst_v, 0, sizeof(GF_VideoSurface)); | |
| dst_v.video_buffer = pixels; | |
| dst_v.u_ptr = pixels + h*pitch; | |
| dst_v.v_ptr = pixels + 5*h*pitch/4; | |
| dst_v.pitch_y = pitch; | |
| dst_v.pixel_format = GF_PIXEL_YUV; | |
| dst_v.width = video_src->width; | |
| dst_v.height = video_src->height; | |
| gf_stretch_bits(&dst_v, video_src, NULL, src_wnd, 0xFF, GF_FALSE, NULL, NULL); | |
| SDL_UnlockTexture(*pool); | |
| } else { | |
| SDL_UpdateTexture(*pool, NULL, video_src->video_buffer, video_src->pitch_y); | |
| } | |
| if (set_blend || (video_src->global_alpha!=0xFF)) { | |
| res = SDL_SetTextureBlendMode(*pool, SDL_BLENDMODE_BLEND); | |
| if (res<0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change texture blend mode: %s\n", SDL_GetError())); | |
| return GF_IO_ERR; | |
| } | |
| res = SDL_SetTextureAlphaMod(*pool, video_src->global_alpha); | |
| if (res<0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change global alpha of texture: %s\n", SDL_GetError())); | |
| return GF_IO_ERR; | |
| } | |
| } else { | |
| res = SDL_SetTextureBlendMode(*pool, SDL_BLENDMODE_NONE); | |
| if (res<0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change texture blend mode: %s\n", SDL_GetError())); | |
| return GF_IO_ERR; | |
| } | |
| } | |
| res = SDL_RenderCopy(ctx->renderer, *pool, src_ptr, &dstrc); | |
| if (res<0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Blit error: %s\n", SDL_GetError())); | |
| return GF_IO_ERR; | |
| } | |
| return GF_OK; | |
| } | |
| #else | |
| static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type) | |
| { | |
| SDLVID(); | |
| u32 amask = 0; | |
| u32 bpp; | |
| GF_Err e = GF_OK; | |
| u32 i; | |
| u8 *dst, *src; | |
| SDL_Rect dstrc; | |
| SDL_Surface **pool; | |
| GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] Bliting surface (overlay type %d)\n", overlay_type)); | |
| if (overlay_type) { | |
| GF_VideoSurface dst_v; | |
| if (!video_src) { | |
| if (ctx->yuv_overlay) { | |
| SDL_FreeYUVOverlay(ctx->yuv_overlay); | |
| ctx->yuv_overlay=NULL; | |
| } | |
| return GF_OK; | |
| } | |
| if (!ctx->yuv_overlay || (ctx->yuv_overlay->w != src_wnd->w) || (ctx->yuv_overlay->h != src_wnd->h) ) { | |
| if (ctx->yuv_overlay) SDL_FreeYUVOverlay(ctx->yuv_overlay); | |
| ctx->yuv_overlay = SDL_CreateYUVOverlay(src_wnd->w, src_wnd->h, SDL_YV12_OVERLAY, ctx->screen); | |
| if (!ctx->yuv_overlay) return GF_NOT_SUPPORTED; | |
| } | |
| /*copy pixels*/ | |
| SDL_LockYUVOverlay(ctx->yuv_overlay); | |
| memset(&dst_v, 0, sizeof(GF_VideoSurface)); | |
| dst_v.video_buffer = (char *) ctx->yuv_overlay->pixels[0]; | |
| dst_v.u_ptr = (char *) ctx->yuv_overlay->pixels[1]; | |
| dst_v.v_ptr = (char *) ctx->yuv_overlay->pixels[2]; | |
| dst_v.pitch_y = ctx->yuv_overlay->pitches[0]; | |
| dst_v.pixel_format = GF_PIXEL_YUV; | |
| dst_v.width = video_src->width; | |
| dst_v.height = video_src->height; | |
| gf_stretch_bits(&dst_v, video_src, NULL, src_wnd, 0xFF, GF_FALSE, NULL, NULL); | |
| SDL_UnlockYUVOverlay(ctx->yuv_overlay); | |
| dstrc.w = dst_wnd->w; | |
| dstrc.h = dst_wnd->h; | |
| dstrc.x = dst_wnd->x; | |
| dstrc.y = dst_wnd->y; | |
| SDL_DisplayYUVOverlay(ctx->yuv_overlay, &dstrc); | |
| return GF_OK; | |
| } | |
| /*SDL doesn't support stretching ...*/ | |
| if ((src_wnd->w != dst_wnd->w) || (src_wnd->h!=dst_wnd->h)) | |
| return GF_NOT_SUPPORTED; | |
| switch (video_src->pixel_format) { | |
| case GF_PIXEL_RGB: | |
| pool = &ctx->pool_rgb; | |
| bpp = 3; | |
| break; | |
| case GF_PIXEL_RGBA: | |
| pool = &ctx->pool_rgba; | |
| #if SDL_BYTEORDER == SDL_BIG_ENDIAN | |
| amask = 0x000000FF; | |
| #else | |
| amask = 0xFF000000; | |
| #endif | |
| bpp = 4; | |
| break; | |
| default: | |
| return GF_NOT_SUPPORTED; | |
| } | |
| if (! *pool || ((*pool)->w < (int) src_wnd->w) || ((*pool)->h < (int) src_wnd->h) ) { | |
| if ((*pool)) SDL_FreeSurface((*pool)); | |
| (*pool) = SDL_CreateRGBSurface(ctx->use_systems_memory ? SDL_SWSURFACE : SDL_HWSURFACE, | |
| src_wnd->w, src_wnd->h, 8*bpp, | |
| 0x000000FF, 0x0000FF00, 0x00FF0000, amask); | |
| if (! (*pool) ) return GF_IO_ERR; | |
| } | |
| SDL_LockSurface(*pool); | |
| dst = (u8 *) ( (*pool)->pixels); | |
| src = (u8*)video_src->video_buffer + video_src->pitch_y*src_wnd->y + src_wnd->x*bpp; | |
| for (i=0; i<src_wnd->h; i++) { | |
| memcpy(dst, src, bpp * src_wnd->w); | |
| src += video_src->pitch_y; | |
| dst += (*pool)->pitch; | |
| } | |
| SDL_UnlockSurface(*pool); | |
| dstrc.w = dst_wnd->w; | |
| dstrc.h = dst_wnd->h; | |
| dstrc.x = dst_wnd->x; | |
| dstrc.y = dst_wnd->y; | |
| if (SDL_BlitSurface(*pool, NULL, ctx->back_buffer, &dstrc)) | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Blit error: %s\n", SDL_GetError())); | |
| return e; | |
| } | |
| #endif | |
| static GF_GPACArg SDLArgs[] = { | |
| GF_DEF_ARG("vsync", NULL, "enable vertical synchro", "true", NULL, GF_ARG_BOOL, 0), | |
| GF_DEF_ARG("switch-vres", NULL, "enable resolution switching of display", "false", NULL, GF_ARG_BOOL, 0), | |
| GF_DEF_ARG("defer", NULL, "enable defer mode when bliting", "false", NULL, GF_ARG_BOOL, 0), | |
| GF_DEF_ARG("hwvmem", NULL, "specify (2D rendering only) memory type of main video backbuffer. Depending on the scene type, this may drastically change the playback speed\n" | |
| "- always: always on hardware\n" | |
| "- never: always on system memory\n" | |
| "- auto: selected by GPAC based on content type (graphics or video)", "auto", "auto|always|never", GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO), | |
| {0}, | |
| }; | |
| void *SDL_NewVideo() | |
| { | |
| SDLVidCtx *ctx; | |
| GF_VideoOutput *driv; | |
| driv = (GF_VideoOutput*)gf_malloc(sizeof(GF_VideoOutput)); | |
| memset(driv, 0, sizeof(GF_VideoOutput)); | |
| GF_REGISTER_MODULE_INTERFACE(driv, GF_VIDEO_OUTPUT_INTERFACE, "sdl", "gpac distribution"); | |
| ctx = (SDLVidCtx*)gf_malloc(sizeof(SDLVidCtx)); | |
| memset(ctx, 0, sizeof(SDLVidCtx)); | |
| #ifdef SDL_WINDOW_THREAD | |
| ctx->sdl_th = gf_th_new("SDLVideo"); | |
| #endif | |
| ctx->evt_mx = gf_mx_new("SDLEvents"); | |
| driv->opaque = ctx; | |
| driv->Setup = SDLVid_Setup; | |
| driv->Shutdown = SDLVid_Shutdown; | |
| driv->SetFullScreen = SDLVid_SetFullScreen; | |
| driv->Flush = SDLVid_Flush; | |
| driv->ProcessEvent = SDLVid_ProcessEvent; | |
| driv->args = SDLArgs; | |
| driv->description = "Video output using SDL"; | |
| /*no offscreen opengl with SDL*/ | |
| driv->hw_caps |= GF_VIDEO_HW_OPENGL; | |
| /*no YUV hardware blitting in SDL (only overlays)*/ | |
| driv->hw_caps |= GF_VIDEO_HW_HAS_RGB ; | |
| #if SDL_VERSION_ATLEAST(2,0,0) | |
| driv->hw_caps |= GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_STRETCH | GF_VIDEO_HW_HAS_RGBA; | |
| ctx->enable_defer_mode = gf_module_get_bool((GF_BaseInterface *)driv, "defer"); | |
| if (! ctx->enable_defer_mode) | |
| driv->hw_caps |= GF_VIDEO_HW_DIRECT_ONLY; | |
| #else | |
| driv->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY; | |
| #endif | |
| #ifdef GPAC_ENABLE_COVERAGE | |
| SDLVid_MapPixelFormat(NULL, GF_FALSE); | |
| #endif | |
| driv->Blit = SDL_Blit; | |
| driv->LockBackBuffer = SDLVid_LockBackBuffer; | |
| driv->LockOSContext = NULL; | |
| #ifndef SDL_TEXTINPUTEVENT_TEXT_SIZE | |
| SDL_EnableUNICODE(1); | |
| #else | |
| SDL_StartTextInput(); | |
| #endif /* SDL_TEXTINPUTEVENT_TEXT_SIZE */ | |
| return driv; | |
| } | |
| void SDL_DeleteVideo(void *ifce) | |
| { | |
| GF_VideoOutput *dr = (GF_VideoOutput *)ifce; | |
| SDLVID(); | |
| #ifdef SDL_WINDOW_THREAD | |
| gf_th_del(ctx->sdl_th); | |
| #endif | |
| gf_mx_del(ctx->evt_mx); | |
| gf_list_del_item(video_outputs, dr); | |
| nb_video_outputs = gf_list_count(video_outputs); | |
| if (!nb_video_outputs) { | |
| gf_list_del(video_outputs); | |
| video_outputs = NULL; | |
| SDL_QuitSubSystem(SDL_INIT_VIDEO); | |
| } | |
| gf_free(ctx); | |
| gf_free(dr); | |
| } | |