#include #include #include #include #include #include "Renderer.h" #include "Preloader.h" #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__) // --- ⬇️ 전역 렌더러, 프리로더 포인터 삭제! ⬇️ --- // Renderer* renderer = nullptr; // Preloader* preloader = nullptr; // JavaVM과 콜백 관련 전역 변수는 앱 프로세스 전체에서 유일하므로 유지합니다. JavaVM* g_vm = nullptr; jobject g_callback_obj = nullptr; jmethodID g_callback_method_id = nullptr; // JNI_OnLoad, callNextMediaCallback 함수는 기존과 동일 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { g_vm = vm; return JNI_VERSION_1_6; } void callNextMediaCallback() { JNIEnv* env; bool isAttached = false; // 현재 스레드가 JVM에 연결되어 있지 않다면 연결 if (g_vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { if (g_vm->AttachCurrentThread(&env, nullptr) != JNI_OK) { LOGE("Failed to attach current thread to JVM"); return; } isAttached = true; } if (g_callback_obj && g_callback_method_id) { env->CallVoidMethod(g_callback_obj, g_callback_method_id); } // 이전에 연결되지 않았다면 연결 해제 if (isAttached) { g_vm->DetachCurrentThread(); } } // C++ 객체 포인터를 jlong으로, jlong을 C++ 객체 포인터로 안전하게 변환하는 헬퍼 함수 template T* toNative(jlong handle) { return reinterpret_cast(handle); } extern "C" { // [수정] jboolean -> jlong. Renderer 객체를 생성하고 그 주소(핸들)를 반환 JNIEXPORT jlong JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeInit(JNIEnv* env, jobject) { // Preloader는 Renderer가 내부적으로 소유하도록 변경하는 것이 더 좋습니다. // 여기서는 간단하게 Renderer만 생성하여 핸들링합니다. Renderer* renderer = new Renderer(); LOGI("Native renderer instance created at address: %p", renderer); return reinterpret_cast(renderer); } // [수정] 핸들을 파라미터로 받아 해당 객체를 파괴 JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeDestroy(JNIEnv* env, jobject, jlong nativeHandle) { Renderer* renderer = toNative(nativeHandle); if (renderer) { LOGI("Destroying native renderer instance at address: %p", renderer); delete renderer; } } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStopRenderLoop(JNIEnv* env, jobject, jlong nativeHandle) { Renderer* renderer = toNative(nativeHandle); if (renderer) { renderer->stopRenderLoop(); } } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartRenderLoop(JNIEnv* env, jobject, jlong nativeHandle, jobject surface) { Renderer* renderer = toNative(nativeHandle); if (!renderer || !surface) return; ANativeWindow* window = ANativeWindow_fromSurface(env, surface); if (!window) { LOGE("Could not get ANativeWindow from Surface."); return; } ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBA_8888); renderer->startRenderLoop(window); ANativeWindow_release(window); } // [수정] 모든 함수가 nativeHandle을 첫 파라미터로 받도록 변경 JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeRender(JNIEnv* env, jobject, jlong nativeHandle, jobject surface) { Renderer* renderer = toNative(nativeHandle); if (!renderer || !surface) return; ANativeWindow* window = ANativeWindow_fromSurface(env, surface); if (!window) { LOGE("Could not get ANativeWindow from Surface."); return; } renderer->renderFrame(window); ANativeWindow_release(window); } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartNextPreload(JNIEnv* env, jobject, jlong nativeHandle, jint fd) { Renderer* renderer = toNative(nativeHandle); if (renderer) { // Preloader가 Renderer의 일부가 되었다고 가정하고 호출 (추후 Renderer 수정 필요) // 여기서는 간단하게 setNextMedia를 호출하는 것으로 변경합니다. renderer->setNextMedia(fd); } } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetAnimationSpeed(JNIEnv* env, jobject, jlong nativeHandle, jfloat speed) { Renderer* renderer = toNative(nativeHandle); if (renderer) { renderer->setAnimationSpeed(speed); } } // --- ⬇️ 새로 추가할 JNI 함수들 ⬇️ --- JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetAnimationMode(JNIEnv* env, jobject, jlong nativeHandle, jint mode) { Renderer* renderer = toNative(nativeHandle); if (renderer) { renderer->setAnimationMode(mode); } } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetTransitionMode(JNIEnv* env, jobject, jlong nativeHandle, jint mode) { Renderer* renderer = toNative(nativeHandle); if (renderer) { renderer->setTransitionMode(mode); } } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetFadeDuration(JNIEnv* env, jobject, jlong nativeHandle, jint duration) { Renderer* renderer = toNative(nativeHandle); if (renderer) { renderer->setFadeDuration(duration); } } JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetPageTurnDelay(JNIEnv* env, jobject, jlong nativeHandle, jint duration) { Renderer* renderer = toNative(nativeHandle); if (renderer) { renderer->setPageTurnDelay(duration); } } JNIEXPORT jstring JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeGetDebugInfo(JNIEnv* env, jobject, jlong nativeHandle) { Renderer* renderer = toNative(nativeHandle); if (renderer) { std::string debugInfo = renderer->getDebugInfo(); return env->NewStringUTF(debugInfo.c_str()); } return env->NewStringUTF("Renderer handle is invalid or null."); } // --- 참고: nativeSetNextMediaCallback은 전역이라 일단 그대로 둡니다 --- JNIEXPORT void JNICALL Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetNextMediaCallback(JNIEnv* env, jobject, jobject callback) { if (g_callback_obj) { env->DeleteGlobalRef(g_callback_obj); } g_callback_obj = env->NewGlobalRef(callback); jclass clazz = env->GetObjectClass(callback); g_callback_method_id = env->GetMethodID(clazz, "onNextMediaRequested", "()V"); if (!g_callback_method_id) { LOGE("Could not find onNextMediaRequested method ID."); } } } // extern "C"