【问题标题】:android ndk open gl es 2 setup without java没有java的android ndk打开gl es 2设置
【发布时间】:2014-12-09 15:10:33
【问题描述】:

我想制作一个 android 应用程序,它完全从本机代码中绘制打开的 gl 图形,换句话说,我在我的 c/c++ 代码中使用 native_app_glue

但是,我在互联网上找不到一个完全从本机代码指向使用 open gl 的资源! 我找到的所有链接都显示了如何在 java 中使用 GLSurfaceView,然后为每个 onDraw() 调用调用 C/C++ 的 JNI。这正是我不想做的!

即使ndk 中的hello-gl2 样本也使用相同的方法!

我确实了解原生应用程序胶水确实在幕后包含了一些 java 代码来启动活动,但我不希望在那之后有任何更频繁的 JNI 调用。

相反,我想在本机代码中设置屏幕的初始化和回调,我想在本机代码中设置显示表面及其相应的回调,而不是通过 java。

1.NDK中表示表面(或窗口显示)的数据结构是什么?

2.如何访问它们并获取显示的宽度和高度等属性(在本机代码中)?

3.如何在该显示器上绘制(由于没有绘制回调,我假设我需要创建一个循环来手动绘制调用,但在这种情况下,我如何知道最后一帧已完成渲染?)

【问题讨论】:

  • 您始终可以编译独立的可执行文件并通过 adb 推送它并从 adb shell 运行它(注意,我并不是说这是 Android 上原生开发的最佳已知方法,但它有可能)
  • 不,这不是我要找的!我编辑了标题以更清晰

标签: android c++ opengl-es android-ndk


【解决方案1】:

下面是一个简单的 C 程序(没有 Manifest/Java 等),它旋转一个三角形 20 秒。这只是为了提供信息(不是创建 Android 应用程序的推荐方式)。它需要对“图形”组的访问权限(如果您通过 ADB 运行它就是这种情况)。

如何编译:

1) 从http://developer.android.com/tools/sdk/ndk/index.html获取android NDK

2) 安装工具链:

  ./android-ndk-r9b/build/tools/make-standalone-toolchain.sh        \
      --platform=android-17 --toolchain=arm-linux-androideabi-4.7   \
      --system=linux-x86_64 --install-dir=where_you_want_to_install 

3) 从设备获取 libui.so:

  adb pull /system/lib/libui.so

4) 编译:

 arm-linux-androideabi-gcc main.c -lGLESv1_CM -lEGL -landroid -L. -lui -o gles_test

要运行该程序,您将需要访问“图形”组,如果您通过 ADB 运行它就是这种情况(但如果您从终端运行它,例如 TerminalIDE 则不需要)

/* Program largely inspired from:                                                            */
/* http://jiggawatt.org/badc0de/android/index.html                                           */
/* http://software.intel.com/en-us/articles/setting-up-native-opengl-es-on-android-platforms */
/* http://www.brucesutherland.co.uk/android-ndk/opengl-es-2-0-android-ndk-game-programming/  */

#include <stdio.h>
#include <stdlib.h>

#include <EGL/egl.h>
#include <GLES/gl.h>
#include <android/native_window.h>

#include <sys/types.h>
#include <sys/times.h> 


/* returns current time in seconds */
double now() {
    struct tms now_tms ;
    return (double)(times(&now_tms)) / 100.0 ;
}

/* from libui.so (get it from the device using adb pull /system/lib/libui.so) */
extern NativeWindowType android_createDisplaySurface();

NativeWindowType displayWindow;

const EGLint config16bpp[] = {
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
    EGL_SURFACE_TYPE,    EGL_WINDOW_BIT, 
    EGL_RED_SIZE,   5,
    EGL_GREEN_SIZE, 6,
    EGL_BLUE_SIZE,  5,
    EGL_NONE
};


const EGLint config24bpp[] = {
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
    EGL_SURFACE_TYPE,    EGL_WINDOW_BIT, 
    EGL_RED_SIZE,   8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE,  8,
    EGL_NONE
};

const EGLint config32bpp[] = {
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
    EGL_SURFACE_TYPE,    EGL_WINDOW_BIT, 
    EGL_RED_SIZE,   8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE,  8,
    EGL_ALPHA_SIZE, 8,
    EGL_NONE
};


GLfloat colors[3][4] = {
    {1.0f, 0.0f, 0.0f, 1.0f},
    {0.0f, 1.0f, 0.0f, 1.0f},
    {0.0f, 0.0f, 1.0f, 1.0f}
};

GLfloat vertices[3][3] = {
    {0.0f, 0.7f, 0.0f},
    {-0.7f, -0.7f, 0.0f},
    {0.7f, -0.7f, 0.0f}
};


