/* Copyright 2015-2018 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. * * In no event and under no legal theory, whether in tort (including negligence), * contract, or otherwise, unless required by applicable law (such as deliberate * and grossly negligent acts) or agreed to in writing, shall any Contributor be * liable for any damages, including any direct, indirect, special, incidental, * or consequential damages of any character arising as a result of this License or * out of the use or inability to use the software (including but not limited to damages * for loss of goodwill, work stoppage, computer failure or malfunction, or any and * all other commercial damages or losses), even if such Contributor has been advised * of the possibility of such damages. */ #include "AndroidAppBase.hpp" #include "Timer.hpp" #include //#include //#include #include //#include namespace Diligent { int AndroidAppBase::InitDisplay() { if (!initialized_resources_) { Initialize(); LoadResources(); initialized_resources_ = true; } else { // initialize OpenGL ES and EGL if (EGL_SUCCESS != Resume(app_->window)) { UnloadResources(); LoadResources(); } } ShowUI(); //tap_camera_.SetFlip( 1.f, -1.f, -1.f ); //tap_camera_.SetPinchTransformFactor( 2.f, 2.f, 8.f ); return 0; } void AndroidAppBase::InitSensors() { sensor_manager_ = ASensorManager_getInstance(); accelerometer_sensor_ = ASensorManager_getDefaultSensor(sensor_manager_, ASENSOR_TYPE_ACCELEROMETER); sensor_event_queue_ = ASensorManager_createEventQueue(sensor_manager_, app_->looper, LOOPER_ID_USER, NULL, NULL); } // // Just the current frame in the display. // void AndroidAppBase::DrawFrame() { float fFPS; if (monitor_.Update(fFPS)) { UpdateFPS(fFPS); } static Diligent::Timer Timer; static double PrevTime = Timer.GetElapsedTime(); auto CurrTime = Timer.GetElapsedTime(); auto ElapsedTime = CurrTime - PrevTime; PrevTime = CurrTime; Update(CurrTime, ElapsedTime); Render(); Present(); //if( EGL_SUCCESS != pRenderDevice_->Present() ) //{ // UnloadResources(); // LoadResources(); //} } // // Process the next input event. // int32_t AndroidAppBase::HandleInput(android_app* app, AInputEvent* event) { AndroidAppBase* eng = (AndroidAppBase*)app->userData; return eng->HandleInput(event); } // // Process the next main command. // void AndroidAppBase::HandleCmd(struct android_app* app, int32_t cmd) { AndroidAppBase* eng = (AndroidAppBase*)app->userData; switch (cmd) { case APP_CMD_SAVE_STATE: break; case APP_CMD_INIT_WINDOW: // The window is being shown, get it ready. if (app->window != NULL) { eng->InitDisplay(); eng->DrawFrame(); } break; case APP_CMD_CONFIG_CHANGED: { // This callback is not reliable for handling orientation changes. Depending on the // device, it may be called before or after the surface has been actually resized. break; } // Note that as of NDK r21b (21.1.6352462), APP_CMD_WINDOW_RESIZED event is never generated // by android_native_app_glue. // Also note that modifying android_native_app_glue to handle onNativeWindowResized // callback (as suggested in https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html) // does not work either - the callback is only called once after the window has been created. case APP_CMD_WINDOW_RESIZED: { auto new_window_width = ANativeWindow_getWidth(app->window); auto new_window_height = ANativeWindow_getHeight(app->window); eng->WindowResize(new_window_width, new_window_height); break; } // Note that as of NDK r21b (21.1.6352462), APP_CMD_CONTENT_RECT_CHANGED event is never // generated by android_native_app_glue case APP_CMD_CONTENT_RECT_CHANGED: { auto new_window_width = app->contentRect.right - app->contentRect.left; auto new_window_height = app->contentRect.bottom - app->contentRect.top; eng->WindowResize(new_window_width, new_window_height); break; } case APP_CMD_TERM_WINDOW: // The window is being hidden or closed, clean it up. eng->TermDisplay(); eng->has_focus_ = false; break; case APP_CMD_STOP: break; case APP_CMD_GAINED_FOCUS: eng->ResumeSensors(); //Start animation eng->has_focus_ = true; break; case APP_CMD_LOST_FOCUS: eng->SuspendSensors(); // Also stop animating. eng->has_focus_ = false; break; case APP_CMD_LOW_MEMORY: //Free up GL resources eng->TrimMemory(); break; } } //------------------------------------------------------------------------- //Sensor handlers //------------------------------------------------------------------------- void AndroidAppBase::ProcessSensors(int32_t id) { // If a sensor has data, process it now. if (id == LOOPER_ID_USER) { if (accelerometer_sensor_ != NULL) { ASensorEvent event; while (ASensorEventQueue_getEvents(sensor_event_queue_, &event, 1) > 0) { } } } } void AndroidAppBase::ResumeSensors() { // When our app gains focus, we start monitoring the accelerometer. if (accelerometer_sensor_ != NULL) { ASensorEventQueue_enableSensor(sensor_event_queue_, accelerometer_sensor_); // We'd like to get 60 events per second (in us). ASensorEventQueue_setEventRate(sensor_event_queue_, accelerometer_sensor_, (1000L / 60) * 1000); } } void AndroidAppBase::SuspendSensors() { // When our app loses focus, we stop monitoring the accelerometer. // This is to avoid consuming battery while not being used. if (accelerometer_sensor_ != NULL) { ASensorEventQueue_disableSensor(sensor_event_queue_, accelerometer_sensor_); } } //------------------------------------------------------------------------- //Misc //------------------------------------------------------------------------- void AndroidAppBase::SetState(android_app* state, const char* native_activity_class_name) { app_ = state; native_activity_class_name_ = native_activity_class_name; doubletap_detector_.SetConfiguration(app_->config); drag_detector_.SetConfiguration(app_->config); pinch_detector_.SetConfiguration(app_->config); } bool AndroidAppBase::IsReady() { if (has_focus_) return true; return false; } //void Engine::TransformPosition( ndk_helper::Vec2& vec ) //{ // vec = ndk_helper::Vec2( 2.0f, 2.0f ) * vec // / ndk_helper::Vec2( pDeviceContext_->GetMainBackBufferDesc().Width, pDeviceContext_->GetMainBackBufferDesc().Height ) // - ndk_helper::Vec2( 1.f, 1.f ); //} void AndroidAppBase::ShowUI() { JNIEnv* jni; app_->activity->vm->AttachCurrentThread(&jni, NULL); //Default class retrieval jclass clazz = jni->GetObjectClass(app_->activity->clazz); jmethodID methodID = jni->GetMethodID(clazz, "showUI", "()V"); jni->CallVoidMethod(app_->activity->clazz, methodID); app_->activity->vm->DetachCurrentThread(); return; } void AndroidAppBase::UpdateFPS(float fFPS) { JNIEnv* jni; app_->activity->vm->AttachCurrentThread(&jni, NULL); //Default class retrieval jclass clazz = jni->GetObjectClass(app_->activity->clazz); jmethodID methodID = jni->GetMethodID(clazz, "updateFPS", "(F)V"); jni->CallVoidMethod(app_->activity->clazz, methodID, fFPS); app_->activity->vm->DetachCurrentThread(); return; } } // namespace Diligent