#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_VITA
#include "../SDL_sysvideo.h"
#include "SDL_version.h"
#include "SDL_syswm.h"
#include "SDL_loadso.h"
#include "SDL_events.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_keyboard_c.h"
#include <psp2/kernel/processmgr.h>
#include "SDL_vitavideo.h"
#include "SDL_vitatouch.h"
#include "SDL_vitakeyboard.h"
#include "SDL_vitamouse_c.h"
#include "SDL_vitaframebuffer.h"
#if defined(SDL_VIDEO_VITA_PIB)
#include "SDL_vitagles_c.h"
#elif defined(SDL_VIDEO_VITA_PVR)
#include "SDL_vitagles_pvr_c.h"
#if defined(SDL_VIDEO_VITA_PVR_OGL)
#include "SDL_vitagl_pvr_c.h"
#endif
#define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddress
#define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define VITA_GLES_DeleteContext SDL_EGL_DeleteContext
#endif
SDL_Window *Vita_Window;
static void
VITA_Destroy(SDL_VideoDevice * device)
{
SDL_free(device->driverdata);
SDL_free(device);
}
static SDL_VideoDevice *
VITA_Create()
{
SDL_VideoDevice *device;
SDL_VideoData *phdata;
#if SDL_VIDEO_VITA_PIB
SDL_GLDriverData *gldata;
#endif
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
return NULL;
}
phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
if (phdata == NULL) {
SDL_OutOfMemory();
SDL_free(device);
return NULL;
}
#if SDL_VIDEO_VITA_PIB
gldata = (SDL_GLDriverData *) SDL_calloc(1, sizeof(SDL_GLDriverData));
if (gldata == NULL) {
SDL_OutOfMemory();
SDL_free(device);
SDL_free(phdata);
return NULL;
}
device->gl_data = gldata;
phdata->egl_initialized = SDL_TRUE;
#endif
phdata->ime_active = SDL_FALSE;
device->driverdata = phdata;
device->num_displays = 0;
device->free = VITA_Destroy;
device->VideoInit = VITA_VideoInit;
device->VideoQuit = VITA_VideoQuit;
device->GetDisplayModes = VITA_GetDisplayModes;
device->SetDisplayMode = VITA_SetDisplayMode;
device->CreateSDLWindow = VITA_CreateWindow;
device->CreateSDLWindowFrom = VITA_CreateWindowFrom;
device->SetWindowTitle = VITA_SetWindowTitle;
device->SetWindowIcon = VITA_SetWindowIcon;
device->SetWindowPosition = VITA_SetWindowPosition;
device->SetWindowSize = VITA_SetWindowSize;
device->ShowWindow = VITA_ShowWindow;
device->HideWindow = VITA_HideWindow;
device->RaiseWindow = VITA_RaiseWindow;
device->MaximizeWindow = VITA_MaximizeWindow;
device->MinimizeWindow = VITA_MinimizeWindow;
device->RestoreWindow = VITA_RestoreWindow;
device->SetWindowMouseGrab = VITA_SetWindowGrab;
device->SetWindowKeyboardGrab = VITA_SetWindowGrab;
device->DestroyWindow = VITA_DestroyWindow;
device->GetWindowWMInfo = VITA_GetWindowWMInfo;
#if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR)
#if defined(SDL_VIDEO_VITA_PVR_OGL)
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
device->GL_LoadLibrary = VITA_GL_LoadLibrary;
device->GL_CreateContext = VITA_GL_CreateContext;
device->GL_GetProcAddress = VITA_GL_GetProcAddress;
} else {
#endif
device->GL_LoadLibrary = VITA_GLES_LoadLibrary;
device->GL_CreateContext = VITA_GLES_CreateContext;
device->GL_GetProcAddress = VITA_GLES_GetProcAddress;
#if defined(SDL_VIDEO_VITA_PVR_OGL)
}
#endif
device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary;
device->GL_MakeCurrent = VITA_GLES_MakeCurrent;
device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval;
device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval;
device->GL_SwapWindow = VITA_GLES_SwapWindow;
device->GL_DeleteContext = VITA_GLES_DeleteContext;
#endif
device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = VITA_ShowScreenKeyboard;
device->HideScreenKeyboard = VITA_HideScreenKeyboard;
device->IsScreenKeyboardShown = VITA_IsScreenKeyboardShown;
device->PumpEvents = VITA_PumpEvents;
return device;
}
VideoBootStrap VITA_bootstrap = {
"VITA",
"VITA Video Driver",
VITA_Create
};
int
VITA_VideoInit(_THIS)
{
SDL_VideoDisplay display;
SDL_DisplayMode current_mode;
#if defined(SDL_VIDEO_VITA_PVR)
char* res = SDL_getenv("VITA_RESOLUTION");
#endif
SDL_zero(current_mode);
#if defined(SDL_VIDEO_VITA_PVR)
if (res) {
if (!SDL_strncmp(res, "1080", 4)) {
current_mode.w = 1920;
current_mode.h = 1088;
}
else if (!SDL_strncmp(res, "720", 3)) {
current_mode.w = 1280;
current_mode.h = 725;
}
}
else {
#endif
current_mode.w = 960;
current_mode.h = 544;
#if defined(SDL_VIDEO_VITA_PVR)
}
#endif
current_mode.refresh_rate = 60;
current_mode.format = SDL_PIXELFORMAT_ABGR8888;
current_mode.driverdata = NULL;
SDL_zero(display);
display.desktop_mode = current_mode;
display.current_mode = current_mode;
display.driverdata = NULL;
SDL_AddVideoDisplay(&display, SDL_FALSE);
VITA_InitTouch();
VITA_InitKeyboard();
VITA_InitMouse();
return 1;
}
void
VITA_VideoQuit(_THIS)
{
VITA_QuitTouch();
}
void
VITA_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_AddDisplayMode(display, &display->current_mode);
}
int
VITA_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
return 0;
}
int
VITA_CreateWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *wdata;
#if defined(SDL_VIDEO_VITA_PVR)
Psp2NativeWindow win;
int temp_major = 2;
int temp_minor = 1;
int temp_profile = 0;
#endif
wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
if (wdata == NULL) {
return SDL_OutOfMemory();
}
window->driverdata = wdata;
if (Vita_Window != NULL)
{
return SDL_SetError("Only one window supported");
}
Vita_Window = window;
#if defined(SDL_VIDEO_VITA_PVR)
win.type = PSP2_DRAWABLE_TYPE_WINDOW;
win.numFlipBuffers = 2;
win.flipChainThrdAffinity = 0x20000;
if (window->w == 1920) {
win.windowSize = PSP2_WINDOW_1920X1088;
}
else if (window->w == 1280) {
win.windowSize = PSP2_WINDOW_1280X725;
}
else {
win.windowSize = PSP2_WINDOW_960X544;
}
if ((window->flags & SDL_WINDOW_OPENGL) != 0) {
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
temp_major = _this->gl_config.major_version;
temp_minor = _this->gl_config.minor_version;
temp_profile = _this->gl_config.profile_mask;
_this->gl_config.major_version = 2;
_this->gl_config.minor_version = 1;
_this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
}
wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win);
if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
_this->gl_config.major_version = temp_major;
_this->gl_config.minor_version = temp_minor;
_this->gl_config.profile_mask = temp_profile;
}
}
#endif
SDL_SetKeyboardFocus(window);
return 0;
}
int
VITA_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
{
return -1;
}
void
VITA_SetWindowTitle(_THIS, SDL_Window * window)
{
}
void
VITA_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
{
}
void
VITA_SetWindowPosition(_THIS, SDL_Window * window)
{
}
void
VITA_SetWindowSize(_THIS, SDL_Window * window)
{
}
void
VITA_ShowWindow(_THIS, SDL_Window * window)
{
}
void
VITA_HideWindow(_THIS, SDL_Window * window)
{
}
void
VITA_RaiseWindow(_THIS, SDL_Window * window)
{
}
void
VITA_MaximizeWindow(_THIS, SDL_Window * window)
{
}
void
VITA_MinimizeWindow(_THIS, SDL_Window * window)
{
}
void
VITA_RestoreWindow(_THIS, SDL_Window * window)
{
}
void
VITA_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
{
}
void
VITA_DestroyWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *data;
data = window->driverdata;
if (data) {
SDL_free(data);
}
window->driverdata = NULL;
Vita_Window = NULL;
}
SDL_bool
VITA_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
{
if (info->version.major <= SDL_MAJOR_VERSION) {
return SDL_TRUE;
} else {
SDL_SetError("application not compiled with SDL %d\n",
SDL_MAJOR_VERSION);
return SDL_FALSE;
}
return SDL_FALSE;
}
SDL_bool VITA_HasScreenKeyboardSupport(_THIS)
{
return SDL_TRUE;
}
#if !defined(SCE_IME_LANGUAGE_ENGLISH_US)
#define SCE_IME_LANGUAGE_ENGLISH_US SCE_IME_LANGUAGE_ENGLISH
#endif
static void utf16_to_utf8(const uint16_t *src, uint8_t *dst) {
int i;
for (i = 0; src[i]; i++) {
if ((src[i] & 0xFF80) == 0) {
*(dst++) = src[i] & 0xFF;
} else if((src[i] & 0xF800) == 0) {
*(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
*(dst++) = (src[i] & 0x3F) | 0x80;
} else if((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) {
*(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
*(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
*(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
*(dst++) = (src[i + 1] & 0x3F) | 0x80;
i += 1;
} else {
*(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
*(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
*(dst++) = (src[i] & 0x3F) | 0x80;
}
}
*dst = '\0';
}
#if defined (SDL_VIDEO_VITA_PVR)
SceWChar16 libime_out[SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1];
char libime_initval[8] = { 1 };
SceImeCaret caret_rev;
void VITA_ImeEventHandler(void *arg, const SceImeEventData *e)
{
SDL_VideoData *videodata = (SDL_VideoData *)arg;
SDL_Scancode scancode;
uint8_t utf8_buffer[SCE_IME_MAX_TEXT_LENGTH];
switch (e->id) {
case SCE_IME_EVENT_UPDATE_TEXT:
if (e->param.text.caretIndex == 0) {
SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_BACKSPACE);
sceImeSetText((SceWChar16 *)libime_initval, 4);
}
else {
scancode = SDL_GetScancodeFromKey(*(SceWChar16 *)&libime_out[1]);
if (scancode == SDL_SCANCODE_SPACE) {
SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_SPACE);
}
else {
utf16_to_utf8((SceWChar16 *)&libime_out[1], utf8_buffer);
SDL_SendKeyboardText((const char*)utf8_buffer);
}
SDL_memset(&caret_rev, 0, sizeof(SceImeCaret));
SDL_memset(libime_out, 0, ((SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1) * sizeof(SceWChar16)));
caret_rev.index = 1;
sceImeSetCaret(&caret_rev);
sceImeSetText((SceWChar16 *)libime_initval, 4);
}
break;
case SCE_IME_EVENT_PRESS_ENTER:
SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_RETURN);
case SCE_IME_EVENT_PRESS_CLOSE:
sceImeClose();
videodata->ime_active = SDL_FALSE;
break;
}
}
#endif
void VITA_ShowScreenKeyboard(_THIS, SDL_Window *window)
{
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
SceInt32 res;
#if defined(SDL_VIDEO_VITA_PVR)
SceUInt32 libime_work[SCE_IME_WORK_BUFFER_SIZE / sizeof(SceInt32)];
SceImeParam param;
sceImeParamInit(¶m);
SDL_memset(libime_out, 0, ((SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1) * sizeof(SceWChar16)));
param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH_US;
param.languagesForced = SCE_FALSE;
param.type = SCE_IME_TYPE_DEFAULT;
param.option = SCE_IME_OPTION_NO_ASSISTANCE;
param.inputTextBuffer = libime_out;
param.maxTextLength = SCE_IME_MAX_TEXT_LENGTH;
param.handler = VITA_ImeEventHandler;
param.filter = NULL;
param.initialText = (SceWChar16 *)libime_initval;
param.arg = videodata;
param.work = libime_work;
res = sceImeOpen(¶m);
if (res < 0) {
SDL_SetError("Failed to init IME");
return;
}
#else
SceWChar16 *title = u"";
SceWChar16 *text = u"";
SceImeDialogParam param;
sceImeDialogParamInit(¶m);
param.supportedLanguages = 0;
param.languagesForced = SCE_FALSE;
param.type = SCE_IME_TYPE_DEFAULT;
param.option = 0;
param.textBoxMode = SCE_IME_DIALOG_TEXTBOX_MODE_WITH_CLEAR;
param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH;
param.title = title;
param.initialText = text;
param.inputTextBuffer = videodata->ime_buffer;
res = sceImeDialogInit(¶m);
if (res < 0) {
SDL_SetError("Failed to init IME dialog");
return;
}
#endif
videodata->ime_active = SDL_TRUE;
}
void VITA_HideScreenKeyboard(_THIS, SDL_Window *window)
{
#if !defined(SDL_VIDEO_VITA_PVR)
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus();
switch (dialogStatus) {
default:
case SCE_COMMON_DIALOG_STATUS_NONE:
case SCE_COMMON_DIALOG_STATUS_RUNNING:
break;
case SCE_COMMON_DIALOG_STATUS_FINISHED:
sceImeDialogTerm();
break;
}
videodata->ime_active = SDL_FALSE;
#endif
}
SDL_bool VITA_IsScreenKeyboardShown(_THIS, SDL_Window *window)
{
#if defined(SDL_VIDEO_VITA_PVR)
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
return videodata->ime_active;
#else
SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus();
return (dialogStatus == SCE_COMMON_DIALOG_STATUS_RUNNING);
#endif
}
void VITA_PumpEvents(_THIS)
{
#if !defined(SDL_VIDEO_VITA_PVR)
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
#endif
if (_this->suspend_screensaver) {
sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT);
}
VITA_PollTouch();
VITA_PollKeyboard();
VITA_PollMouse();
#if !defined(SDL_VIDEO_VITA_PVR)
if (videodata->ime_active == SDL_TRUE) {
SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus();
if (dialogStatus == SCE_COMMON_DIALOG_STATUS_FINISHED) {
uint8_t utf8_buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
SceImeDialogResult result;
SDL_memset(&result, 0, sizeof(SceImeDialogResult));
sceImeDialogGetResult(&result);
utf16_to_utf8(videodata->ime_buffer, utf8_buffer);
SDL_SendKeyboardText((const char*)utf8_buffer);
if (result.button == SCE_IME_DIALOG_BUTTON_ENTER)
SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_RETURN);
sceImeDialogTerm();
videodata->ime_active = SDL_FALSE;
}
}
#endif
}
#endif