2025-08-27 15:09:05 +09:00
|
|
|
#include <jni.h>
|
2025-08-26 13:32:53 +09:00
|
|
|
#include <android/native_window.h>
|
2025-08-26 18:24:06 +09:00
|
|
|
#include <android/native_window_jni.h>
|
2025-08-26 13:32:53 +09:00
|
|
|
#include <android/log.h>
|
2025-08-26 18:24:06 +09:00
|
|
|
#include <thread>
|
2025-08-27 15:09:05 +09:00
|
|
|
#include "Renderer.h"
|
|
|
|
|
#include "Preloader.h"
|
2025-08-26 18:24:06 +09:00
|
|
|
|
2025-08-26 13:32:53 +09:00
|
|
|
#define LOG_TAG "NativeRenderer"
|
|
|
|
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
|
|
|
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
// 전역 변수
|
|
|
|
|
Renderer* renderer = nullptr;
|
|
|
|
|
Preloader* preloader = nullptr;
|
|
|
|
|
JavaVM* g_vm = nullptr;
|
|
|
|
|
jobject g_callback_obj = nullptr;
|
|
|
|
|
jmethodID g_callback_method_id = nullptr;
|
2025-08-26 18:24:06 +09:00
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
// JNI_OnLoad 함수
|
|
|
|
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|
|
|
|
g_vm = vm;
|
|
|
|
|
return JNI_VERSION_1_6;
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
void callNextMediaCallback() {
|
|
|
|
|
JNIEnv* env;
|
|
|
|
|
bool isAttached = false;
|
|
|
|
|
// 현재 스레드가 JVM에 연결되어 있지 않다면 연결
|
|
|
|
|
if (g_vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
|
|
|
|
|
g_vm->AttachCurrentThread(&env, nullptr);
|
|
|
|
|
isAttached = true;
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
if (g_callback_obj && g_callback_method_id) {
|
|
|
|
|
env->CallVoidMethod(g_callback_obj, g_callback_method_id);
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
// 이전에 연결되지 않았다면 연결 해제
|
|
|
|
|
if (isAttached) {
|
|
|
|
|
g_vm->DetachCurrentThread();
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
extern "C" {
|
2025-08-26 18:24:06 +09:00
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
JNIEXPORT jboolean JNICALL
|
|
|
|
|
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeInit(JNIEnv* env, jobject) {
|
|
|
|
|
if (!renderer) {
|
|
|
|
|
renderer = new Renderer();
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
2025-08-27 15:09:05 +09:00
|
|
|
if (!preloader) {
|
|
|
|
|
preloader = new Preloader();
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
2025-08-27 15:09:05 +09:00
|
|
|
LOGI("Native renderer and preloader initialized.");
|
|
|
|
|
return JNI_TRUE;
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
JNIEXPORT void JNICALL
|
|
|
|
|
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeRender(JNIEnv* env, jobject, jobject surface) {
|
|
|
|
|
if (!renderer || !surface) return;
|
2025-08-26 18:24:06 +09:00
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
|
|
|
|
|
if (!window) {
|
|
|
|
|
LOGE("Could not get ANativeWindow from Surface.");
|
2025-08-26 13:32:53 +09:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
renderer->renderFrame(window);
|
2025-08-26 13:32:53 +09:00
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
ANativeWindow_release(window);
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
2025-08-26 13:32:53 +09:00
|
|
|
|
2025-08-26 18:24:06 +09:00
|
|
|
JNIEXPORT void JNICALL
|
2025-08-27 15:09:05 +09:00
|
|
|
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeDestroy(JNIEnv* env, jobject) {
|
|
|
|
|
if (renderer) {
|
|
|
|
|
delete renderer;
|
|
|
|
|
renderer = nullptr;
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
2025-08-27 15:09:05 +09:00
|
|
|
if (preloader) {
|
|
|
|
|
delete preloader;
|
|
|
|
|
preloader = nullptr;
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
2025-08-27 15:09:05 +09:00
|
|
|
if (g_callback_obj) {
|
|
|
|
|
env->DeleteGlobalRef(g_callback_obj);
|
|
|
|
|
g_callback_obj = nullptr;
|
|
|
|
|
}
|
|
|
|
|
LOGI("Native renderer destroyed and memory freed.");
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
JNIEXPORT void JNICALL
|
2025-08-27 15:09:05 +09:00
|
|
|
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetCurrentMedia(JNIEnv* env, jobject, jint fd) {
|
|
|
|
|
if (!renderer) return;
|
|
|
|
|
// 경로 대신 파일 디스크립터를 전달
|
|
|
|
|
renderer->setNextMedia(fd);
|
2025-08-26 13:32:53 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
JNIEXPORT void JNICALL
|
|
|
|
|
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartNextPreload(JNIEnv* env, jobject, jint fd) {
|
|
|
|
|
if (!preloader) return;
|
|
|
|
|
// 경로 대신 파일 디스크립터를 전달
|
|
|
|
|
preloader->startNextPreload(fd);
|
2025-08-26 13:32:53 +09:00
|
|
|
}
|
2025-08-26 18:24:06 +09:00
|
|
|
|
|
|
|
|
JNIEXPORT void JNICALL
|
2025-08-27 15:09:05 +09:00
|
|
|
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetNextMediaCallback(JNIEnv* env, jobject, jobject callback) {
|
|
|
|
|
jclass clazz = env->GetObjectClass(callback);
|
|
|
|
|
g_callback_method_id = env->GetMethodID(clazz, "onNextMediaRequested", "()V");
|
|
|
|
|
g_callback_obj = env->NewGlobalRef(callback);
|
2025-08-26 18:24:06 +09:00
|
|
|
|
2025-08-27 15:09:05 +09:00
|
|
|
if (!g_callback_method_id) {
|
|
|
|
|
LOGE("Could not find onNextMediaRequested method ID.");
|
2025-08-26 18:24:06 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-27 15:09:05 +09:00
|
|
|
}
|