std::string seems to be the preferred method since you don't need to alloc more memory then you need (the Class automagically allocates the necessary RAM) and there is no chance of buffer overflow. But since I don't have Mac OSX, I didn't test it (it should work, since this is standard C++). Add Mac OSX support to Launcher{Market,Email} too and changed Linux to use "xdg-email " instead "xdg-open mailto:" since this seems the preferred method.
717 lines
19 KiB
C++
717 lines
19 KiB
C++
// SDL/EGL implementation of the framework.
|
|
// This is quite messy due to platform-specific implementations and #ifdef's.
|
|
// It is suggested to use the Qt implementation instead.
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
#include <shlobj.h>
|
|
#include <shlwapi.h>
|
|
#include <ShellAPI.h>
|
|
#else
|
|
#include <pwd.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include <string>
|
|
#include <map>
|
|
#ifdef _WIN32
|
|
#include "SDL/SDL.h"
|
|
#include "SDL/SDL_timer.h"
|
|
#include "SDL/SDL_audio.h"
|
|
#include "SDL/SDL_video.h"
|
|
#else
|
|
#include "SDL.h"
|
|
#include "SDL_timer.h"
|
|
#include "SDL_audio.h"
|
|
#include "SDL_video.h"
|
|
#endif
|
|
#include "base/display.h"
|
|
#include "base/logging.h"
|
|
#include "base/timeutil.h"
|
|
#include "gfx_es2/gl_state.h"
|
|
#include "gfx_es2/glsl_program.h"
|
|
#include "file/zip_read.h"
|
|
#include "input/input_state.h"
|
|
#include "input/keycodes.h"
|
|
#include "base/NKCodeFromSDL.h"
|
|
#include "base/NativeApp.h"
|
|
#include "net/resolve.h"
|
|
#include "util/const_map.h"
|
|
|
|
#if defined(MAEMO) || defined(PANDORA)
|
|
#define EGL
|
|
#include "EGL/egl.h"
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include "SDL_syswm.h"
|
|
#include "math.h"
|
|
|
|
#ifdef PANDORA
|
|
void enable_runfast()
|
|
{
|
|
static const unsigned int x = 0x04086060;
|
|
static const unsigned int y = 0x03000000;
|
|
int r;
|
|
asm volatile (
|
|
"fmrx %0, fpscr \n\t" //r0 = FPSCR
|
|
"and %0, %0, %1 \n\t" //r0 = r0 & 0x04086060
|
|
"orr %0, %0, %2 \n\t" //r0 = r0 | 0x03000000
|
|
"fmxr fpscr, %0 \n\t" //FPSCR = r0
|
|
: "=r"(r)
|
|
: "r"(x), "r"(y)
|
|
);
|
|
}
|
|
#endif
|
|
|
|
EGLDisplay g_eglDisplay = NULL;
|
|
EGLContext g_eglContext = NULL;
|
|
EGLSurface g_eglSurface = NULL;
|
|
Display* g_Display = NULL;
|
|
NativeWindowType g_Window = (NativeWindowType)NULL;
|
|
|
|
int8_t CheckEGLErrors(const std::string& file, uint16_t line) {
|
|
EGLenum error;
|
|
std::string errortext;
|
|
|
|
error = eglGetError();
|
|
switch (error)
|
|
{
|
|
case EGL_SUCCESS: case 0: return 0;
|
|
case EGL_NOT_INITIALIZED: errortext = "EGL_NOT_INITIALIZED"; break;
|
|
case EGL_BAD_ACCESS: errortext = "EGL_BAD_ACCESS"; break;
|
|
case EGL_BAD_ALLOC: errortext = "EGL_BAD_ALLOC"; break;
|
|
case EGL_BAD_ATTRIBUTE: errortext = "EGL_BAD_ATTRIBUTE"; break;
|
|
case EGL_BAD_CONTEXT: errortext = "EGL_BAD_CONTEXT"; break;
|
|
case EGL_BAD_CONFIG: errortext = "EGL_BAD_CONFIG"; break;
|
|
case EGL_BAD_CURRENT_SURFACE: errortext = "EGL_BAD_CURRENT_SURFACE"; break;
|
|
case EGL_BAD_DISPLAY: errortext = "EGL_BAD_DISPLAY"; break;
|
|
case EGL_BAD_SURFACE: errortext = "EGL_BAD_SURFACE"; break;
|
|
case EGL_BAD_MATCH: errortext = "EGL_BAD_MATCH"; break;
|
|
case EGL_BAD_PARAMETER: errortext = "EGL_BAD_PARAMETER"; break;
|
|
case EGL_BAD_NATIVE_PIXMAP: errortext = "EGL_BAD_NATIVE_PIXMAP"; break;
|
|
case EGL_BAD_NATIVE_WINDOW: errortext = "EGL_BAD_NATIVE_WINDOW"; break;
|
|
default: errortext = "unknown"; break;
|
|
}
|
|
printf( "ERROR: EGL Error detected in file %s at line %d: %s (0x%X)\n", file.c_str(), line, errortext.c_str(), error );
|
|
return 1;
|
|
}
|
|
#define EGL_ERROR(str, check) { \
|
|
if (check) CheckEGLErrors( __FILE__, __LINE__ ); \
|
|
printf("EGL ERROR: " str "\n"); \
|
|
return 1; \
|
|
}
|
|
|
|
int8_t EGL_Open() {
|
|
#ifdef PANDORA
|
|
g_Display = EGL_DEFAULT_DISPLAY;
|
|
#else
|
|
if ((g_Display = XOpenDisplay(NULL)) == NULL)
|
|
EGL_ERROR("Unable to get display!", false);
|
|
#endif
|
|
if ((g_eglDisplay = eglGetDisplay((NativeDisplayType)g_Display)) == EGL_NO_DISPLAY)
|
|
EGL_ERROR("Unable to create EGL display.", true);
|
|
if (eglInitialize(g_eglDisplay, NULL, NULL) != EGL_TRUE)
|
|
EGL_ERROR("Unable to initialize EGL display.", true);
|
|
return 0;
|
|
}
|
|
|
|
int8_t EGL_Init() {
|
|
EGLConfig g_eglConfig; //[1] = {NULL};
|
|
EGLint g_numConfigs = 0;
|
|
EGLint attrib_list[]= {
|
|
#ifdef PANDORA
|
|
EGL_RED_SIZE, 5,
|
|
EGL_GREEN_SIZE, 6,
|
|
EGL_BLUE_SIZE, 5,
|
|
#endif
|
|
EGL_DEPTH_SIZE, 16,
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
EGL_SAMPLE_BUFFERS, 0,
|
|
EGL_SAMPLES, 0,
|
|
#ifdef MAEMO
|
|
EGL_BUFFER_SIZE, 16,
|
|
#endif
|
|
EGL_NONE};
|
|
|
|
const EGLint attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
|
|
|
|
EGLBoolean result = eglChooseConfig(g_eglDisplay, attrib_list, &g_eglConfig, 1, &g_numConfigs);
|
|
if (result != EGL_TRUE || g_numConfigs == 0) EGL_ERROR("Unable to query for available configs.", true);
|
|
|
|
g_eglContext = eglCreateContext(g_eglDisplay, g_eglConfig, NULL, attributes );
|
|
if (g_eglContext == EGL_NO_CONTEXT) EGL_ERROR("Unable to create GLES context!", true);
|
|
|
|
// Get the SDL window handle
|
|
SDL_SysWMinfo sysInfo; //Will hold our Window information
|
|
SDL_VERSION(&sysInfo.version); //Set SDL version
|
|
if(SDL_GetWMInfo(&sysInfo) <= 0)
|
|
{
|
|
printf("EGL ERROR: Unable to get SDL window handle: %s\n", SDL_GetError());
|
|
return 1;
|
|
}
|
|
|
|
#ifdef PANDORA
|
|
g_Window = (NativeWindowType)NULL;
|
|
#else
|
|
g_Window = (NativeWindowType)sysInfo.info.x11.window;
|
|
#endif
|
|
g_eglSurface = eglCreateWindowSurface(g_eglDisplay, g_eglConfig, g_Window, 0);
|
|
if (g_eglSurface == EGL_NO_SURFACE) EGL_ERROR("Unable to create EGL surface!", true);
|
|
|
|
if (eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, g_eglContext) != EGL_TRUE)
|
|
EGL_ERROR("Unable to make GLES context current.", true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void EGL_Close() {
|
|
if (g_eglDisplay != NULL)
|
|
{
|
|
eglMakeCurrent(g_eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
|
|
if (g_eglContext != NULL) {
|
|
eglDestroyContext(g_eglDisplay, g_eglContext);
|
|
}
|
|
if (g_eglSurface != NULL) {
|
|
eglDestroySurface(g_eglDisplay, g_eglSurface);
|
|
}
|
|
eglTerminate(g_eglDisplay);
|
|
g_eglDisplay = NULL;
|
|
}
|
|
if (g_Display != NULL) {
|
|
XCloseDisplay(g_Display);
|
|
g_Display = NULL;
|
|
}
|
|
g_eglSurface = NULL;
|
|
g_eglContext = NULL;
|
|
}
|
|
#else
|
|
#endif
|
|
|
|
#ifdef PANDORA
|
|
SDL_Joystick *ljoy = NULL;
|
|
SDL_Joystick *rjoy = NULL;
|
|
#else
|
|
SDL_Joystick *joy = NULL;
|
|
#endif
|
|
|
|
// Simple implementations of System functions
|
|
|
|
|
|
void SystemToast(const char *text) {
|
|
#ifdef _WIN32
|
|
MessageBox(0, text, "Toast!", MB_ICONINFORMATION);
|
|
#else
|
|
puts(text);
|
|
#endif
|
|
}
|
|
|
|
void ShowAd(int x, int y, bool center_x) {
|
|
// Ignore ads on PC
|
|
}
|
|
|
|
void ShowKeyboard() {
|
|
// Irrelevant on PC
|
|
}
|
|
|
|
void Vibrate(int length_ms) {
|
|
// Ignore on PC
|
|
}
|
|
|
|
void System_InputBox(const char *title, const char *defaultValue) {
|
|
// Stub
|
|
NativeMessageReceived((std::string("INPUTBOX:") + title).c_str(), "TestFile");
|
|
}
|
|
|
|
void LaunchBrowser(const char *url)
|
|
{
|
|
#ifdef _WIN32
|
|
ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
|
#elif __linux__
|
|
std::string command = std::string("xdg-open ") + url;
|
|
system(command.c_str());
|
|
#elif __APPLE__
|
|
std::string command = std::string("open ") + url;
|
|
system(command.c_str());
|
|
#else
|
|
ILOG("Would have gone to %s but LaunchBrowser is not implemented on this platform", url);
|
|
#endif
|
|
}
|
|
|
|
void LaunchMarket(const char *url)
|
|
{
|
|
#ifdef _WIN32
|
|
ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
|
#elif __linux__
|
|
std::string command = std::string("xdg-open ") + url;
|
|
system(command.c_str());
|
|
#elif __APPLE__
|
|
std::string command = std::string("open ") + url;
|
|
system(command.c_str());
|
|
#else
|
|
ILOG("Would have gone to %s but LaunchMarket is not implemented on this platform", url);
|
|
#endif
|
|
}
|
|
|
|
void LaunchEmail(const char *email_address)
|
|
{
|
|
#ifdef _WIN32
|
|
ShellExecute(NULL, "open", (std::string("mailto:") + email_address).c_str(), NULL, NULL, SW_SHOWNORMAL);
|
|
#elif __linux__
|
|
std::string command = std::string("xdg-email ") + email_address;
|
|
system(command.c_str());
|
|
#elif __APPLE__
|
|
std::string command = std::string("open mailto:") + email_address;
|
|
system(command.c_str());
|
|
#else
|
|
ILOG("Would have opened your email client for %s but LaunchEmail is not implemented on this platform", email_address);
|
|
#endif
|
|
}
|
|
|
|
std::string System_GetProperty(SystemProperty prop) {
|
|
switch (prop) {
|
|
case SYSPROP_NAME:
|
|
return "SDL:";
|
|
case SYSPROP_LANGREGION:
|
|
return "en_US";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
InputState input_state;
|
|
|
|
void SimulateGamepad(const uint8 *keys, InputState *input) {
|
|
input->pad_buttons = 0;
|
|
input->pad_lstick_x = 0;
|
|
input->pad_lstick_y = 0;
|
|
input->pad_rstick_x = 0;
|
|
input->pad_rstick_y = 0;
|
|
|
|
// TODO: Use NativeAxis for joy instead.
|
|
#ifdef PANDORA
|
|
if ((ljoy)||(rjoy)) {
|
|
SDL_JoystickUpdate();
|
|
if (ljoy) {
|
|
input->pad_lstick_x = max(min(SDL_JoystickGetAxis(ljoy, 0) / 32000.0f, 1.0f), -1.0f);
|
|
input->pad_lstick_y = max(min(-SDL_JoystickGetAxis(ljoy, 1) / 32000.0f, 1.0f), -1.0f);
|
|
}
|
|
if (rjoy) {
|
|
input->pad_rstick_x = max(min(SDL_JoystickGetAxis(rjoy, 0) / 32000.0f, 1.0f), -1.0f);
|
|
input->pad_rstick_y = max(min(SDL_JoystickGetAxis(rjoy, 1) / 32000.0f, 1.0f), -1.0f);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
extern void mixaudio(void *userdata, Uint8 *stream, int len) {
|
|
NativeMix((short *)stream, len / 4);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#undef main
|
|
#endif
|
|
int main(int argc, char *argv[]) {
|
|
std::string app_name;
|
|
std::string app_name_nice;
|
|
bool landscape;
|
|
NativeGetAppInfo(&app_name, &app_name_nice, &landscape);
|
|
|
|
net::Init();
|
|
#ifdef __APPLE__
|
|
// Make sure to request a somewhat modern GL context at least - the
|
|
// latest supported by MacOSX (really, really sad...)
|
|
// Requires SDL 2.0
|
|
// We really should upgrade to SDL 2.0 soon.
|
|
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
|
#endif
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0) {
|
|
fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
|
|
return 1;
|
|
}
|
|
#ifdef EGL
|
|
if (EGL_Open())
|
|
return 1;
|
|
#endif
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
|
|
|
int mode;
|
|
#ifdef USING_GLES2
|
|
mode = SDL_SWSURFACE | SDL_FULLSCREEN;
|
|
#else
|
|
mode = SDL_OPENGL;
|
|
for (int i = 1; i < argc; i++)
|
|
if (!strcmp(argv[i],"--fullscreen"))
|
|
mode |= SDL_FULLSCREEN;
|
|
#endif
|
|
if ((mode & SDL_FULLSCREEN) == 0) {
|
|
// set a sensible default resolution (2x)
|
|
pixel_xres = 480 * 2;
|
|
pixel_yres = 272 * 2;
|
|
}
|
|
|
|
if (SDL_SetVideoMode(pixel_xres, pixel_yres, 0, mode) == NULL) {
|
|
fprintf(stderr, "SDL SetVideoMode failed: Unable to create OpenGL screen: %s\n", SDL_GetError());
|
|
SDL_Quit();
|
|
return(2);
|
|
}
|
|
#ifdef EGL
|
|
EGL_Init();
|
|
#endif
|
|
|
|
SDL_WM_SetCaption(app_name_nice.c_str(), NULL);
|
|
#ifdef MAEMO
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
#endif
|
|
|
|
|
|
#ifndef USING_GLES2
|
|
if (GLEW_OK != glewInit()) {
|
|
printf("Failed to initialize glew!\n");
|
|
return 1;
|
|
}
|
|
|
|
if (GLEW_VERSION_2_0) {
|
|
printf("OpenGL 2.0 or higher.\n");
|
|
} else {
|
|
printf("Sorry, this program requires OpenGL 2.0.\n");
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
// Maybe resize screen first if on a desktop
|
|
const SDL_VideoInfo* info = SDL_GetVideoInfo();
|
|
pixel_xres = info->current_w;
|
|
pixel_yres = info->current_h;
|
|
|
|
#ifdef _MSC_VER
|
|
// VFSRegister("temp/", new DirectoryAssetReader("E:\\Temp\\"));
|
|
TCHAR path[MAX_PATH];
|
|
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path);
|
|
PathAppend(path, (app_name + "\\").c_str());
|
|
#else
|
|
// Mac / Linux
|
|
char path[512];
|
|
const char *the_path = getenv("HOME");
|
|
if (!the_path) {
|
|
struct passwd* pwd = getpwuid(getuid());
|
|
if (pwd)
|
|
the_path = pwd->pw_dir;
|
|
}
|
|
strcpy(path, the_path);
|
|
if (path[strlen(path)-1] != '/')
|
|
strcat(path, "/");
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
NativeInit(argc, (const char **)argv, path, "D:\\", "BADCOFFEE");
|
|
#else
|
|
NativeInit(argc, (const char **)argv, path, "/tmp", "BADCOFFEE");
|
|
#endif
|
|
|
|
dp_xres = (float)pixel_xres;
|
|
dp_yres = (float)pixel_yres;
|
|
pixel_in_dps = (float)pixel_xres / dp_xres;
|
|
|
|
NativeInitGraphics();
|
|
glstate.viewport.set(0, 0, pixel_xres, pixel_yres);
|
|
|
|
float dp_xscale = (float)dp_xres / pixel_xres;
|
|
float dp_yscale = (float)dp_yres / pixel_yres;
|
|
|
|
g_dpi_scale = dp_xres / (float)pixel_xres;
|
|
|
|
printf("Pixels: %i x %i\n", pixel_xres, pixel_yres);
|
|
printf("Virtual pixels: %i x %i\n", dp_xres, dp_yres);
|
|
|
|
SDL_AudioSpec fmt;
|
|
fmt.freq = 44100;
|
|
fmt.format = AUDIO_S16;
|
|
fmt.channels = 2;
|
|
fmt.samples = 2048;
|
|
fmt.callback = &mixaudio;
|
|
fmt.userdata = (void *)0;
|
|
|
|
if (SDL_OpenAudio(&fmt, NULL) < 0)
|
|
ELOG("Failed to open audio: %s", SDL_GetError());
|
|
|
|
// Audio must be unpaused _after_ NativeInit()
|
|
SDL_PauseAudio(0);
|
|
int numjoys = SDL_NumJoysticks();
|
|
#ifdef PANDORA
|
|
// Joysticks init, we the nubs if setup as Joystick
|
|
if (numjoys > 0) {
|
|
ljoy = SDL_JoystickOpen(0);
|
|
if (numjoys > 1)
|
|
rjoy = SDL_JoystickOpen(1);
|
|
}
|
|
enable_runfast(); // VFPv2 RunFast
|
|
#else
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
if (numjoys > 0) {
|
|
joy = SDL_JoystickOpen(0);
|
|
}
|
|
#endif
|
|
|
|
// This is just a standard mapping that matches the X360 controller on MacOSX. Names will probably be all wrong
|
|
// on other controllers.
|
|
std::map<int, int> SDLJoyButtonMap;
|
|
SDLJoyButtonMap[0] = NKCODE_DPAD_UP;
|
|
SDLJoyButtonMap[1] = NKCODE_DPAD_DOWN;
|
|
SDLJoyButtonMap[2] = NKCODE_DPAD_LEFT;
|
|
SDLJoyButtonMap[3] = NKCODE_DPAD_RIGHT;
|
|
SDLJoyButtonMap[4] = NKCODE_BUTTON_10;
|
|
SDLJoyButtonMap[5] = NKCODE_BUTTON_9;
|
|
SDLJoyButtonMap[6] = NKCODE_BUTTON_5;
|
|
SDLJoyButtonMap[7] = NKCODE_BUTTON_6;
|
|
SDLJoyButtonMap[8] = NKCODE_BUTTON_7;
|
|
SDLJoyButtonMap[9] = NKCODE_BUTTON_8;
|
|
SDLJoyButtonMap[10] = NKCODE_BUTTON_SELECT;
|
|
SDLJoyButtonMap[11] = NKCODE_BUTTON_2;
|
|
SDLJoyButtonMap[12] = NKCODE_BUTTON_3;
|
|
SDLJoyButtonMap[13] = NKCODE_BUTTON_4;
|
|
SDLJoyButtonMap[14] = NKCODE_BUTTON_1;
|
|
|
|
std::map<int, int> SDLJoyAxisMap;
|
|
SDLJoyAxisMap[0] = JOYSTICK_AXIS_X;
|
|
SDLJoyAxisMap[1] = JOYSTICK_AXIS_Y;
|
|
SDLJoyAxisMap[2] = JOYSTICK_AXIS_Z;
|
|
SDLJoyAxisMap[3] = JOYSTICK_AXIS_RZ;
|
|
SDLJoyAxisMap[4] = JOYSTICK_AXIS_LTRIGGER;
|
|
SDLJoyAxisMap[5] = JOYSTICK_AXIS_RTRIGGER;
|
|
|
|
int framecount = 0;
|
|
float t = 0;
|
|
float lastT = 0;
|
|
while (true) {
|
|
input_state.accelerometer_valid = false;
|
|
input_state.mouse_valid = true;
|
|
int quitRequested = 0;
|
|
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
float mx = event.motion.x * dp_xscale;
|
|
float my = event.motion.y * dp_yscale;
|
|
|
|
switch (event.type) {
|
|
case SDL_QUIT:
|
|
quitRequested = 1;
|
|
break;
|
|
|
|
case SDL_JOYAXISMOTION:
|
|
{
|
|
AxisInput axis;
|
|
axis.axisId = SDLJoyAxisMap[event.jaxis.axis];
|
|
// 1.2 to try to approximate the PSP's clamped rectangular range.
|
|
axis.value = 1.2 * event.jaxis.value / 32767.0f;
|
|
if (axis.value > 1.0f) axis.value = 1.0f;
|
|
if (axis.value < -1.0f) axis.value = -1.0f;
|
|
axis.deviceId = DEVICE_ID_PAD_0;
|
|
axis.flags = 0;
|
|
NativeAxis(axis);
|
|
break;
|
|
}
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
{
|
|
KeyInput key;
|
|
key.flags = KEY_DOWN;
|
|
key.keyCode = SDLJoyButtonMap[event.jbutton.button];
|
|
key.deviceId = DEVICE_ID_PAD_0;
|
|
NativeKey(key);
|
|
break;
|
|
}
|
|
|
|
case SDL_JOYBUTTONUP:
|
|
{
|
|
KeyInput key;
|
|
key.flags = KEY_UP;
|
|
key.keyCode = SDLJoyButtonMap[event.jbutton.button];
|
|
key.deviceId = DEVICE_ID_PAD_0;
|
|
NativeKey(key);
|
|
break;
|
|
}
|
|
|
|
case SDL_KEYDOWN:
|
|
{
|
|
int k = event.key.keysym.sym;
|
|
KeyInput key;
|
|
key.flags = KEY_DOWN;
|
|
key.keyCode = KeyMapRawSDLtoNative.find(k)->second;
|
|
key.deviceId = DEVICE_ID_KEYBOARD;
|
|
NativeKey(key);
|
|
break;
|
|
}
|
|
case SDL_KEYUP:
|
|
{
|
|
int k = event.key.keysym.sym;
|
|
KeyInput key;
|
|
key.flags = KEY_UP;
|
|
key.keyCode = KeyMapRawSDLtoNative.find(k)->second;
|
|
key.deviceId = DEVICE_ID_KEYBOARD;
|
|
NativeKey(key);
|
|
break;
|
|
}
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
switch (event.button.button) {
|
|
case SDL_BUTTON_LEFT:
|
|
{
|
|
input_state.pointer_x[0] = mx;
|
|
input_state.pointer_y[0] = my;
|
|
//input_state.mouse_buttons_down = 1;
|
|
input_state.pointer_down[0] = true;
|
|
input_state.mouse_valid = true;
|
|
TouchInput input;
|
|
input.x = mx;
|
|
input.y = my;
|
|
input.flags = TOUCH_DOWN;
|
|
input.id = 0;
|
|
NativeTouch(input);
|
|
KeyInput key(DEVICE_ID_MOUSE, NKCODE_EXT_MOUSEBUTTON_1, KEY_DOWN);
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
case SDL_BUTTON_RIGHT:
|
|
{
|
|
KeyInput key(DEVICE_ID_MOUSE, NKCODE_EXT_MOUSEBUTTON_2, KEY_DOWN);
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
case SDL_BUTTON_WHEELUP:
|
|
{
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_MOUSE;
|
|
key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP;
|
|
key.flags = KEY_DOWN;
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
case SDL_BUTTON_WHEELDOWN:
|
|
{
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_MOUSE;
|
|
key.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN;
|
|
key.flags = KEY_DOWN;
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case SDL_MOUSEMOTION:
|
|
if (input_state.pointer_down[0]) {
|
|
input_state.pointer_x[0] = mx;
|
|
input_state.pointer_y[0] = my;
|
|
input_state.mouse_valid = true;
|
|
TouchInput input;
|
|
input.x = mx;
|
|
input.y = my;
|
|
input.flags = TOUCH_MOVE;
|
|
input.id = 0;
|
|
NativeTouch(input);
|
|
}
|
|
break;
|
|
case SDL_MOUSEBUTTONUP:
|
|
switch (event.button.button) {
|
|
case SDL_BUTTON_LEFT:
|
|
{
|
|
input_state.pointer_x[0] = mx;
|
|
input_state.pointer_y[0] = my;
|
|
input_state.pointer_down[0] = false;
|
|
input_state.mouse_valid = true;
|
|
//input_state.mouse_buttons_up = 1;
|
|
TouchInput input;
|
|
input.x = mx;
|
|
input.y = my;
|
|
input.flags = TOUCH_UP;
|
|
input.id = 0;
|
|
NativeTouch(input);
|
|
KeyInput key(DEVICE_ID_MOUSE, NKCODE_EXT_MOUSEBUTTON_1, KEY_UP);
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
case SDL_BUTTON_RIGHT:
|
|
{
|
|
KeyInput key(DEVICE_ID_MOUSE, NKCODE_EXT_MOUSEBUTTON_2, KEY_UP);
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
case SDL_BUTTON_WHEELUP:
|
|
{
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_DEFAULT;
|
|
key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP;
|
|
key.flags = KEY_UP;
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
case SDL_BUTTON_WHEELDOWN:
|
|
{
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_DEFAULT;
|
|
key.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN;
|
|
key.flags = KEY_UP;
|
|
NativeKey(key);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (quitRequested)
|
|
break;
|
|
|
|
const uint8 *keys = (const uint8 *)SDL_GetKeyState(NULL);
|
|
SimulateGamepad(keys, &input_state);
|
|
UpdateInputState(&input_state);
|
|
NativeUpdate(input_state);
|
|
NativeRender();
|
|
|
|
EndInputState(&input_state);
|
|
|
|
if (framecount % 60 == 0) {
|
|
// glsl_refresh(); // auto-reloads modified GLSL shaders once per second.
|
|
}
|
|
|
|
#ifdef EGL
|
|
eglSwapBuffers(g_eglDisplay, g_eglSurface);
|
|
#else
|
|
if (!keys[SDLK_TAB] || t - lastT >= 1.0/60.0)
|
|
{
|
|
SDL_GL_SwapBuffers();
|
|
lastT = t;
|
|
}
|
|
#endif
|
|
time_update();
|
|
t = time_now();
|
|
framecount++;
|
|
}
|
|
// Faster exit, thanks to the OS. Remove this if you want to debug shutdown
|
|
// The speed difference is only really noticable on Linux. On Windows you do notice it though
|
|
#ifdef _WIN32
|
|
exit(0);
|
|
#endif
|
|
NativeShutdownGraphics();
|
|
SDL_PauseAudio(1);
|
|
SDL_CloseAudio();
|
|
NativeShutdown();
|
|
#ifdef EGL
|
|
EGL_Close();
|
|
#endif
|
|
SDL_Quit();
|
|
net::Shutdown();
|
|
exit(0);
|
|
return 0;
|
|
}
|