1444 lines
51 KiB
C
1444 lines
51 KiB
C
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 2009-2014 Sergii Pylypenko
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
/*
|
|
This source code is distibuted under ZLIB license, however when compiling with SDL 1.2,
|
|
which is licensed under LGPL, the resulting library, and all it's source code,
|
|
falls under "stronger" LGPL terms, so is this file.
|
|
If you compile this code with SDL 1.3 or newer, or use in some other way, the license stays ZLIB.
|
|
*/
|
|
|
|
#include "SDL_config.h"
|
|
|
|
#include "SDL_video.h"
|
|
#include "SDL_mouse.h"
|
|
#include "SDL_mutex.h"
|
|
#include "SDL_thread.h"
|
|
#include "../SDL_sysvideo.h"
|
|
#include "../SDL_pixels_c.h"
|
|
#include "../../events/SDL_events_c.h"
|
|
|
|
#include "SDL_pixels.h"
|
|
#include "SDL_video-1.3.h"
|
|
#include "SDL_surface.h"
|
|
#include "SDL_androidvideo.h"
|
|
#include "SDL_androidinput.h"
|
|
|
|
#include <jni.h>
|
|
#include <android/log.h>
|
|
#include <GLES/gl.h>
|
|
#include <GLES/glext.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h> // for memset()
|
|
#include <dlfcn.h>
|
|
|
|
#define _THIS SDL_VideoDevice *this
|
|
|
|
#ifdef VIDEO_DEBUG
|
|
#define DEBUGOUT(...) __android_log_print(ANDROID_LOG_INFO, "libSDL", __VA_ARGS__)
|
|
#else
|
|
#define DEBUGOUT(...)
|
|
#endif
|
|
|
|
static int ANDROID_VideoInit(_THIS, SDL_PixelFormat *vformat);
|
|
static SDL_Rect **ANDROID_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
|
|
static SDL_Surface *ANDROID_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
|
|
static int ANDROID_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
|
|
static void ANDROID_VideoQuit(_THIS);
|
|
|
|
static int ANDROID_AllocHWSurface(_THIS, SDL_Surface *surface);
|
|
static int ANDROID_LockHWSurface(_THIS, SDL_Surface *surface);
|
|
static void ANDROID_UnlockHWSurface(_THIS, SDL_Surface *surface);
|
|
static void ANDROID_FreeHWSurface(_THIS, SDL_Surface *surface);
|
|
static int ANDROID_FlipHWSurface(_THIS, SDL_Surface *surface);
|
|
static void ANDROID_GL_SwapBuffers(_THIS);
|
|
static void ANDROID_PumpEvents(_THIS);
|
|
static int ANDROID_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst);
|
|
static int ANDROID_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
|
|
static int ANDROID_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key);
|
|
static int ANDROID_SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 value);
|
|
static void* ANDROID_GL_GetProcAddress(_THIS, const char *proc);
|
|
static void ANDROID_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
|
|
|
|
// Multithreaded video support for speed optimization
|
|
static int ANDROID_VideoInitMT(_THIS, SDL_PixelFormat *vformat);
|
|
static SDL_Surface *ANDROID_SetVideoModeMT(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
|
|
static void ANDROID_VideoQuitMT(_THIS);
|
|
static void ANDROID_UpdateRectsMT(_THIS, int numrects, SDL_Rect *rects);
|
|
static int ANDROID_FlipHWSurfaceMT(_THIS, SDL_Surface *surface);
|
|
static int ANDROID_ToggleFullScreen(_THIS, int fullscreen);
|
|
static Uint32 PixelFormatEnum = SDL_PIXELFORMAT_RGB565;
|
|
static Uint32 PixelFormatEnumAlpha = SDL_PIXELFORMAT_RGBA4444;
|
|
static Uint32 PixelFormatEnumColorkey = SDL_PIXELFORMAT_RGBA5551;
|
|
|
|
|
|
// Stubs to get rid of crashing in OpenGL mode
|
|
// The implementation dependent data for the window manager cursor
|
|
struct WMcursor {
|
|
int unused ;
|
|
};
|
|
|
|
void ANDROID_FreeWMCursor(_THIS, WMcursor *cursor) {
|
|
SDL_free (cursor);
|
|
return;
|
|
}
|
|
WMcursor * ANDROID_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y) {
|
|
WMcursor * cursor;
|
|
cursor = (WMcursor *) SDL_malloc (sizeof (WMcursor)) ;
|
|
if (cursor == NULL) {
|
|
SDL_OutOfMemory () ;
|
|
return NULL ;
|
|
}
|
|
return cursor;
|
|
}
|
|
int ANDROID_ShowWMCursor(_THIS, WMcursor *cursor) {
|
|
return 1;
|
|
}
|
|
void ANDROID_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
|
|
{
|
|
SDL_ANDROID_WarpMouse(x, y);
|
|
}
|
|
//void ANDROID_MoveWMCursor(_THIS, int x, int y) { }
|
|
|
|
int ANDROID_ToggleFullScreen(_THIS, int fullscreen)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
enum { SDL_NUMMODES = 57 };
|
|
static SDL_Rect *SDL_modelist[SDL_NUMMODES+1];
|
|
|
|
//#define SDL_modelist (this->hidden->SDL_modelist)
|
|
|
|
typedef struct SDL_Texture private_hwdata;
|
|
|
|
// Pointer to in-memory video surface
|
|
int SDL_ANDROID_sFakeWindowWidth = 640;
|
|
int SDL_ANDROID_sFakeWindowHeight = 480;
|
|
int sdl_opengl = 0;
|
|
static SDL_Window *SDL_VideoWindow = NULL;
|
|
SDL_Surface *SDL_CurrentVideoSurface = NULL;
|
|
static int HwSurfaceCount = 0;
|
|
static SDL_Surface ** HwSurfaceList = NULL;
|
|
void * glLibraryHandle = NULL;
|
|
void * gl2LibraryHandle = NULL;
|
|
|
|
static Uint32 SDL_VideoThreadID = 0;
|
|
int SDL_ANDROID_InsideVideoThread()
|
|
{
|
|
return SDL_VideoThreadID == SDL_ThreadID();
|
|
}
|
|
|
|
|
|
/* ANDROID driver bootstrap functions */
|
|
|
|
static int ANDROID_Available(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void ANDROID_DeleteDevice(SDL_VideoDevice *device)
|
|
{
|
|
SDL_free(device->hidden);
|
|
SDL_free(device);
|
|
}
|
|
|
|
static SDL_VideoDevice *ANDROID_CreateDevice(int devindex)
|
|
{
|
|
SDL_VideoDevice *device;
|
|
|
|
/* Initialize all variables that we clean on shutdown */
|
|
device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
|
|
if ( device ) {
|
|
SDL_memset(device, 0, sizeof(SDL_VideoDevice));
|
|
} else {
|
|
SDL_OutOfMemory();
|
|
return(0);
|
|
}
|
|
|
|
/* Set the function pointers */
|
|
device->VideoInit = SDL_ANDROID_VideoMultithreaded ? ANDROID_VideoInitMT : ANDROID_VideoInit;
|
|
device->ListModes = ANDROID_ListModes;
|
|
device->SetVideoMode = SDL_ANDROID_VideoMultithreaded ? ANDROID_SetVideoModeMT : ANDROID_SetVideoMode;
|
|
device->CreateYUVOverlay = NULL;
|
|
device->SetColors = ANDROID_SetColors;
|
|
device->UpdateRects = SDL_ANDROID_VideoMultithreaded ? ANDROID_UpdateRectsMT : ANDROID_UpdateRects;
|
|
device->VideoQuit = SDL_ANDROID_VideoMultithreaded ? ANDROID_VideoQuitMT : ANDROID_VideoQuit;
|
|
device->AllocHWSurface = ANDROID_AllocHWSurface;
|
|
device->CheckHWBlit = ANDROID_CheckHWBlit;
|
|
device->FillHWRect = ANDROID_FillHWRect;
|
|
device->SetHWColorKey = ANDROID_SetHWColorKey;
|
|
device->SetHWAlpha = ANDROID_SetHWAlpha;
|
|
device->LockHWSurface = ANDROID_LockHWSurface;
|
|
device->UnlockHWSurface = ANDROID_UnlockHWSurface;
|
|
device->FlipHWSurface = SDL_ANDROID_VideoMultithreaded ? ANDROID_FlipHWSurfaceMT : ANDROID_FlipHWSurface;
|
|
device->FreeHWSurface = ANDROID_FreeHWSurface;
|
|
device->SetCaption = NULL;
|
|
device->SetIcon = NULL;
|
|
device->IconifyWindow = NULL;
|
|
device->GrabInput = NULL;
|
|
device->GetWMInfo = NULL;
|
|
device->InitOSKeymap = ANDROID_InitOSKeymap;
|
|
device->PumpEvents = ANDROID_PumpEvents;
|
|
device->GL_SwapBuffers = ANDROID_GL_SwapBuffers;
|
|
device->GL_GetProcAddress = ANDROID_GL_GetProcAddress;
|
|
device->free = ANDROID_DeleteDevice;
|
|
device->WarpWMCursor = ANDROID_WarpWMCursor;
|
|
|
|
// Stubs
|
|
device->FreeWMCursor = ANDROID_FreeWMCursor;
|
|
device->CreateWMCursor = ANDROID_CreateWMCursor;
|
|
device->ShowWMCursor = ANDROID_ShowWMCursor;
|
|
device->ToggleFullScreen = ANDROID_ToggleFullScreen;
|
|
|
|
device->handles_any_size = 1; // Any video mode is OK
|
|
|
|
glLibraryHandle = dlopen("libGLESv1_CM.so", RTLD_NOW | RTLD_GLOBAL);
|
|
if(SDL_ANDROID_UseGles2)
|
|
{
|
|
gl2LibraryHandle = dlopen("libGLESv2.so", RTLD_NOW | RTLD_GLOBAL);
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Loading libGLESv2.so: %p", gl2LibraryHandle);
|
|
}
|
|
|
|
return device;
|
|
}
|
|
|
|
VideoBootStrap ANDROID_bootstrap = {
|
|
"android", "SDL android video driver",
|
|
ANDROID_Available, ANDROID_CreateDevice
|
|
};
|
|
|
|
int ANDROID_VideoInit(_THIS, SDL_PixelFormat *vformat)
|
|
{
|
|
int i;
|
|
static SDL_PixelFormat alphaFormat;
|
|
int bpp;
|
|
static int alreadyInitialized = 0;
|
|
if(alreadyInitialized)
|
|
__android_log_print(ANDROID_LOG_WARN, "libSDL", "Application calls SDL_Init() multiple times, this is not supported yet!");
|
|
alreadyInitialized = 1;
|
|
|
|
/* Determine the screen depth (use default 16-bit depth) */
|
|
/* we change this during the SDL_SetVideoMode implementation... */
|
|
if( vformat ) {
|
|
vformat->BitsPerPixel = SDL_ANDROID_BITSPERPIXEL;
|
|
vformat->BytesPerPixel = SDL_ANDROID_BYTESPERPIXEL;
|
|
}
|
|
|
|
if( SDL_ANDROID_BITSPERPIXEL == 24 )
|
|
PixelFormatEnum = SDL_PIXELFORMAT_RGB24;
|
|
if( SDL_ANDROID_BITSPERPIXEL == 32 )
|
|
PixelFormatEnum = SDL_PIXELFORMAT_ABGR8888;
|
|
|
|
if( SDL_ANDROID_BITSPERPIXEL >= 24 )
|
|
{
|
|
PixelFormatEnumAlpha = SDL_PIXELFORMAT_ABGR8888;
|
|
PixelFormatEnumColorkey = SDL_PIXELFORMAT_ABGR8888;
|
|
}
|
|
|
|
SDL_memset(&alphaFormat, 0, sizeof(alphaFormat));
|
|
SDL_PixelFormatEnumToMasks( PixelFormatEnumAlpha, &bpp,
|
|
&alphaFormat.Rmask, &alphaFormat.Gmask,
|
|
&alphaFormat.Bmask, &alphaFormat.Amask );
|
|
alphaFormat.BitsPerPixel = SDL_ANDROID_BITSPERPIXEL;
|
|
alphaFormat.BytesPerPixel = SDL_ANDROID_BYTESPERPIXEL;
|
|
this->displayformatalphapixel = &alphaFormat;
|
|
|
|
this->info.hw_available = 1;
|
|
this->info.blit_hw = 1;
|
|
this->info.blit_hw_CC = 1;
|
|
this->info.blit_hw_A = 1;
|
|
this->info.blit_fill = 1;
|
|
this->info.video_mem = 128 * 1024; // Random value
|
|
this->info.current_w = SDL_ANDROID_sWindowWidth;
|
|
this->info.current_h = SDL_ANDROID_sWindowHeight;
|
|
SDL_VideoThreadID = SDL_ThreadID();
|
|
|
|
for ( i=0; i<SDL_NUMMODES; ++i ) {
|
|
SDL_modelist[i] = SDL_malloc(sizeof(SDL_Rect));
|
|
SDL_modelist[i]->x = SDL_modelist[i]->y = 0;
|
|
}
|
|
/* Modes sorted largest to smallest */
|
|
SDL_modelist[0]->w = SDL_ANDROID_sWindowWidth; SDL_modelist[0]->h = SDL_ANDROID_sWindowHeight;
|
|
SDL_modelist[1]->w = SDL_ANDROID_sWindowWidth * 5 / 6; SDL_modelist[1]->h = SDL_ANDROID_sWindowHeight * 5 / 6;
|
|
SDL_modelist[2]->w = SDL_ANDROID_sWindowWidth * 4 / 6; SDL_modelist[2]->h = SDL_ANDROID_sWindowHeight * 4 / 6;
|
|
SDL_modelist[3]->w = SDL_ANDROID_sWindowWidth * 3 / 6; SDL_modelist[3]->h = SDL_ANDROID_sWindowHeight * 3 / 6;
|
|
SDL_modelist[4]->w = SDL_ANDROID_sWindowWidth * 2 / 6; SDL_modelist[4]->h = SDL_ANDROID_sWindowHeight * 2 / 6;
|
|
SDL_modelist[5]->w = 800; SDL_modelist[5]->h = 600; // Widely used on PC
|
|
SDL_modelist[6]->w = 640; SDL_modelist[6]->h = 480; // Widely used on PC
|
|
SDL_modelist[7]->w = 640; SDL_modelist[7]->h = 400; // Widely used on PC
|
|
SDL_modelist[8]->w = 320; SDL_modelist[8]->h = 240; // For older games
|
|
SDL_modelist[9]->w = 320; SDL_modelist[9]->h = 200; // For even older games
|
|
SDL_modelist[10]->w = 480; SDL_modelist[10]->h = 320; // Virtual wide-screen mode
|
|
SDL_modelist[11]->w = 800; SDL_modelist[11]->h = 480; // Virtual wide-screen mode
|
|
SDL_modelist[12]->w = 640; SDL_modelist[12]->h = 350; // For PrefClub app
|
|
SDL_modelist[13]->w = 320; SDL_modelist[13]->h = 256; // For UAE4ALL2
|
|
SDL_modelist[14]->w = 640; SDL_modelist[14]->h = 200; // For UAE4ALL2
|
|
SDL_modelist[15]->w = 640; SDL_modelist[15]->h = 240; // For UAE4ALL2
|
|
SDL_modelist[16]->w = 640; SDL_modelist[16]->h = 256; // For UAE4ALL2
|
|
SDL_modelist[17]->w = 320; SDL_modelist[17]->h = 262; // For UAE4ALL2
|
|
SDL_modelist[18]->w = 640; SDL_modelist[18]->h = 262; // For UAE4ALL2
|
|
SDL_modelist[19]->w = 320; SDL_modelist[19]->h = 270; // For UAE4ALL2
|
|
SDL_modelist[20]->w = 640; SDL_modelist[20]->h = 270; // For UAE4ALL2
|
|
SDL_modelist[21]->w = 320; SDL_modelist[21]->h = 216; // For UAE4ALL2
|
|
SDL_modelist[22]->w = 640; SDL_modelist[22]->h = 216; // For UAE4ALL2
|
|
SDL_modelist[23]->w = 384; SDL_modelist[23]->h = 272; // For VICE
|
|
SDL_modelist[24]->w = 854; SDL_modelist[24]->h = 480; // Virtual wide-screen mode
|
|
SDL_modelist[25]->w = 1280; SDL_modelist[25]->h = 720; // Virtual wide-screen mode
|
|
SDL_modelist[26]->w = 1920; SDL_modelist[26]->h = 1080; // Virtual wide-screen mode
|
|
SDL_modelist[27]->w = 1024; SDL_modelist[27]->h = 768; // Widely used on PC
|
|
SDL_modelist[28]->w = 640; SDL_modelist[28]->h = 512; // For P-UAE
|
|
SDL_modelist[29]->w = 640; SDL_modelist[29]->h = 524; // For P-UAE
|
|
SDL_modelist[30]->w = 640; SDL_modelist[30]->h = 540; // For P-UAE
|
|
SDL_modelist[31]->w = 352; SDL_modelist[31]->h = 200; // For UAE4ALL2
|
|
SDL_modelist[32]->w = 352; SDL_modelist[32]->h = 216; // For UAE4ALL2
|
|
SDL_modelist[33]->w = 352; SDL_modelist[33]->h = 240; // For UAE4ALL2
|
|
SDL_modelist[34]->w = 352; SDL_modelist[34]->h = 256; // For UAE4ALL2
|
|
SDL_modelist[35]->w = 352; SDL_modelist[35]->h = 262; // For UAE4ALL2
|
|
SDL_modelist[36]->w = 352; SDL_modelist[36]->h = 270; // For UAE4ALL2
|
|
SDL_modelist[37]->w = 384; SDL_modelist[37]->h = 200; // For UAE4ALL2
|
|
SDL_modelist[38]->w = 384; SDL_modelist[38]->h = 216; // For UAE4ALL2
|
|
SDL_modelist[39]->w = 384; SDL_modelist[39]->h = 240; // For UAE4ALL2
|
|
SDL_modelist[40]->w = 384; SDL_modelist[40]->h = 256; // For UAE4ALL2
|
|
SDL_modelist[41]->w = 384; SDL_modelist[41]->h = 262; // For UAE4ALL2
|
|
SDL_modelist[42]->w = 384; SDL_modelist[42]->h = 270; // For UAE4ALL2
|
|
SDL_modelist[43]->w = 704; SDL_modelist[43]->h = 200; // For UAE4ALL2
|
|
SDL_modelist[44]->w = 704; SDL_modelist[44]->h = 216; // For UAE4ALL2
|
|
SDL_modelist[45]->w = 704; SDL_modelist[45]->h = 240; // For UAE4ALL2
|
|
SDL_modelist[46]->w = 704; SDL_modelist[46]->h = 256; // For UAE4ALL2
|
|
SDL_modelist[47]->w = 704; SDL_modelist[47]->h = 262; // For UAE4ALL2
|
|
SDL_modelist[48]->w = 704; SDL_modelist[48]->h = 270; // For UAE4ALL2
|
|
SDL_modelist[49]->w = 768; SDL_modelist[49]->h = 200; // For UAE4ALL2
|
|
SDL_modelist[50]->w = 768; SDL_modelist[50]->h = 216; // For UAE4ALL2
|
|
SDL_modelist[51]->w = 768; SDL_modelist[51]->h = 240; // For UAE4ALL2
|
|
SDL_modelist[52]->w = 768; SDL_modelist[52]->h = 256; // For UAE4ALL2
|
|
SDL_modelist[53]->w = 768; SDL_modelist[53]->h = 262; // For UAE4ALL2
|
|
SDL_modelist[54]->w = 768; SDL_modelist[54]->h = 270; // For UAE4ALL2
|
|
SDL_modelist[55]->w = 1280; SDL_modelist[55]->h = 960; // For UQM-HD
|
|
SDL_modelist[56]->w = 960; SDL_modelist[56]->h = 600; // For ScummVM 3x-mode
|
|
SDL_modelist[57] = NULL;
|
|
// If you going to add another video mode, increase SDL_NUMMODES constant
|
|
|
|
SDL_VideoInit_1_3(NULL, 0);
|
|
|
|
/* We're done! */
|
|
return(0);
|
|
}
|
|
|
|
SDL_Rect **ANDROID_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
|
|
{
|
|
if(format->BitsPerPixel != SDL_ANDROID_BITSPERPIXEL)
|
|
return NULL;
|
|
return SDL_modelist;
|
|
}
|
|
|
|
SDL_Surface *ANDROID_SetVideoMode(_THIS, SDL_Surface *current,
|
|
int width, int height, int bpp, Uint32 flags)
|
|
{
|
|
SDL_PixelFormat format;
|
|
int bpp1;
|
|
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_SetVideoMode(): application requested mode %dx%d OpenGL %d HW %d BPP %d", width, height, flags & SDL_OPENGL, flags & SDL_HWSURFACE, SDL_ANDROID_BITSPERPIXEL);
|
|
if( ! SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
if( SDL_ANDROID_VideoForceSoftwareMode )
|
|
{
|
|
if( flags & SDL_HWSURFACE )
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_SetVideoMode(): application requested hardware video mode - forcing software video mode");
|
|
if( flags & SDL_OPENGL )
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: application requested OpenGL context - SDL will ignore this. Set SwVideoMode=n inside AndroidAppSettings.cfg to enable OpenGL inside SDL.");
|
|
flags = (flags & SDL_FULLSCREEN) | (flags & SDL_DOUBLEBUF);
|
|
}
|
|
|
|
sdl_opengl = (flags & SDL_OPENGL) ? 1 : 0;
|
|
|
|
SDL_ANDROID_sFakeWindowWidth = width;
|
|
SDL_ANDROID_sFakeWindowHeight = height;
|
|
|
|
current->flags = (flags & SDL_FULLSCREEN) | (flags & SDL_OPENGL) | SDL_DOUBLEBUF | (flags & SDL_HWSURFACE);
|
|
current->w = width;
|
|
current->h = height;
|
|
current->pitch = SDL_ANDROID_sFakeWindowWidth * SDL_ANDROID_BYTESPERPIXEL;
|
|
current->pixels = NULL;
|
|
current->hwdata = NULL;
|
|
|
|
HwSurfaceCount = 0;
|
|
HwSurfaceList = NULL;
|
|
DEBUGOUT("ANDROID_SetVideoMode() HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
|
|
if( ! sdl_opengl )
|
|
{
|
|
SDL_DisplayMode mode;
|
|
SDL_RendererInfo SDL_VideoRendererInfo;
|
|
SDL_Rect window;
|
|
|
|
SDL_ANDROID_sWindowWidth = SDL_ANDROID_sRealWindowWidth;
|
|
SDL_ANDROID_sWindowHeight = SDL_ANDROID_sRealWindowHeight;
|
|
|
|
SDL_ANDROID_ForceClearScreenRectAmount = 0;
|
|
if( SDL_ANDROID_ScreenKeep43Ratio )
|
|
{
|
|
if( (float)width / (float)height < (float)SDL_ANDROID_sWindowWidth / (float)SDL_ANDROID_sWindowHeight )
|
|
SDL_ANDROID_sWindowWidth = (SDL_ANDROID_sFakeWindowWidth * SDL_ANDROID_sRealWindowHeight) / SDL_ANDROID_sFakeWindowHeight;
|
|
else
|
|
// Force 4:3 ratio, with black borders at the left/right,
|
|
// this is needede for Uae4all2, which has 640x256 video mode,
|
|
// and expects those 256 pixels to stretch 2x height like on a TV interlaced display.
|
|
SDL_ANDROID_sWindowWidth = SDL_ANDROID_sWindowHeight * 4 / 3;
|
|
|
|
SDL_ANDROID_TouchscreenCalibrationWidth = SDL_ANDROID_sWindowWidth;
|
|
SDL_ANDROID_ForceClearScreenRectAmount = 2;
|
|
}
|
|
|
|
window.x = (SDL_ANDROID_sRealWindowWidth - SDL_ANDROID_sWindowWidth) / 2;
|
|
window.y = 0;
|
|
window.w = width;
|
|
window.h = height;
|
|
|
|
SDL_ANDROID_ForceClearScreenRect[0].x = 0;
|
|
SDL_ANDROID_ForceClearScreenRect[0].y = 0;
|
|
SDL_ANDROID_ForceClearScreenRect[0].w = window.x;
|
|
SDL_ANDROID_ForceClearScreenRect[0].h = SDL_ANDROID_sRealWindowHeight;
|
|
SDL_ANDROID_ForceClearScreenRect[1].x = SDL_ANDROID_sRealWindowWidth - window.x;
|
|
SDL_ANDROID_ForceClearScreenRect[1].y = 0;
|
|
SDL_ANDROID_ForceClearScreenRect[1].w = window.x;
|
|
SDL_ANDROID_ForceClearScreenRect[1].h = SDL_ANDROID_sRealWindowHeight;
|
|
SDL_ANDROID_ForceClearScreenRect[2].x = window.x;
|
|
SDL_ANDROID_ForceClearScreenRect[2].y = 0;
|
|
SDL_ANDROID_ForceClearScreenRect[2].w = SDL_ANDROID_sRealWindowWidth - window.x * 2;
|
|
SDL_ANDROID_ForceClearScreenRect[2].h = window.y;
|
|
SDL_ANDROID_ForceClearScreenRect[3].x = window.x;
|
|
SDL_ANDROID_ForceClearScreenRect[3].y = SDL_ANDROID_sRealWindowHeight - window.y;
|
|
SDL_ANDROID_ForceClearScreenRect[3].w = SDL_ANDROID_sRealWindowWidth - window.x * 2;
|
|
SDL_ANDROID_ForceClearScreenRect[3].h = window.y;
|
|
|
|
SDL_SelectVideoDisplay(0);
|
|
if (SDL_VideoWindow)
|
|
SDL_DestroyWindow(SDL_VideoWindow);
|
|
SDL_VideoWindow = SDL_CreateWindow("", window.x, window.y, window.w, window.h, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_OPENGL);
|
|
|
|
SDL_memset(&mode, 0, sizeof(mode));
|
|
mode.format = PixelFormatEnum;
|
|
SDL_SetWindowDisplayMode(SDL_VideoWindow, &mode);
|
|
|
|
if (SDL_CreateRenderer(SDL_VideoWindow, -1, 0) < 0) {
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_SetVideoMode(): Error creating renderer");
|
|
return NULL;
|
|
}
|
|
SDL_GetRendererInfo(&SDL_VideoRendererInfo);
|
|
|
|
current->hwdata = NULL;
|
|
if( ! (flags & SDL_HWSURFACE) )
|
|
{
|
|
current->pixels = SDL_malloc(width * height * SDL_ANDROID_BYTESPERPIXEL);
|
|
if ( ! current->pixels ) {
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Couldn't allocate buffer for requested mode");
|
|
SDL_SetError("Couldn't allocate buffer for requested mode");
|
|
return(NULL);
|
|
}
|
|
SDL_memset(current->pixels, 0, width * height * SDL_ANDROID_BYTESPERPIXEL);
|
|
current->hwdata = (struct private_hwdata *)SDL_CreateTexture(PixelFormatEnum, SDL_TEXTUREACCESS_STATIC, width, height);
|
|
if( !current->hwdata ) {
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Couldn't allocate texture for SDL_CurrentVideoSurface");
|
|
SDL_free(current->pixels);
|
|
current->pixels = NULL;
|
|
SDL_OutOfMemory();
|
|
return(NULL);
|
|
}
|
|
if( SDL_ANDROID_VideoLinearFilter )
|
|
SDL_SetTextureScaleMode((SDL_Texture *)current->hwdata, SDL_SCALEMODE_SLOW);
|
|
|
|
// Register main video texture to be recreated when needed
|
|
HwSurfaceCount++;
|
|
HwSurfaceList = SDL_realloc( HwSurfaceList, HwSurfaceCount * sizeof(SDL_Surface *) );
|
|
HwSurfaceList[HwSurfaceCount-1] = current;
|
|
DEBUGOUT("ANDROID_SetVideoMode() HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
}
|
|
glViewport(0, 0, SDL_ANDROID_sRealWindowWidth, SDL_ANDROID_sRealWindowHeight);
|
|
glOrthof(0, SDL_ANDROID_sRealWindowWidth, SDL_ANDROID_sRealWindowHeight, 0, 0, 1);
|
|
}
|
|
|
|
/* Allocate the new pixel format for the screen */
|
|
SDL_memset(&format, 0, sizeof(format));
|
|
SDL_PixelFormatEnumToMasks( PixelFormatEnum, &bpp1,
|
|
&format.Rmask, &format.Gmask,
|
|
&format.Bmask, &format.Amask );
|
|
format.BitsPerPixel = bpp1;
|
|
format.BytesPerPixel = SDL_ANDROID_BYTESPERPIXEL;
|
|
|
|
if ( ! SDL_ReallocFormat(current, SDL_ANDROID_BITSPERPIXEL, format.Rmask, format.Gmask, format.Bmask, format.Amask) ) {
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Couldn't allocate new pixel format for requested mode");
|
|
SDL_SetError("Couldn't allocate new pixel format for requested mode");
|
|
return(NULL);
|
|
}
|
|
|
|
/* Set up the new mode framebuffer */
|
|
SDL_CurrentVideoSurface = current;
|
|
|
|
UpdateScreenUnderFingerRect(0,0);
|
|
SDL_ANDROID_ShowScreenUnderFingerRect.w = SDL_ANDROID_ShowScreenUnderFingerRect.h = 0;
|
|
SDL_ANDROID_SetHoverDeadzone();
|
|
SDL_ANDROID_currentMouseX = SDL_ANDROID_sFakeWindowWidth / 2;
|
|
SDL_ANDROID_currentMouseY = SDL_ANDROID_sFakeWindowHeight / 2;
|
|
|
|
/* We're done */
|
|
return(current);
|
|
}
|
|
|
|
/* Note: If we are terminated, this could be called in the middle of
|
|
another SDL video routine -- notably UpdateRects.
|
|
*/
|
|
void ANDROID_VideoQuit(_THIS)
|
|
{
|
|
// TODO: this function crashes SDL
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Calling VideoQuit()");
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
}
|
|
|
|
if( ! sdl_opengl )
|
|
{
|
|
DEBUGOUT("ANDROID_VideoQuit() in HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
HwSurfaceCount = 0;
|
|
if(HwSurfaceList)
|
|
SDL_free(HwSurfaceList);
|
|
HwSurfaceList = NULL;
|
|
DEBUGOUT("ANDROID_VideoQuit() out HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
|
|
if( SDL_CurrentVideoSurface )
|
|
{
|
|
if( SDL_CurrentVideoSurface->hwdata )
|
|
SDL_DestroyTexture((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata);
|
|
if( SDL_CurrentVideoSurface->pixels )
|
|
SDL_free(SDL_CurrentVideoSurface->pixels);
|
|
SDL_CurrentVideoSurface->pixels = NULL;
|
|
}
|
|
SDL_CurrentVideoSurface = NULL;
|
|
if(SDL_VideoWindow)
|
|
SDL_DestroyWindow(SDL_VideoWindow);
|
|
SDL_VideoWindow = NULL;
|
|
}
|
|
|
|
SDL_ANDROID_sFakeWindowWidth = 0;
|
|
SDL_ANDROID_sFakeWindowWidth = 0;
|
|
|
|
int i;
|
|
|
|
/* Free video mode lists */
|
|
for ( i=0; i<SDL_NUMMODES; ++i ) {
|
|
if ( SDL_modelist[i] != NULL ) {
|
|
SDL_free(SDL_modelist[i]);
|
|
SDL_modelist[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ANDROID_PumpEvents(_THIS)
|
|
{
|
|
SDL_ANDROID_PumpEvents();
|
|
}
|
|
|
|
static int ANDROID_AllocHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if ( ! (surface->w && surface->h) )
|
|
return -1;
|
|
|
|
if( SDL_ANDROID_VideoForceSoftwareMode )
|
|
{
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_SetVideoMode(): ignoring application attempt to allocate HW surface");
|
|
return -1;
|
|
}
|
|
|
|
DEBUGOUT("ANDROID_AllocHWSurface() surface %p w %d h %d", surface, surface->w, surface->h);
|
|
Uint32 format = PixelFormatEnumColorkey; // 1-bit alpha for color key, every surface will have colorkey so it's easier for us
|
|
if( surface->format->Amask )
|
|
{
|
|
SDL_PixelFormat format1;
|
|
int bpp;
|
|
format = PixelFormatEnumAlpha;
|
|
SDL_memset(&format1, 0, sizeof(format1));
|
|
SDL_PixelFormatEnumToMasks( format, &bpp,
|
|
&format1.Rmask, &format1.Gmask,
|
|
&format1.Bmask, &format1.Amask );
|
|
if( surface->format->BitsPerPixel != bpp ||
|
|
surface->format->Rmask != format1.Rmask ||
|
|
surface->format->Gmask != format1.Gmask ||
|
|
surface->format->Bmask != format1.Bmask ||
|
|
surface->format->Amask != format1.Amask )
|
|
return(-1); // Do not allow alpha-surfaces with format other than RGBA4444 (it will be pain to lock/copy them)
|
|
}
|
|
else
|
|
{
|
|
// HW-accel surface should be RGB565
|
|
if( !( SDL_CurrentVideoSurface->format->BitsPerPixel == surface->format->BitsPerPixel &&
|
|
SDL_CurrentVideoSurface->format->Rmask == surface->format->Rmask &&
|
|
SDL_CurrentVideoSurface->format->Gmask == surface->format->Gmask &&
|
|
SDL_CurrentVideoSurface->format->Bmask == surface->format->Bmask &&
|
|
SDL_CurrentVideoSurface->format->Amask == surface->format->Amask ) )
|
|
return(-1);
|
|
}
|
|
|
|
surface->pitch = surface->w * surface->format->BytesPerPixel;
|
|
surface->pixels = SDL_malloc(surface->h * surface->w * surface->format->BytesPerPixel);
|
|
if ( surface->pixels == NULL ) {
|
|
SDL_OutOfMemory();
|
|
return(-1);
|
|
}
|
|
SDL_memset(surface->pixels, 0, surface->h*surface->pitch);
|
|
|
|
surface->hwdata = (struct private_hwdata *)SDL_CreateTexture(format, SDL_TEXTUREACCESS_STATIC, surface->w, surface->h);
|
|
if( !surface->hwdata ) {
|
|
SDL_free(surface->pixels);
|
|
surface->pixels = NULL;
|
|
SDL_OutOfMemory();
|
|
return(-1);
|
|
}
|
|
|
|
if( SDL_ANDROID_VideoLinearFilter )
|
|
SDL_SetTextureScaleMode((SDL_Texture *)surface->hwdata, SDL_SCALEMODE_SLOW);
|
|
|
|
if( surface->format->Amask )
|
|
{
|
|
SDL_SetTextureAlphaMod((struct SDL_Texture *)surface->hwdata, SDL_ALPHA_OPAQUE);
|
|
SDL_SetTextureBlendMode((struct SDL_Texture *)surface->hwdata, SDL_BLENDMODE_BLEND);
|
|
}
|
|
|
|
surface->flags |= SDL_HWSURFACE | SDL_HWACCEL;
|
|
|
|
HwSurfaceCount++;
|
|
DEBUGOUT("ANDROID_AllocHWSurface() in HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
HwSurfaceList = SDL_realloc( HwSurfaceList, HwSurfaceCount * sizeof(SDL_Surface *) );
|
|
DEBUGOUT("ANDROID_AllocHWSurface() out HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
|
|
HwSurfaceList[HwSurfaceCount-1] = surface;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ANDROID_FreeHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
int i;
|
|
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
if( !surface->hwdata )
|
|
return;
|
|
SDL_DestroyTexture((struct SDL_Texture *)surface->hwdata);
|
|
|
|
DEBUGOUT("ANDROID_FreeHWSurface() surface %p w %d h %d in HwSurfaceCount %d HwSurfaceList %p", surface, surface->w, surface->h, HwSurfaceCount, HwSurfaceList);
|
|
|
|
for( i = 0; i < HwSurfaceCount; i++ )
|
|
{
|
|
if( HwSurfaceList[i] == surface )
|
|
{
|
|
HwSurfaceCount--;
|
|
memmove(HwSurfaceList + i, HwSurfaceList + i + 1, sizeof(SDL_Surface *) * (HwSurfaceCount - i) );
|
|
HwSurfaceList = SDL_realloc( HwSurfaceList, HwSurfaceCount * sizeof(SDL_Surface *) );
|
|
i = -1;
|
|
DEBUGOUT("ANDROID_FreeHWSurface() in HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
break;
|
|
}
|
|
}
|
|
if( i != -1 )
|
|
SDL_SetError("ANDROID_FreeHWSurface: cannot find freed HW surface in HwSurfaceList array");
|
|
}
|
|
|
|
static int ANDROID_LockHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if( surface == SDL_CurrentVideoSurface )
|
|
{
|
|
// Copy pixels from pixelbuffer to video surface - this is slow!
|
|
Uint16 * row = NULL;
|
|
int fakeH = SDL_ANDROID_sFakeWindowHeight, fakeW = SDL_ANDROID_sFakeWindowWidth;
|
|
int realH = SDL_ANDROID_sWindowHeight, realW = SDL_ANDROID_sWindowWidth;
|
|
int x, y;
|
|
if( ! SDL_CurrentVideoSurface->pixels )
|
|
{
|
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
SDL_CurrentVideoSurface->pixels = SDL_malloc(SDL_ANDROID_sFakeWindowWidth * SDL_ANDROID_sFakeWindowHeight * SDL_ANDROID_BYTESPERPIXEL);
|
|
if ( ! SDL_CurrentVideoSurface->pixels ) {
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Couldn't allocate buffer for SDL_CurrentVideoSurface");
|
|
SDL_SetError("Couldn't allocate buffer for SDL_CurrentVideoSurface");
|
|
return(-1);
|
|
}
|
|
}
|
|
if( ! SDL_CurrentVideoSurface->hwdata )
|
|
{
|
|
SDL_CurrentVideoSurface->hwdata = (struct private_hwdata *)SDL_CreateTexture(PixelFormatEnum, SDL_TEXTUREACCESS_STATIC, SDL_ANDROID_sFakeWindowWidth, SDL_ANDROID_sFakeWindowHeight);
|
|
if( !SDL_CurrentVideoSurface->hwdata ) {
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Couldn't allocate texture for SDL_CurrentVideoSurface");
|
|
SDL_OutOfMemory();
|
|
return(-1);
|
|
}
|
|
if( SDL_ANDROID_VideoLinearFilter )
|
|
SDL_SetTextureScaleMode((SDL_Texture *)SDL_CurrentVideoSurface->hwdata, SDL_SCALEMODE_SLOW);
|
|
// Register main video texture to be recreated when needed
|
|
HwSurfaceCount++;
|
|
HwSurfaceList = SDL_realloc( HwSurfaceList, HwSurfaceCount * sizeof(SDL_Surface *) );
|
|
HwSurfaceList[HwSurfaceCount-1] = SDL_CurrentVideoSurface;
|
|
DEBUGOUT("ANDROID_SetVideoMode() HwSurfaceCount %d HwSurfaceList %p", HwSurfaceCount, HwSurfaceList);
|
|
}
|
|
|
|
row = SDL_stack_alloc(Uint16, SDL_ANDROID_sWindowWidth);
|
|
|
|
for(y=0; y<fakeH; y++)
|
|
{
|
|
// TODO: support 24bpp and 32bpp
|
|
glReadPixels(0, realH - 1 - (realH * y / fakeH),
|
|
realW, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, row);
|
|
for(x=0; x<fakeW; x++)
|
|
((Uint16 *)SDL_CurrentVideoSurface->pixels)[ fakeW * y + x ] = row[ x * fakeW / realW ];
|
|
}
|
|
|
|
SDL_stack_free(row);
|
|
}
|
|
|
|
if( !surface->hwdata )
|
|
return(-1);
|
|
|
|
// Extra check not necessary
|
|
/*
|
|
if( SDL_CurrentVideoSurface->format->BitsPerPixel == surface->format->BitsPerPixel &&
|
|
SDL_CurrentVideoSurface->format->Rmask == surface->format->Rmask &&
|
|
SDL_CurrentVideoSurface->format->Gmask == surface->format->Gmask &&
|
|
SDL_CurrentVideoSurface->format->Bmask == surface->format->Bmask &&
|
|
SDL_CurrentVideoSurface->format->Amask == surface->format->Amask )
|
|
return(0);
|
|
|
|
if( this->displayformatalphapixel->BitsPerPixel == surface->format->BitsPerPixel &&
|
|
this->displayformatalphapixel->Rmask == surface->format->Rmask &&
|
|
this->displayformatalphapixel->Gmask == surface->format->Gmask &&
|
|
this->displayformatalphapixel->Bmask == surface->format->Bmask &&
|
|
this->displayformatalphapixel->Amask == surface->format->Amask )
|
|
return(0);
|
|
return(-1);
|
|
*/
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void ANDROID_UnlockHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
SDL_PixelFormat format;
|
|
Uint32 hwformat = PixelFormatEnumColorkey;
|
|
int bpp;
|
|
SDL_Surface * converted = NULL;
|
|
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
if( !surface->hwdata )
|
|
return;
|
|
|
|
if( surface->format->Amask )
|
|
hwformat = PixelFormatEnumAlpha;
|
|
|
|
if( surface == SDL_CurrentVideoSurface ) // Special case
|
|
hwformat = PixelFormatEnum;
|
|
|
|
/* Allocate the new pixel format for the screen */
|
|
SDL_memset(&format, 0, sizeof(format));
|
|
SDL_PixelFormatEnumToMasks( hwformat, &bpp,
|
|
&format.Rmask, &format.Gmask,
|
|
&format.Bmask, &format.Amask );
|
|
format.BytesPerPixel = SDL_ANDROID_BYTESPERPIXEL;
|
|
format.BitsPerPixel = bpp;
|
|
|
|
// TODO: support 24bpp and 32bpp
|
|
if( format.BitsPerPixel == surface->format->BitsPerPixel &&
|
|
format.Rmask == surface->format->Rmask &&
|
|
format.Gmask == surface->format->Gmask &&
|
|
format.Bmask == surface->format->Bmask &&
|
|
format.Amask == surface->format->Amask )
|
|
{
|
|
converted = surface; // No need for conversion
|
|
}
|
|
else
|
|
{
|
|
Uint16 x, y;
|
|
|
|
converted = SDL_CreateRGBSurface(SDL_SWSURFACE, surface->w, surface->h, format.BitsPerPixel,
|
|
format.Rmask, format.Gmask, format.Bmask, format.Amask);
|
|
if( !converted ) {
|
|
SDL_OutOfMemory();
|
|
return;
|
|
}
|
|
|
|
#define CONVERT_RGB565_RGBA5551( pixel ) (0x1 | ( (pixel & 0xFFC0) | ( (pixel & 0x1F) << 1 ) ))
|
|
|
|
if( surface->flags & SDL_SRCCOLORKEY )
|
|
{
|
|
DEBUGOUT("ANDROID_UnlockHWSurface() CONVERT_RGB565_RGBA5551 + colorkey");
|
|
for( y = 0; y < surface->h; y++ )
|
|
{
|
|
Uint16* src = (Uint16 *)( surface->pixels + surface->pitch * y );
|
|
Uint16* dst = (Uint16 *)( converted->pixels + converted->pitch * y );
|
|
Uint16 w = surface->w;
|
|
Uint16 key = surface->format->colorkey;
|
|
Uint16 pixel;
|
|
for( x = 0; x < w; x++, src++, dst++ )
|
|
{
|
|
pixel = *src;
|
|
*dst = (pixel == key) ? 0 : CONVERT_RGB565_RGBA5551( pixel );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUGOUT("ANDROID_UnlockHWSurface() CONVERT_RGB565_RGBA5551");
|
|
for( y = 0; y < surface->h; y++ )
|
|
{
|
|
Uint16* src = (Uint16 *)( surface->pixels + surface->pitch * y );
|
|
Uint16* dst = (Uint16 *)( converted->pixels + converted->pitch * y );
|
|
Uint16 w = surface->w;
|
|
Uint16 pixel;
|
|
for( x = 0; x < w; x++, src++, dst++ )
|
|
{
|
|
pixel = *src;
|
|
*dst = CONVERT_RGB565_RGBA5551( pixel );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_Rect rect;
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.w = surface->w;
|
|
rect.h = surface->h;
|
|
SDL_UpdateTexture((struct SDL_Texture *)surface->hwdata, &rect, converted->pixels, converted->pitch);
|
|
|
|
if( surface == SDL_CurrentVideoSurface ) // Special case
|
|
SDL_RenderCopy((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata, NULL, NULL);
|
|
|
|
if( converted != surface )
|
|
SDL_FreeSurface(converted);
|
|
}
|
|
|
|
// We're only blitting HW surface to screen, no other options provided (and if you need them your app designed wrong)
|
|
int ANDROID_HWBlit(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect)
|
|
{
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if( dst != SDL_CurrentVideoSurface || (! src->hwdata) )
|
|
{
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROID_HWBlit(): blitting SW");
|
|
return(src->map->sw_blit(src, srcrect, dst, dstrect));
|
|
}
|
|
if( src == SDL_CurrentVideoSurface )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROID_HWBlit(): reading from screen surface not supported");
|
|
return(-1);
|
|
}
|
|
|
|
return SDL_RenderCopy((struct SDL_Texture *)src->hwdata, srcrect, dstrect);
|
|
};
|
|
|
|
static int ANDROID_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst)
|
|
{
|
|
// This part is ignored by SDL (though it should not be)
|
|
/*
|
|
if( dst != SDL_CurrentVideoSurface || ! src->hwdata )
|
|
return(-1);
|
|
*/
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROID_CheckHWBlit()");
|
|
src->map->hw_blit = ANDROID_HWBlit;
|
|
src->flags |= SDL_HWACCEL;
|
|
return(0);
|
|
};
|
|
|
|
static int ANDROID_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
|
|
{
|
|
Uint8 r, g, b, a;
|
|
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if( dst != SDL_CurrentVideoSurface )
|
|
{
|
|
// TODO: hack
|
|
current_video->info.blit_fill = 0;
|
|
SDL_FillRect( dst, rect, color );
|
|
current_video->info.blit_fill = 1;
|
|
return(0);
|
|
}
|
|
SDL_GetRGBA(color, dst->format, &r, &g, &b, &a);
|
|
SDL_SetRenderDrawColor( r, g, b, a );
|
|
return SDL_RenderFillRect(rect);
|
|
};
|
|
|
|
static int ANDROID_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
|
|
{
|
|
SDL_PixelFormat format;
|
|
SDL_Surface * converted = NULL;
|
|
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if( !surface->hwdata )
|
|
return(-1);
|
|
if( surface->format->Amask )
|
|
return(-1);
|
|
|
|
surface->flags |= SDL_SRCCOLORKEY;
|
|
|
|
ANDROID_UnlockHWSurface(this, surface); // Convert surface using colorkey
|
|
|
|
SDL_SetTextureBlendMode((struct SDL_Texture *)surface->hwdata, SDL_BLENDMODE_BLEND);
|
|
|
|
return 0;
|
|
};
|
|
|
|
static int ANDROID_SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 value)
|
|
{
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if( !surface->hwdata )
|
|
return(-1);
|
|
|
|
surface->flags |= SDL_SRCALPHA;
|
|
|
|
if( value == SDL_ALPHA_OPAQUE && ! (surface->flags & SDL_SRCCOLORKEY) )
|
|
SDL_SetTextureBlendMode((struct SDL_Texture *)surface->hwdata, SDL_BLENDMODE_NONE);
|
|
else
|
|
SDL_SetTextureBlendMode((struct SDL_Texture *)surface->hwdata, SDL_BLENDMODE_BLEND);
|
|
|
|
return SDL_SetTextureAlphaMod((struct SDL_Texture *)surface->hwdata, value);
|
|
};
|
|
|
|
static void ANDROID_FlipHWSurfaceInternal(int numrects, SDL_Rect *rects)
|
|
{
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROID_FlipHWSurface()");
|
|
if( SDL_CurrentVideoSurface->hwdata && SDL_CurrentVideoSurface->pixels && ! ( SDL_CurrentVideoSurface->flags & SDL_HWSURFACE ) )
|
|
{
|
|
SDL_Rect rect;
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.w = SDL_CurrentVideoSurface->w;
|
|
rect.h = SDL_CurrentVideoSurface->h;
|
|
if(numrects == 0)
|
|
SDL_UpdateTexture((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata, &rect, SDL_CurrentVideoSurface->pixels, SDL_CurrentVideoSurface->pitch);
|
|
else
|
|
{
|
|
int i;
|
|
for(i = 0; i < numrects; i++)
|
|
{
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_UpdateTexture: rect %d: %04d:%04d:%04d:%04d", i, rects[i].x, rects[i].y, rects[i].w, rects[i].h);
|
|
SDL_UpdateTexture((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata, &rects[i],
|
|
SDL_CurrentVideoSurface->pixels + rects[i].y * SDL_CurrentVideoSurface->pitch +
|
|
rects[i].x * SDL_CurrentVideoSurface->format->BytesPerPixel,
|
|
SDL_CurrentVideoSurface->pitch);
|
|
}
|
|
}
|
|
|
|
if( !SDL_ANDROID_SystemBarAndKeyboardShown )
|
|
SDL_RenderCopy((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata, &rect, &rect);
|
|
else
|
|
{
|
|
int x, y;
|
|
SDL_Rect dstrect;
|
|
SDL_GetMouseState(&x, &y); // Follow mouse pointer location
|
|
rect.w = SDL_ANDROID_ScreenVisibleRect.w * SDL_ANDROID_sFakeWindowWidth / SDL_ANDROID_sRealWindowWidth;
|
|
rect.h = SDL_ANDROID_ScreenVisibleRect.h * SDL_ANDROID_sFakeWindowHeight / SDL_ANDROID_sRealWindowHeight;
|
|
rect.x = x - rect.w / 2;
|
|
if( rect.x < 0 )
|
|
rect.x = 0;
|
|
if( rect.x + rect.w > SDL_ANDROID_sFakeWindowWidth )
|
|
rect.x = SDL_ANDROID_sFakeWindowWidth - rect.w;
|
|
rect.y = y - rect.h / 2;
|
|
if( rect.y < 0 )
|
|
rect.y = 0;
|
|
if( rect.y + rect.h > SDL_ANDROID_sFakeWindowHeight )
|
|
rect.y = SDL_ANDROID_sFakeWindowHeight - rect.h;
|
|
dstrect.w = rect.w;
|
|
dstrect.h = rect.h;
|
|
dstrect.x = SDL_ANDROID_ScreenVisibleRect.x * SDL_ANDROID_sFakeWindowWidth / SDL_ANDROID_sRealWindowWidth;
|
|
dstrect.y = SDL_ANDROID_ScreenVisibleRect.y * SDL_ANDROID_sFakeWindowHeight / SDL_ANDROID_sRealWindowHeight;
|
|
//__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Flip: %04d:%04d:%04d:%04d -> %04d:%04d:%04d:%04d vis %04d:%04d:%04d:%04d", rect.x, rect.y, rect.w, rect.h, dstrect.x, dstrect.y, dstrect.w, dstrect.h, SDL_ANDROID_ScreenVisibleRect.x, SDL_ANDROID_ScreenVisibleRect.y, SDL_ANDROID_ScreenVisibleRect.w, SDL_ANDROID_ScreenVisibleRect.h);
|
|
SDL_RenderCopy((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata, &rect, &dstrect);
|
|
}
|
|
|
|
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_MAGNIFIER )
|
|
{
|
|
SDL_Rect dstrect = SDL_ANDROID_ShowScreenUnderFingerRect;
|
|
rect = SDL_ANDROID_ShowScreenUnderFingerRectSrc;
|
|
SDL_RenderCopy((struct SDL_Texture *)SDL_CurrentVideoSurface->hwdata, &rect, &dstrect);
|
|
int buttons = SDL_GetMouseState(NULL, NULL);
|
|
// Do it old-fashioned way with direct GL calls
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrthof( 0.0f, SDL_ANDROID_sFakeWindowWidth, SDL_ANDROID_sFakeWindowHeight, 0.0f, 0.0f, 1.0f );
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glColor4f(0.0f, buttons & SDL_BUTTON_RMASK ? 1.0f : 0.0f, buttons & SDL_BUTTON_LMASK ? 1.0f : 0.0f, 1.0f);
|
|
GLshort vertices[] = { dstrect.x, dstrect.y,
|
|
dstrect.x + dstrect.w, dstrect.y,
|
|
dstrect.x + dstrect.w, dstrect.y + dstrect.h,
|
|
dstrect.x, dstrect.y + dstrect.h };
|
|
glVertexPointer(2, GL_SHORT, 0, vertices);
|
|
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glPopMatrix();
|
|
}
|
|
#ifdef VIDEO_DEBUG
|
|
if( SDL_ANDROID_VideoDebugRect.w > 0 )
|
|
{
|
|
SDL_Rect frame = SDL_ANDROID_VideoDebugRect;
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrthof( 0.0f, SDL_ANDROID_sFakeWindowWidth, SDL_ANDROID_sFakeWindowHeight, 0.0f, 0.0f, 1.0f );
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glColor4f(SDL_ANDROID_VideoDebugRectColor.r / 255.0f, SDL_ANDROID_VideoDebugRectColor.g / 255.0f, SDL_ANDROID_VideoDebugRectColor.b / 255.0f, 1.0f);
|
|
GLshort vertices[] = { frame.x, frame.y,
|
|
frame.x + frame.w, frame.y,
|
|
frame.x + frame.w, frame.y + frame.h,
|
|
frame.x, frame.y + frame.h };
|
|
glVertexPointer(2, GL_SHORT, 0, vertices);
|
|
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glPopMatrix();
|
|
}
|
|
#endif
|
|
if(SDL_ANDROID_ShowMouseCursor)
|
|
{
|
|
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_NONE || SDL_ANDROID_ShowScreenUnderFinger == ZOOM_MAGNIFIER )
|
|
{
|
|
int x, y;
|
|
SDL_GetMouseState(&x, &y);
|
|
x = x * SDL_ANDROID_sRealWindowWidth / SDL_ANDROID_sFakeWindowWidth;
|
|
y = y * SDL_ANDROID_sRealWindowHeight / SDL_ANDROID_sFakeWindowHeight;
|
|
SDL_ANDROID_DrawMouseCursor( x, y, 0, 1.0f );
|
|
}
|
|
if( SDL_ANDROID_ShowScreenUnderFinger != ZOOM_NONE &&
|
|
SDL_ANDROID_ShowScreenUnderFingerRectSrc.w > 0 &&
|
|
SDL_ANDROID_ShowScreenUnderFingerRectSrc.h > 0 )
|
|
{
|
|
int x, y;
|
|
SDL_GetMouseState(&x, &y);
|
|
x = SDL_ANDROID_ShowScreenUnderFingerRect.x +
|
|
( x - SDL_ANDROID_ShowScreenUnderFingerRectSrc.x ) *
|
|
SDL_ANDROID_ShowScreenUnderFingerRect.w / SDL_ANDROID_ShowScreenUnderFingerRectSrc.w;
|
|
y = SDL_ANDROID_ShowScreenUnderFingerRect.y +
|
|
( y - SDL_ANDROID_ShowScreenUnderFingerRectSrc.y ) *
|
|
SDL_ANDROID_ShowScreenUnderFingerRect.h / SDL_ANDROID_ShowScreenUnderFingerRectSrc.h;
|
|
x = x * SDL_ANDROID_sRealWindowWidth / SDL_ANDROID_sFakeWindowWidth;
|
|
y = y * SDL_ANDROID_sRealWindowHeight / SDL_ANDROID_sFakeWindowHeight;
|
|
SDL_ANDROID_DrawMouseCursor( x, y, 16, 1.0f );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
static int ANDROID_FlipHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if(!SDL_CurrentVideoSurface)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s without main video surface!", __PRETTY_FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
ANDROID_FlipHWSurfaceInternal(0, NULL);
|
|
|
|
SDL_ANDROID_CallJavaSwapBuffers();
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void ANDROID_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
|
|
{
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
if(!SDL_CurrentVideoSurface)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s without main video surface!", __PRETTY_FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
#ifdef SDL_COMPATIBILITY_HACKS_PROPER_USADE_OF_SDL_UPDATERECTS
|
|
ANDROID_FlipHWSurfaceInternal(numrects, rects); // Fails for fheroes2, I'll add a compatibility option later.
|
|
#else
|
|
ANDROID_FlipHWSurfaceInternal(0, NULL);
|
|
#endif
|
|
|
|
SDL_ANDROID_CallJavaSwapBuffers();
|
|
}
|
|
|
|
void ANDROID_GL_SwapBuffers(_THIS)
|
|
{
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROID_GL_SwapBuffers");
|
|
// TeeWorlds use hacky hack to draw from separate thread, however it works surprisingly well
|
|
/*
|
|
if( !SDL_ANDROID_InsideVideoThread() )
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Error: calling %s not from the main thread!", __PRETTY_FUNCTION__);
|
|
return;
|
|
}
|
|
*/
|
|
|
|
SDL_ANDROID_CallJavaSwapBuffers();
|
|
};
|
|
|
|
int ANDROID_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
void SDL_ANDROID_VideoContextLost()
|
|
{
|
|
if( ! sdl_opengl )
|
|
{
|
|
int i;
|
|
for( i = 0; i < HwSurfaceCount; i++ )
|
|
{
|
|
SDL_DestroyTexture((struct SDL_Texture *)HwSurfaceList[i]->hwdata);
|
|
HwSurfaceList[i]->hwdata = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
extern DECLSPEC int SDL_ANDROID_ScreenKeyboardUpdateToNewVideoMode(int oldx, int oldy, int newx, int newy);
|
|
|
|
void SDL_ANDROID_VideoContextRecreated()
|
|
{
|
|
int i;
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Sending SDL_VIDEORESIZE event %dx%d", SDL_ANDROID_sFakeWindowWidth, SDL_ANDROID_sFakeWindowHeight);
|
|
//SDL_PrivateResize(SDL_ANDROID_sFakeWindowWidth, SDL_ANDROID_sFakeWindowHeight);
|
|
if ( SDL_ProcessEvents[SDL_VIDEORESIZE] == SDL_ENABLE ) {
|
|
SDL_Event event;
|
|
event.type = SDL_VIDEORESIZE;
|
|
event.resize.w = SDL_ANDROID_sFakeWindowWidth;
|
|
event.resize.h = SDL_ANDROID_sFakeWindowHeight;
|
|
if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) {
|
|
SDL_PushEvent(&event);
|
|
}
|
|
}
|
|
|
|
SDL_ANDROID_ScreenKeyboardUpdateToNewVideoMode(SDL_modelist[0]->w, SDL_modelist[0]->h, SDL_ANDROID_sWindowWidth, SDL_ANDROID_sWindowHeight);
|
|
|
|
SDL_modelist[0]->w = SDL_ANDROID_sWindowWidth;
|
|
SDL_modelist[0]->h = SDL_ANDROID_sWindowHeight;
|
|
|
|
if( ! sdl_opengl )
|
|
{
|
|
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Setting display dimensions to %dx%d", SDL_ANDROID_sRealWindowWidth, SDL_ANDROID_sRealWindowHeight);
|
|
SDL_PrivateAndroidSetDesktopMode(SDL_VideoWindow, SDL_ANDROID_sRealWindowWidth, SDL_ANDROID_sRealWindowHeight);
|
|
SDL_SelectRenderer(SDL_VideoWindow); // Re-apply glOrtho() and blend modes
|
|
// Re-apply our custom 4:3 screen aspect ratio
|
|
glViewport(0, 0, SDL_ANDROID_sRealWindowWidth, SDL_ANDROID_sRealWindowHeight);
|
|
glOrthof(0, SDL_ANDROID_sRealWindowWidth, SDL_ANDROID_sWindowHeight, 0, 0, 1);
|
|
for( i = 0; i < HwSurfaceCount; i++ )
|
|
{
|
|
// Allocate HW texture
|
|
Uint32 format = PixelFormatEnumColorkey; // 1-bit alpha for color key, every surface will have colorkey so it's easier for us
|
|
int flags = HwSurfaceList[i]->flags;
|
|
if( HwSurfaceList[i]->format->Amask )
|
|
format = PixelFormatEnumAlpha;
|
|
if( HwSurfaceList[i] == SDL_CurrentVideoSurface )
|
|
format = PixelFormatEnum;
|
|
HwSurfaceList[i]->hwdata = (struct private_hwdata *)SDL_CreateTexture(format, SDL_TEXTUREACCESS_STATIC, HwSurfaceList[i]->w, HwSurfaceList[i]->h);
|
|
if( !HwSurfaceList[i]->hwdata )
|
|
{
|
|
SDL_OutOfMemory();
|
|
return;
|
|
}
|
|
if( SDL_ANDROID_VideoLinearFilter )
|
|
SDL_SetTextureScaleMode((SDL_Texture *)HwSurfaceList[i]->hwdata, SDL_SCALEMODE_SLOW);
|
|
if (flags & SDL_SRCALPHA)
|
|
{
|
|
int alpha = HwSurfaceList[i]->format->alpha;
|
|
ANDROID_SetHWAlpha(NULL, HwSurfaceList[i], alpha);
|
|
ANDROID_UnlockHWSurface(NULL, HwSurfaceList[i]); // Re-fill texture with graphics
|
|
}
|
|
else if (flags & SDL_SRCCOLORKEY)
|
|
{
|
|
int colorkey = HwSurfaceList[i]->format->colorkey;
|
|
ANDROID_SetHWColorKey(NULL, HwSurfaceList[i], colorkey);
|
|
}
|
|
else
|
|
{
|
|
ANDROID_UnlockHWSurface(NULL, HwSurfaceList[i]); // Re-fill texture with graphics
|
|
}
|
|
}
|
|
SDL_ANDROID_CallJavaSwapBuffers(); // Swap buffers once to force screen redraw
|
|
}
|
|
};
|
|
|
|
static void* ANDROID_GL_GetProcAddress(_THIS, const char *proc)
|
|
{
|
|
void * func = dlsym(glLibraryHandle, proc);
|
|
if(!func && gl2LibraryHandle)
|
|
func = dlsym(gl2LibraryHandle, proc);
|
|
__android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROID_GL_GetProcAddress(\"%s\"): %p", proc, func);
|
|
return func;
|
|
};
|
|
|
|
// Multithreaded video - this will free up some CPU time while GPU renders video inside SDL_Flip()
|
|
enum videoThreadCmd_t { CMD_INIT, CMD_SETVIDEOMODE, CMD_QUIT, CMD_UPDATERECTS, CMD_FLIP };
|
|
typedef struct
|
|
{
|
|
SDL_mutex * mutex;
|
|
SDL_cond * cond;
|
|
SDL_cond * cond2;
|
|
int execute;
|
|
int threadReady;
|
|
enum videoThreadCmd_t cmd;
|
|
SDL_VideoDevice *_this;
|
|
SDL_PixelFormat *vformat;
|
|
SDL_Surface *current;
|
|
int width;
|
|
int height;
|
|
int bpp;
|
|
Uint32 flags;
|
|
int numrects;
|
|
SDL_Rect *rects;
|
|
|
|
int retcode;
|
|
SDL_Surface * retcode2;
|
|
} videoThread_t;
|
|
static videoThread_t videoThread;
|
|
|
|
extern void SDL_ANDROID_MultiThreadedVideoLoopInit();
|
|
extern void SDL_ANDROID_MultiThreadedVideoLoop();
|
|
|
|
void SDL_ANDROID_MultiThreadedVideoLoopInit()
|
|
{
|
|
videoThread.mutex = SDL_CreateMutex();
|
|
videoThread.cond = SDL_CreateCond();
|
|
videoThread.cond2 = SDL_CreateCond();
|
|
videoThread.execute = 0;
|
|
}
|
|
|
|
void SDL_ANDROID_MultiThreadedVideoLoop()
|
|
{
|
|
int lastUpdate = SDL_GetTicks(); // For compat mode
|
|
int nextUpdateDelay = 100; // For compat mode
|
|
while(1)
|
|
{
|
|
int signalNeeded = 0;
|
|
int swapBuffersNeeded = 0;
|
|
int ret;
|
|
int currentTime;
|
|
SDL_mutexP(videoThread.mutex);
|
|
videoThread.threadReady = 1;
|
|
SDL_CondSignal(videoThread.cond2);
|
|
ret = SDL_CondWaitTimeout(videoThread.cond, videoThread.mutex, SDL_ANDROID_CompatibilityHacks ? nextUpdateDelay : 1000);
|
|
if( videoThread.execute )
|
|
{
|
|
videoThread.threadReady = 0;
|
|
switch( videoThread.cmd )
|
|
{
|
|
case CMD_INIT:
|
|
videoThread.retcode = ANDROID_VideoInit(videoThread._this, videoThread.vformat);
|
|
break;
|
|
case CMD_SETVIDEOMODE:
|
|
videoThread.retcode2 = ANDROID_SetVideoMode(videoThread._this, videoThread.current,
|
|
videoThread.width, videoThread.height, videoThread.bpp, videoThread.flags);
|
|
break;
|
|
case CMD_QUIT:
|
|
ANDROID_VideoQuit(videoThread._this);
|
|
break;
|
|
case CMD_UPDATERECTS:
|
|
if( SDL_ANDROID_CompatibilityHacks ) // DIRTY HACK for MilkyTracker - DO NOT update screen when application requests that, update 50 ms later
|
|
{
|
|
if( nextUpdateDelay >= 100 )
|
|
nextUpdateDelay = 50;
|
|
else
|
|
nextUpdateDelay = lastUpdate + 50 - (int)SDL_GetTicks();
|
|
}
|
|
else
|
|
{
|
|
ANDROID_FlipHWSurfaceInternal(videoThread.numrects, videoThread.rects);
|
|
swapBuffersNeeded = 1;
|
|
}
|
|
break;
|
|
case CMD_FLIP:
|
|
if( SDL_ANDROID_CompatibilityHacks ) // DIRTY HACK for MilkyTracker - DO NOT update screen when application requests that, update 50 ms later
|
|
{
|
|
if( nextUpdateDelay >= 100 )
|
|
nextUpdateDelay = 50;
|
|
else
|
|
nextUpdateDelay = lastUpdate + 50 - (int)SDL_GetTicks();
|
|
}
|
|
else
|
|
{
|
|
ANDROID_FlipHWSurfaceInternal(0, NULL);
|
|
swapBuffersNeeded = 1;
|
|
}
|
|
break;
|
|
}
|
|
videoThread.execute = 0;
|
|
signalNeeded = 1;
|
|
}
|
|
if( SDL_ANDROID_CompatibilityHacks && SDL_CurrentVideoSurface &&
|
|
( ret == SDL_MUTEX_TIMEDOUT || nextUpdateDelay <= 0 ) )
|
|
{
|
|
ANDROID_FlipHWSurfaceInternal(0, NULL);
|
|
swapBuffersNeeded = 1;
|
|
lastUpdate = SDL_GetTicks();
|
|
nextUpdateDelay = 100;
|
|
}
|
|
SDL_mutexV(videoThread.mutex);
|
|
if( signalNeeded )
|
|
SDL_CondSignal(videoThread.cond2);
|
|
if( swapBuffersNeeded )
|
|
{
|
|
SDL_ANDROID_CallJavaSwapBuffers();
|
|
}
|
|
}
|
|
}
|
|
|
|
int ANDROID_VideoInitMT(_THIS, SDL_PixelFormat *vformat)
|
|
{
|
|
SDL_mutexP(videoThread.mutex);
|
|
while( ! videoThread.threadReady )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
videoThread.cmd = CMD_INIT;
|
|
videoThread._this = this;
|
|
videoThread.vformat = vformat;
|
|
videoThread.execute = 1;
|
|
SDL_CondSignal(videoThread.cond);
|
|
while( videoThread.execute )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
int ret = videoThread.retcode;
|
|
SDL_mutexV(videoThread.mutex);
|
|
return ret;
|
|
}
|
|
|
|
SDL_Surface *ANDROID_SetVideoModeMT(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags)
|
|
{
|
|
if( flags & SDL_OPENGL || flags & SDL_HWSURFACE )
|
|
{
|
|
return NULL;
|
|
}
|
|
SDL_mutexP(videoThread.mutex);
|
|
while( ! videoThread.threadReady )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
videoThread.cmd = CMD_SETVIDEOMODE;
|
|
videoThread._this = this;
|
|
videoThread.current = current;
|
|
videoThread.width = width;
|
|
videoThread.height = height;
|
|
videoThread.bpp = bpp;
|
|
videoThread.flags = flags;
|
|
videoThread.execute = 1;
|
|
SDL_CondSignal(videoThread.cond);
|
|
while( videoThread.execute )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
SDL_Surface * ret = videoThread.retcode2;
|
|
SDL_mutexV(videoThread.mutex);
|
|
return ret;
|
|
}
|
|
|
|
void ANDROID_VideoQuitMT(_THIS)
|
|
{
|
|
SDL_mutexP(videoThread.mutex);
|
|
while( ! videoThread.threadReady )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
videoThread.cmd = CMD_QUIT;
|
|
videoThread._this = this;
|
|
videoThread.execute = 1;
|
|
SDL_CondSignal(videoThread.cond);
|
|
while( videoThread.execute )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
SDL_mutexV(videoThread.mutex);
|
|
}
|
|
|
|
void ANDROID_UpdateRectsMT(_THIS, int numrects, SDL_Rect *rects)
|
|
{
|
|
SDL_mutexP(videoThread.mutex);
|
|
while( ! videoThread.threadReady )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
videoThread.cmd = CMD_UPDATERECTS;
|
|
videoThread._this = this;
|
|
videoThread.numrects = numrects;
|
|
videoThread.rects = rects;
|
|
videoThread.execute = 1;
|
|
SDL_CondSignal(videoThread.cond);
|
|
while( videoThread.execute )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
SDL_mutexV(videoThread.mutex);
|
|
}
|
|
|
|
int ANDROID_FlipHWSurfaceMT(_THIS, SDL_Surface *surface)
|
|
{
|
|
SDL_mutexP(videoThread.mutex);
|
|
while( ! videoThread.threadReady )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
videoThread.cmd = CMD_FLIP;
|
|
videoThread._this = this;
|
|
videoThread.execute = 1;
|
|
SDL_CondSignal(videoThread.cond);
|
|
while( videoThread.execute )
|
|
SDL_CondWaitTimeout(videoThread.cond2, videoThread.mutex, 1000);
|
|
SDL_mutexV(videoThread.mutex);
|
|
return 0;
|
|
}
|