#include "il2cpp-config.h"
|
#include "il2cpp-api.h"
|
|
#if IL2CPP_TARGET_LUMIN && IL2CPP_TARGET_LUMIN_AUTOMATION
|
#include "Automation.h"
|
|
#include <atomic>
|
#include <chrono>
|
#include <thread>
|
|
#ifndef EGL_EGLEXT_PROTOTYPES
|
#define EGL_EGLEXT_PROTOTYPES
|
#endif
|
|
#include <EGL/egl.h>
|
#include <EGL/eglext.h>
|
|
#ifndef GL_GLEXT_PROTOTYPES
|
#define GL_GLEXT_PROTOTYPES
|
#endif
|
|
#include <GLES3/gl3.h>
|
#include <GLES3/gl3ext.h>
|
|
#define ML_DEFAULT_LOG_TAG "il2cpp"
|
|
#include "ml_graphics.h"
|
#include "ml_head_tracking.h"
|
#include "ml_lifecycle.h"
|
#include "ml_logging.h"
|
#include "ml_perception.h"
|
|
static void onStopWrapper(void* app_ctx);
|
static void onPauseWrapper(void *app_ctx);
|
static void onResumeWrapper(void *app_ctx);
|
|
static std::thread s_app_thread;
|
|
namespace il2cpp
|
{
|
namespace os
|
{
|
namespace lumin
|
{
|
namespace automation
|
{
|
class app_ctx_t;
|
|
static app_ctx_t* s_app;
|
|
class app_ctx_t
|
{
|
public:
|
app_ctx_t();
|
~app_ctx_t();
|
|
bool init();
|
|
void main_loop();
|
void on_stop();
|
void on_pause();
|
void on_resume();
|
|
void makeCurrent();
|
void releaseCurrent();
|
private:
|
EGLContext context;
|
EGLDisplay display;
|
|
MLHandle graphics_client;
|
|
std::atomic_int op_mode;
|
};
|
|
app_ctx_t::app_ctx_t() :
|
graphics_client(ML_INVALID_HANDLE),
|
op_mode(0)
|
{
|
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
eglInitialize(display, nullptr, nullptr);
|
eglBindAPI(EGL_OPENGL_ES_API);
|
|
EGLint config_attribs[] = {
|
EGL_RED_SIZE, 5,
|
EGL_GREEN_SIZE, 6,
|
EGL_BLUE_SIZE, 5,
|
EGL_ALPHA_SIZE, 0,
|
EGL_DEPTH_SIZE, 24,
|
EGL_STENCIL_SIZE, 8,
|
EGL_NONE
|
};
|
EGLConfig egl_config = nullptr;
|
EGLint config_size = 0;
|
eglChooseConfig(display, config_attribs, &egl_config, 1, &config_size);
|
|
EGLint context_attribs[] = {
|
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
EGL_CONTEXT_MINOR_VERSION_KHR, 0,
|
EGL_NONE
|
};
|
context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
|
}
|
|
app_ctx_t::~app_ctx_t()
|
{
|
eglDestroyContext(display, context);
|
eglTerminate(display);
|
}
|
|
bool app_ctx_t::init()
|
{
|
MLLifecycleCallbacks cbs = {0};
|
cbs.on_stop = &onStopWrapper;
|
cbs.on_pause = &onPauseWrapper;
|
cbs.on_resume = &onResumeWrapper;
|
|
if (MLLifecycleInit(&cbs, static_cast<void*>(this)) != MLResult_Ok)
|
{
|
ML_LOG(Error, "[il2cpp_automation]: failed to initialize lifecycle");
|
return false;
|
}
|
|
// initialize perception system
|
MLPerceptionSettings perception_settings;
|
if (MLResult_Ok != MLPerceptionInitSettings(&perception_settings))
|
{
|
ML_LOG(Error, "[il2cpp_automation]: Failed to initialize perception.");
|
}
|
|
if (MLResult_Ok != MLPerceptionStartup(&perception_settings))
|
{
|
ML_LOG(Error, "[il2cpp_automation]: Failed to startup perception.");
|
return false;
|
}
|
|
return true;
|
}
|
|
void app_ctx_t::main_loop()
|
{
|
on_resume();
|
|
makeCurrent();
|
|
// Get ready to connect our GL context to the MLSDK graphics API
|
MLGraphicsOptions graphics_options = { 0, MLSurfaceFormat_RGBA8UNorm, MLSurfaceFormat_D32Float };
|
MLHandle opengl_context = reinterpret_cast<MLHandle>(context);
|
|
MLGraphicsCreateClientGL(&graphics_options, opengl_context, &graphics_client);
|
|
GLuint framebuffer_id;
|
glGenFramebuffers(1, &framebuffer_id);
|
|
MLHandle head_tracker;
|
MLResult head_track_result = MLHeadTrackingCreate(&head_tracker);
|
MLHeadTrackingStaticData head_static_data;
|
if (MLResult_Ok == head_track_result && MLHandleIsValid(head_tracker))
|
{
|
MLHeadTrackingGetStaticData(head_tracker, &head_static_data);
|
}
|
else
|
{
|
ML_LOG(Error, "[il2cpp_automation]: Failed to create head tracker.");
|
}
|
|
ML_LOG(Info, "[il2cpp_automation]: Start loop.");
|
|
auto start = std::chrono::steady_clock::now();
|
|
do
|
{
|
MLGraphicsFrameParams frame_params;
|
|
MLResult out_result = MLGraphicsInitFrameParams(&frame_params);
|
if (MLResult_Ok != out_result)
|
{
|
ML_LOG(Error, "MLGraphicsInitFrameParams complained: %d", out_result);
|
}
|
frame_params.surface_scale = 1.0f;
|
frame_params.far_clip = 100.0f;
|
frame_params.near_clip = 0.37f;
|
frame_params.focus_distance = 100.0f;
|
|
MLHandle frame_handle = ML_INVALID_HANDLE;
|
MLGraphicsVirtualCameraInfoArray virtual_camera_array;
|
out_result = MLGraphicsBeginFrame(graphics_client, &frame_params, &frame_handle, &virtual_camera_array);
|
if (MLResult_Ok != out_result)
|
{
|
static bool loggedBeginFrameFailure = false;
|
if (!loggedBeginFrameFailure)
|
{
|
ML_LOG(Error, "MLGraphicsInitFrameParams complained: %d", out_result);
|
loggedBeginFrameFailure = true;
|
}
|
if (((int)op_mode) > 0)
|
continue; // early out if we fail to acquire a frame.
|
else
|
break;
|
}
|
|
auto msRuntime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
auto factor = labs(msRuntime % 2000 - 1000) / 1000.0;
|
|
for (int camera = 0; camera < 2; ++camera)
|
{
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
|
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, virtual_camera_array.color_id, 0, camera);
|
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, virtual_camera_array.depth_id, 0, camera);
|
|
const MLRectf& viewport = virtual_camera_array.viewport;
|
glViewport((GLint)viewport.x, (GLint)viewport.y,
|
(GLsizei)viewport.w, (GLsizei)viewport.h);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
if (camera == 0)
|
{
|
glClearColor(1.0 - factor, 0.0, 0.0, 0.0);
|
}
|
else
|
{
|
glClearColor(0.0, 0.0, factor, 0.0);
|
}
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
MLGraphicsSignalSyncObjectGL(graphics_client, virtual_camera_array.virtual_cameras[camera].sync_object);
|
}
|
out_result = MLGraphicsEndFrame(graphics_client, frame_handle);
|
if (MLResult_Ok != out_result)
|
{
|
ML_LOG(Error, "MLGraphicsEndFrame complained: %d", out_result);
|
}
|
}
|
while (((int)op_mode) > 0);
|
|
ML_LOG(Info, "[il2cpp_automation]: End loop.");
|
|
glDeleteFramebuffers(1, &framebuffer_id);
|
|
releaseCurrent();
|
|
// clean up system
|
MLGraphicsDestroyClient(&graphics_client);
|
MLPerceptionShutdown();
|
}
|
|
void app_ctx_t::on_stop()
|
{
|
op_mode = 0;
|
}
|
|
void app_ctx_t::on_pause()
|
{
|
op_mode = 1;
|
}
|
|
void app_ctx_t::on_resume()
|
{
|
op_mode = 2;
|
}
|
|
void app_ctx_t::makeCurrent()
|
{
|
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
|
}
|
|
void app_ctx_t::releaseCurrent()
|
{
|
eglMakeCurrent(NULL, EGL_NO_SURFACE, EGL_NO_SURFACE, NULL);
|
}
|
|
void Bootstrap()
|
{
|
il2cpp_set_data_dir("/package/Data");
|
il2cpp_set_config_dir("/package/Data/etc");
|
s_app = new app_ctx_t;
|
if (s_app->init())
|
{
|
s_app_thread = std::thread(&app_ctx_t::main_loop, s_app);
|
}
|
MLLifecycleSetReadyIndication();
|
}
|
|
void WaitForAppThread()
|
{
|
if (s_app)
|
s_app->on_stop();
|
if (s_app_thread.joinable())
|
s_app_thread.join();
|
delete s_app;
|
s_app = nullptr;
|
}
|
}
|
}
|
}
|
}
|
|
static void onStopWrapper(void* app_ctx)
|
{
|
auto ctx = static_cast<il2cpp::os::lumin::automation::app_ctx_t*>(app_ctx);
|
ctx->on_stop();
|
}
|
|
static void onPauseWrapper(void *app_ctx)
|
{
|
auto ctx = static_cast<il2cpp::os::lumin::automation::app_ctx_t*>(app_ctx);
|
ctx->on_pause();
|
}
|
|
static void onResumeWrapper(void *app_ctx)
|
{
|
auto ctx = static_cast<il2cpp::os::lumin::automation::app_ctx_t*>(app_ctx);
|
ctx->on_resume();
|
}
|
|
#endif //IL2CPP_TARGET_LUMIN_AUTOMATION
|