mirror of https://github.com/bjornbytes/lovr.git
Clean up os_android and fix event polling issues;
This commit is contained in:
parent
eb008935e8
commit
29f8365eed
|
@ -12,55 +12,18 @@
|
|||
#include <android_native_app_glue.c>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
// The activity is considered ready if it's resumed and there's an active window. This is just an
|
||||
// artifact of how Oculus' app model works and could be the wrong abstraction, feel free to change.
|
||||
typedef void (*activeCallback)(bool active);
|
||||
|
||||
static struct {
|
||||
struct android_app* app;
|
||||
ANativeWindow* window;
|
||||
bool resumed;
|
||||
JNIEnv* jni;
|
||||
EGLDisplay display;
|
||||
EGLContext context;
|
||||
EGLSurface surface;
|
||||
activeCallback onActive;
|
||||
quitCallback onQuit;
|
||||
pthread_t log;
|
||||
} state;
|
||||
|
||||
// To make regular printing work, a thread makes a pipe and redirects stdout and stderr to the write
|
||||
// end of the pipe. The read end of the pipe is forwarded to __android_log_write.
|
||||
static void* log_main(void* data) {
|
||||
int* fd = data;
|
||||
pipe(fd);
|
||||
dup2(fd[1], STDOUT_FILENO);
|
||||
dup2(fd[1], STDERR_FILENO);
|
||||
setvbuf(stdout, 0, _IOLBF, 0);
|
||||
setvbuf(stderr, 0, _IONBF, 0);
|
||||
ssize_t length;
|
||||
char buffer[1024];
|
||||
while ((length = read(fd[0], buffer, sizeof(buffer) - 1)) > 0) {
|
||||
buffer[length] = '\0';
|
||||
__android_log_write(ANDROID_LOG_DEBUG, "LOVR", buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void onAppCmd(struct android_app* app, int32_t cmd) {
|
||||
bool wasActive = state.window && state.resumed;
|
||||
|
||||
switch (cmd) {
|
||||
case APP_CMD_RESUME: state.resumed = true; break;
|
||||
case APP_CMD_PAUSE: state.resumed = false; break;
|
||||
case APP_CMD_INIT_WINDOW: state.window = app->window; break;
|
||||
case APP_CMD_TERM_WINDOW: state.window = NULL; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
bool active = state.window && state.resumed;
|
||||
if (state.onActive && wasActive != active) {
|
||||
state.onActive(active);
|
||||
if (cmd == APP_CMD_DESTROY && state.onQuit) {
|
||||
state.onQuit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,9 +32,7 @@ int main(int argc, char** argv);
|
|||
void android_main(struct android_app* app) {
|
||||
state.app = app;
|
||||
(*app->activity->vm)->AttachCurrentThread(app->activity->vm, &state.jni, NULL);
|
||||
int fd[2];
|
||||
pthread_create(&state.log, NULL, log_main, fd);
|
||||
pthread_detach(state.log);
|
||||
lovrPlatformOpenConsole();
|
||||
app->onAppCmd = onAppCmd;
|
||||
main(0, NULL);
|
||||
(*app->activity->vm)->DetachCurrentThread(app->activity->vm);
|
||||
|
@ -119,18 +80,56 @@ void lovrPlatformSleep(double seconds) {
|
|||
}
|
||||
|
||||
void lovrPlatformPollEvents() {
|
||||
int events;
|
||||
struct android_poll_source* source;
|
||||
bool active = state.window && state.resumed;
|
||||
while (ALooper_pollAll(active ? 0 : 0, NULL, &events, (void**) &source) >= 0) {
|
||||
if (source) {
|
||||
source->process(state.app, source);
|
||||
// Notes about polling:
|
||||
// - Stop polling if a destroy is requested to give the application a chance to shut down.
|
||||
// Otherwise this loop would still wait for an event and the app would seem unresponsive.
|
||||
// - Block if the app is paused or no window is present
|
||||
// - If the app was active and becomes inactive after an event, break instead of waiting for
|
||||
// another event. This gives the main loop a chance to respond (e.g. exit VR mode).
|
||||
while (!state.app->destroyRequested) {
|
||||
int events;
|
||||
struct android_poll_source* source;
|
||||
int timeout = (state.app->window && state.app->activityState == APP_CMD_RESUME) ? 0 : -1;
|
||||
if (ALooper_pollAll(timeout, NULL, &events, (void**) &source) >= 0) {
|
||||
if (source) {
|
||||
source->process(state.app, source);
|
||||
}
|
||||
|
||||
if (timeout == 0 && (!state.app->window || state.app->activityState != APP_CMD_RESUME)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To make regular printing work, a thread makes a pipe and redirects stdout and stderr to the write
|
||||
// end of the pipe. The read end of the pipe is forwarded to __android_log_write.
|
||||
static struct {
|
||||
int handles[2];
|
||||
pthread_t thread;
|
||||
} log;
|
||||
|
||||
static void* log_main(void* data) {
|
||||
int* fd = data;
|
||||
pipe(fd);
|
||||
dup2(fd[1], STDOUT_FILENO);
|
||||
dup2(fd[1], STDERR_FILENO);
|
||||
setvbuf(stdout, 0, _IOLBF, 0);
|
||||
setvbuf(stderr, 0, _IONBF, 0);
|
||||
ssize_t length;
|
||||
char buffer[1024];
|
||||
while ((length = read(fd[0], buffer, sizeof(buffer) - 1)) > 0) {
|
||||
buffer[length] = '\0';
|
||||
__android_log_write(ANDROID_LOG_DEBUG, "LOVR", buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lovrPlatformOpenConsole() {
|
||||
// TODO
|
||||
pthread_create(&log.thread, NULL, log_main, log.handles);
|
||||
pthread_detach(log.thread);
|
||||
}
|
||||
|
||||
size_t lovrPlatformGetHomeDirectory(char* buffer, size_t size) {
|
||||
|
@ -326,16 +325,16 @@ bool lovrPlatformIsKeyDown(KeyCode key) {
|
|||
|
||||
// Private, must be declared manually to use
|
||||
|
||||
void lovrPlatformOnActive(activeCallback callback) {
|
||||
state.onActive = callback;
|
||||
}
|
||||
|
||||
struct ANativeActivity* lovrPlatformGetActivity() {
|
||||
return state.app->activity;
|
||||
}
|
||||
|
||||
int lovrPlatformGetActivityState() {
|
||||
return state.app->activityState;
|
||||
}
|
||||
|
||||
ANativeWindow* lovrPlatformGetNativeWindow() {
|
||||
return state.window;
|
||||
return state.app->window;
|
||||
}
|
||||
|
||||
JNIEnv* lovrPlatformGetJNI() {
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
#define GL_SRGB8_ALPHA8 0x8C43
|
||||
|
||||
// Private platform functions
|
||||
void lovrPlatformOnActive(void (*callback)(bool active));
|
||||
JNIEnv* lovrPlatformGetJNI(void);
|
||||
struct ANativeActivity* lovrPlatformGetActivity(void);
|
||||
int lovrPlatformGetActivityState(void);
|
||||
ANativeWindow* lovrPlatformGetNativeWindow(void);
|
||||
EGLDisplay lovrPlatformGetEGLDisplay(void);
|
||||
EGLContext lovrPlatformGetEGLContext(void);
|
||||
|
@ -52,27 +52,6 @@ static struct {
|
|||
float hapticDuration[2];
|
||||
} state;
|
||||
|
||||
static void onActive(bool active) {
|
||||
if (!state.session && active) {
|
||||
ovrModeParms config = vrapi_DefaultModeParms(&state.java);
|
||||
config.Flags &= ~VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN;
|
||||
config.Flags |= VRAPI_MODE_FLAG_NATIVE_WINDOW;
|
||||
config.Flags |= VRAPI_MODE_FLAG_FRONT_BUFFER_SRGB;
|
||||
config.Display = (size_t) lovrPlatformGetEGLDisplay();
|
||||
config.WindowSurface = (size_t) lovrPlatformGetNativeWindow();
|
||||
config.ShareContext = (size_t) lovrPlatformGetEGLContext();
|
||||
state.session = vrapi_EnterVrMode(&config);
|
||||
state.frameIndex = 0;
|
||||
if (state.deviceType == VRAPI_DEVICE_TYPE_OCULUSQUEST) {
|
||||
vrapi_SetTrackingSpace(state.session, VRAPI_TRACKING_SPACE_STAGE);
|
||||
state.offset = 0.f;
|
||||
}
|
||||
} else if (state.session && !active) {
|
||||
vrapi_LeaveVrMode(state.session);
|
||||
state.session = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool vrapi_init(float offset, uint32_t msaa) {
|
||||
ANativeActivity* activity = lovrPlatformGetActivity();
|
||||
state.java.Vm = activity->vm;
|
||||
|
@ -85,16 +64,20 @@ static bool vrapi_init(float offset, uint32_t msaa) {
|
|||
return false;
|
||||
}
|
||||
state.deviceType = vrapi_GetSystemPropertyInt(&state.java, VRAPI_SYS_PROP_DEVICE_TYPE);
|
||||
lovrPlatformOnActive(onActive);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vrapi_destroy() {
|
||||
if (state.session) {
|
||||
vrapi_LeaveVrMode(state.session);
|
||||
}
|
||||
vrapi_DestroyTextureSwapChain(state.swapchain);
|
||||
vrapi_Shutdown();
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
lovrRelease(Canvas, state.canvases[i]);
|
||||
}
|
||||
free(state.rawBoundaryPoints);
|
||||
free(state.boundaryPoints);
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
|
@ -431,6 +414,30 @@ static void vrapi_renderTo(void (*callback)(void*), void* userdata) {
|
|||
}
|
||||
|
||||
static void vrapi_update(float dt) {
|
||||
int appState = lovrPlatformGetActivityState();
|
||||
ANativeWindow* window = lovrPlatformGetNativeWindow();
|
||||
|
||||
if (!state.session && appState == APP_CMD_RESUME && window) {
|
||||
printf("Entering VR\n");
|
||||
ovrModeParms config = vrapi_DefaultModeParms(&state.java);
|
||||
config.Flags &= ~VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN;
|
||||
config.Flags |= VRAPI_MODE_FLAG_NATIVE_WINDOW;
|
||||
config.Flags |= VRAPI_MODE_FLAG_FRONT_BUFFER_SRGB;
|
||||
config.Display = (size_t) lovrPlatformGetEGLDisplay();
|
||||
config.ShareContext = (size_t) lovrPlatformGetEGLContext();
|
||||
config.WindowSurface = (size_t) window;
|
||||
state.session = vrapi_EnterVrMode(&config);
|
||||
state.frameIndex = 0;
|
||||
if (state.deviceType == VRAPI_DEVICE_TYPE_OCULUSQUEST) {
|
||||
vrapi_SetTrackingSpace(state.session, VRAPI_TRACKING_SPACE_STAGE);
|
||||
state.offset = 0.f;
|
||||
}
|
||||
} else if (state.session && (appState != APP_CMD_RESUME || !window)) {
|
||||
printf("Leaving VR\n");
|
||||
vrapi_LeaveVrMode(state.session);
|
||||
state.session = NULL;
|
||||
}
|
||||
|
||||
if (!state.session) return;
|
||||
|
||||
VRAPI_LARGEST_EVENT_TYPE event;
|
||||
|
|
Loading…
Reference in New Issue