android_multiviewwer/app/src/main/cpp/native_renderer.cpp

193 lines
6.9 KiB
C++
Raw Normal View History

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