void draw_tri() {
    glViewport(
        0,
        0,
        ANativeWindow_getWidth(displayWindow),
        ANativeWindow_getHeight(displayWindow)
    );
    glRotatef(0.5, 0, 0, 1) ;

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);

    glColorPointer(4, GL_FLOAT, 0, colors);
    glVertexPointer(3, GL_FLOAT, 0, vertices);

    /* Draw the triangle (3 vertices) */
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
}


int main(int argc, char** argv) {
    EGLint majorVersion, minorVersion;
    EGLContext eglContext;
    EGLSurface eglSurface;
    EGLConfig eglConfig;
    EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    EGLint format;
    const EGLint* config = NULL ;
    int numConfigs;
    int windowFormat;
    double start_time  = now() ;


    /* 
     * create a window surface that covers the entire screen.
     * This function is from libui. 
     */
    displayWindow = android_createDisplaySurface();

    eglInitialize(eglDisplay, &majorVersion, &minorVersion);
    printf("GL version: %d.%d\n",majorVersion,minorVersion);

    if(displayWindow == 0) {
       printf("Could not create window\n") ;
       printf("Started from an on-device shell ?\n") ;
       printf("use: adb shell <path_to_exe>/%s\n",argv[0]) ;
       exit(-1) ;
    }

    /* get the format of the window. */
    windowFormat = ANativeWindow_getFormat(displayWindow) ;

    printf("Window specs: %d*%d format=%d\n",
           ANativeWindow_getWidth(displayWindow),
           ANativeWindow_getHeight(displayWindow),
           windowFormat
    ) ;

    /* choose the config according to the format of the window. */
    switch(windowFormat) {
     case WINDOW_FORMAT_RGBA_8888:
       config = config32bpp ;
       break ;
     case WINDOW_FORMAT_RGBX_8888:
       config = config24bpp ;       
       break ;
     case WINDOW_FORMAT_RGB_565:
       config = config16bpp ;       
       break ;
     default:
       printf("Unknown window format\n") ;
       exit(-1) ;
    }

    if (!eglChooseConfig(eglDisplay, config32bpp, &eglConfig, 1, &numConfigs)) {
        printf("eglChooseConfig failed\n");
        if (eglContext==0) printf("Error code: %x\n", eglGetError());
        exit(-1) ;
    }

    eglContext = eglCreateContext(eglDisplay, eglConfig,  EGL_NO_CONTEXT, NULL);
    printf("GL context: %x\n", eglContext);
    if (eglContext==0) {
       printf("Error code: %x\n", eglGetError());
       exit(-1) ;
    }

    eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, displayWindow, NULL);

    printf("GL surface: %x\n", eglSurface);
    if (eglSurface==0) {
       printf("Error code: %x\n", eglGetError());
       exit(-1);
    }

    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

    printf(
        "Vendor: %s, Renderer: %s, Version: %s\n",
        glGetString(GL_VENDOR),
        glGetString(GL_RENDERER),
        glGetString(GL_VERSION)
    ) ;

    printf("Extensions: %s\n", glGetString(GL_EXTENSIONS)) ;

    printf("Spinning triangle for 20s\n") ;

    while (now() - start_time < 20.0) {
        draw_tri();
        eglSwapBuffers(eglDisplay, eglSurface);
    }

    printf("End (tap the screen of the phone to continue).\n") ;

    return 0;
}

【讨论】:

    【解决方案2】:

    查看 NDK 示例。这里有一个: \android-ndk\samples\native-activity

    在线链接: http://developer.android.com/reference/android/app/NativeActivity.html

    【讨论】:

    • 这是唯一有效的方法吗?我的意思是这些调用是 open gl 特定的,所以它们会干扰菜单等其他小部件吗?
    • 说真的,这些信息必须被挖掘出来,并且应该以比参考文献中的示例 sn-p 更好的方式记录下来!
    • android 使用什么 egl 版本(带有 gles2.0)?
    • IIRC,Android 在 4.2 (API 17) 之前提供了对 EGL 1.0 的支持,当时它添加了对 EGL 1.4 的支持。 EGL 上下文和表面是使用eglMakeCurrent() 为每个线程设置的,无论您是从Java 还是本地代码配置它都没有关系。设置完成后,您只需使用 GLES 绘制任何您想要的内容,然后调用 eglSwapBuffers() 来提交新缓冲区——来自 Java 代码、本机代码或两者的混合。 NativeActivity 类仅适用于不需要任何 Java 代码的人。
    • 那里有一些很好的信息!但是我怎么知道是时候交换缓冲区并绘制下一帧了(本机代码中没有 onDrawFrame,还是有?)
    猜你喜欢
    • 2017-01-17
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多