Возможно ли создать живые обои для Android только с использованием С++?
Или все же придется создавать WallpaperService на Java и связывать его с движком на С++?
ialexbr
Как разберешься, свистни!
Есть идея из NDK звать через JNI Java функциональность и создавать сервис. А чем тебя не устраивает немного на гавно Java пописать? я очень "люблю" гавно Java, но писал и смирился.
Andrey
> я очень "люблю" гавно Java
Не начинай :)
Andrey
Уже разобрался. Похоже, что без Java никак :(
Буду пробовать через JNI.
P.S. А ведь мне так понравилось на Native Activity, ни строчки на Java) Хотя на самом деле это тоже JNI вызовы, только гугловцы их за тебя написали. Работает быстро, так что ничего плохого в них нет)
ialexbr
Тут уместо перецитировать афоризм про boost про 3 степени эволюции программиста:
Сперва программист на Android учится писать на Java.
Потом программист на Android учится писать без Java на NativeActivity
И, наконец, программист на Android учится писать на Java и С++ без NativeActivity.
=A=L=X=
Аха, похоже я на грани 3 стадии :D
Появилось затруднение.. Пытаюсь создать контекст OpenGL ES 2, но вылетает ошибка при вызове функции eglCreateWindowSurface(lex::window.display, config, NULL, NULL). Я так понимаю, что это из-за того, что третьим аргументом вместо EGLNativeWindowType передаю NULL.
Не подскажите, что туда нужно передавать, если обои создаются без использования NativeActivity, а с помощью самописного WallpaperService на Java?
ialexbr
Нужно передавать ANativeWindow, как обычно. WallpaperService должен выглядеть примерно так:
public class LiveWallpaperService extends WallpaperService { @Override public Engine onCreateEngine() { return new LiveWallpaperEngine( ); } private class LiveWallpaperEngine extends Engine { private final NativeMethods nativeMethods = new NativeMethods( ); @Override public void onSurfaceCreated( SurfaceHolder holder) { super.onSurfaceCreated( holder); nativeMethods.windowCreated( holder.getSurface( )); } @Override public void onSurfaceDestroyed( SurfaceHolder holder) { nativeMethods.windowDestroyed( ); super.onSurfaceDestroyed( holder); } @Override public void onVisibilityChanged( boolean visible) { super.onVisibilityChanged( visible); nativeMethods.setPaused( !visible); } } }
_zerg_
Что-то не выходит.. Вызывает eglCreateWindowSurface и fatal signal 11.
Вот как делаю:
Java
public static native void AndroidLiveWallpapersCreate(Surface surface); @Override public void onSurfaceCreated( SurfaceHolder holder) { super.onSurfaceCreated( holder); lexlib.AndroidLiveWallpapersCreate( holder.getSurface( )); }
C++
class Window { ANativeWindow* nativewindow; EGLDisplay display; EGLContext context; EGLSurface surface; }; JNIEXPORT void JNICALL Java_lex_lexlib_lexlib_AndroidLiveWallpapersCreate(ANativeWindow* nativewindow) { lex::window.nativewindow = nativewindow; lex::OpenGLInit( ); void OpenGLInit( ) { const EGLint eglChooseConfigAttribList[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_NONE }; const EGLint eglCreateContextAttribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint format; EGLint numConfigs; EGLConfig config; if( ( lex::window.display = eglGetDisplay( EGL_DEFAULT_DISPLAY)) == NULL) { Log( "!!! eglGetDisplay()"); return; } if( !eglInitialize( lex::window.display, 0, 0)) { Log( "!!! eglInitialize()"); return; } if( !eglChooseConfig( lex::window.display, eglChooseConfigAttribList, &config, 1, &numConfigs)) { Log( "!!! eglChooseConfig()"); return; } if( !eglGetConfigAttrib( lex::window.display, config, EGL_NATIVE_VISUAL_ID, &format)) { Log( "!!! eglGetConfigAttrib()"); return; } if( ( lex::window.surface = eglCreateWindowSurface( lex::window.display, config, lex::window.nativewindow, NULL)) == NULL) { Log( "!!! eglCreateWindowSurface()"); return; } if( ( lex::window.context = eglCreateContext( lex::window.display, config, NULL, eglCreateContextAttribList)) == NULL) { Log( "!!! eglCreateContext()"); return; } if( eglMakeCurrent( lex::window.display, lex::window.surface, lex::window.surface, lex::window.context) == EGL_FALSE) { Log( "!!! eglMakeCurrent()"); return; } eglSwapInterval( lex::window.display, 0); }
ialexbr
Surface это еще не ANativeWindow. ANativeWindow нужно получить функцией ANativeWindow_fromSurface.
У нативного метода неправильная сигнатура. Должна быть
JNIEXPORT void JNICALL Java_lex_lexlib_lexlib_AndroidLiveWallpapersCreate(JNIEnv* env, jclass, jobject surface)
И еще надо проверять сколько конфигов нашла функция eglChooseConfig. Может быть так что она вернула true, но нашла 0 конфигов.
_zerg_
Спасибо, все заработало :)
Правда сейчас запустил вечный цикл в Java, который вызывает обновление логики и перерисовки в C++. И каждый кадр стал ловить EGL_BAD_CONTEXT.
Только сейчас понял, что создал контекст OpenGL в главном потоке, а функциями OpenGL пользуюсь в другом потоке.
Можно ли как-то запустить вечный цикл в главном потоке так, чтоб приходили события onVisibilityChanged и подобные?
ialexbr
Создавай поток на С++ (std::thread или pthread) и в нем запускай вечный цикл.
Моя реализация:
_zerg_
Вчера к этому же выводу пришел, спасибо, так и сделаю.
Тема в архиве.