寂寞啦,怀念小时候的胡同和弄堂啦,怎么办呢?就坐飞机去那些柯布西耶的科学还没照耀到的偏远古镇,旅游一下。
需要 Java 代码 和 C++ 代码协作,完成渲染,渲染的关键部分需要在 C++ 3D 引擎里面完成,这就需要用 egl 来粘连 Java & C++ 代码。
Java 端 MagicSurfaceView extends SurfaceView
。
开始的时候采用 GLSurfaceView
,然后 C++ 端创建 Window 会失败。因为 GLSurfaceView
已经默认创建了一个,不能重复创建。
正确的做法是:
Surface surface = getHolder().getSurface();
AssetManager assetmgr = getContext().getAssets();
DisplayMetrics metrics = getResources().getDisplayMetrics();
IrrlichtJNI.nativeInitGL(surface, assetmgr, metrics, getWidth(), getHeight());
然后 C++ 端拿到 surface 对象后,
#include <android/native_window_jni.h>
#include <android/native_window.h>
AAssetManager *assetManager = AAssetManager_fromJava(env, assetmgr);
ANativeWindow *window = ANativeWindow_fromSurface(env, surface); // 创建 window 对象
...
eglCreateWindowSurface...
// nativeWindow 不用了要释放
ANativeWindow *nativeWindow = gdevice->getANativeWindow();
ANativeWindow_release(nativeWindow);
现在的问题是,Irrlicht 崩溃了,崩溃的很突然,还莫名其妙:
bool CEGLManager::generateSurface() {
if (EglDisplay == EGL_NO_DISPLAY)
return false;
if (EglSurface != EGL_NO_SURFACE)
return true;
// We should assign new WindowID on platforms, where WindowID may change at runtime,
// at this time only Android support this feature.
// this needs an update method instead!
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EglWindow = (ANativeWindow*) Data.OGLESAndroid.Window;
#endif
#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
// eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing)
// But the other solution would also be fine as it also only generates a single context so there is not much to choose from.
EglConfig = chooseConfig(ECS_IRR_CHOOSE);
#else
EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
#endif
if ( EglConfig == 0 ) {
os::Printer::log("Could not get config for EGL display.");
return false;
}
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EGLint Format = 0;
eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &Format);
ANativeWindow_setBuffersGeometry(EglWindow, 0, 0, Format);
#endif
// Now we are able to create EGL surface.
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0);
if (EGL_NO_SURFACE == EglSurface)
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, 0, 0);
if (EGL_NO_SURFACE == EglSurface)
os::Printer::log("Could not create EGL surface.");
#ifdef EGL_VERSION_1_2
if (MinorVersion > 1)
eglBindAPI(EGL_OPENGL_ES_API);
#endif
if (Params.Vsync)
eglSwapInterval(EglDisplay, 1);
return true;
}
bool CEGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) {
if (!bEglMakeCurrent) {
// 成功调用一次就可以了,频繁调用 Adreno 貌似容易崩溃。
eglMakeCurrent(EglDisplay, EglSurface, EglSurface, EglContext);
bEglMakeCurrent = eglGetError() == EGL_SUCCESS;
}
if (testEGLError()) {
os::Printer::log("Could not make EGL context current.");
return false;
}
return true;
}
Ogre 崩溃也崩溃了:
// RenderingAPIException: Fail to create EGLSurface based on NativeWindowType
// in createSurfaceFromWindow at RenderSystems/GLSupport/src/EGL/OgreEGLWindow.cpp (line 217)
// Ogre::Exception::ERR_RENDERINGAPI_ERROR
::EGLSurface EGLWindow::createSurfaceFromWindow(::EGLDisplay display, NativeWindowType win) {
::EGLSurface surface;
surface = eglCreateWindowSurface(display, mEglConfig, (EGLNativeWindowType) win, NULL);
EGL_CHECK_ERROR
if (surface == EGL_NO_SURFACE) {
OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
"Fail to create EGLSurface based on NativeWindowType");
}
return surface;
}
void EGLWindow::swapBuffers() {
if (mClosed || mIsExternalGLControl) {
return;
}
if (eglSwapBuffers(mEglDisplay, mEglSurface) == EGL_FALSE) {
EGL_CHECK_ERROR
OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Fail to SwapBuffers");
}
}
eglCreateWindowSurface
为啥会崩溃呢?研究发现参数 win 为空,那 win 为什么为空呢?ANativeWindow_fromSurface
返回了空?这个为什么返回空呢?public class IrrlichtGLView extends SurfaceView implements SurfaceHolder.Callback {
private boolean firstTime = true;
private boolean windowready = false;
public IrrlichtGLView(Context context) {
super(context);
getHolder().addCallback(this);
}
public IrrlichtGLView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
}
public IrrlichtGLView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getHolder().addCallback(this);
}
public void onDrawFrame() {
if (!windowready) {
return;
}
// render a frame
if (firstTime) {
Surface surface = getHolder().getSurface();
AssetManager assetmgr = getContext().getAssets();
DisplayMetrics metrics = getResources().getDisplayMetrics();
IrrlichtJNI.nativeInitGL(surface, assetmgr, metrics, getWidth(), getHeight());
firstTime = false;
}
IrrlichtJNI.nativeDrawIteration();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
windowready = true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int i, int j, int k) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}