5
回答
怎么在android上面做出根据形状来渐变的效果
百度AI开发者大赛带你边学边开发,赢100万奖金,加群:418589053   

小弟现在在一个powerpoint阅读器,现在遇到一个问题。相信大家用过ppt的都应该对渐变不陌生,像这个图片,在android上面没有

找到现成的api可以根据Path来做出渐变效果。请教各位,知道的帮忙解决一下,谢谢。

PS:是否用到高等数学里面的知识,像微分、矩阵之类的。

举报
老黄coding
发帖于6年前 5回/4K+阅
共有5个答案 最后回答: 6年前
如果你是用代码画出来的话  需要你有强的思维能力去画这个图,如果是配置的动画的画比较好办
--- 共有 2 条评论 ---
老黄coding像圆、矩形。但是像五角星这些按形状就不好搞了。另外动画的画实现方式又是怎么实现了。麻烦兄弟指点下,小弟在此感谢。 6年前 回复
老黄coding请教兄弟,因为阅读器的话查看的时候是静态的,如果用动画来实现好像不太合适。(也有可能是我理解的有问题吧)。因为android上面做渐变效果的,我发现只有LinearGradient、RadialGradient、SweepGradient这3类,通过画笔中setShader()可以实现比较规则图形的渐变。 6年前 回复

如果只是实现一种操作的动画感知,就用图片+动画就可以了。

如果是单独做这种效果的话,倒是可以挑战下,具体说说你的需求。


--- 共有 1 条评论 ---
老黄coding感谢这位兄弟。你说的是用图片+动画的方式,请问具体是怎么样实现的。就是单独做一种这样的效果。具体是这样的。渐变中,给一个颜色值(rgb值),还有这个颜色值所占的比例(是一个百分比)。还有给出一个形状的路径。怎么将这3类参数在android平台上面实现图片所显示的那种效果。如果兄弟能抽空帮忙下,小弟定当酬谢。 6年前 回复
更正一下上面的需求,是给定一组颜色值,如一个int数组,存储颜色的rgb值。还有一个float数组,存储颜色的比例值。这两个数组是一一对应的。然后再给出一个形状的路径。怎么讲这3类参数做出图片的效果。
opengl es 2.0用几行shader就完成,有那么复杂么,设置好5星的顶点坐标设定好颜色就搞定,不但硬件加速而且代码简单。不过能不能硬件加速还是看你的手机。
--- 共有 3 条评论 ---
老黄coding回复 @cut : 哥,你帮我弄好没。弄好了,小弟给你银行卡打100块。。。 6年前 回复
cut回复 @黄锦坤 : 一会哥下班回去给你给你发个hello三角形的渐变画法代码你自己慢慢研究,很简单的说,不过不是用3DMAX,MAYA那些工具设定,自己写顶点坐标的值,就一个蛋疼,哥就不给你搞五星了。 6年前 回复
老黄coding兄弟,我对android里面的opengl的api不熟悉,能否指点一下怎么set shader吗。因为路径有可能是不规则的图形,所以只能传一个形状的路径。 6年前 回复

 

 

 

 

 

 

 

 

 

 

 

这个是输出一层颜色渐变的效果,而你的是多层的,做法一样,弄几个小的的三角形同样的画法画到上面。而颜色的值是不可能是线性的值,你只能自己定义每层三角形的颜色,这个是你要做的。

这个我直接用NDK自带的HELLO-GL2给你弄的,就设置下三角形顶点和改了shader部分的代码而已。

原理很简单,设置5个顶点,第一个顶点为三角形中心顶点坐标,其他四的坐标为,三角形三个顶点坐标,其中第2和第5个顶点一样。绘制三角形的时候使用扇形绘制。

中间顶点一个颜色,其他4个顶点为另一个颜色。

多层渐变就加几个小点的三角形然后将颜色设置好覆盖上去。

下面是参考代码,哥OPENGL只用C++搞不好意思,转JAVA的话,你看SDK的文档去转。

/*  * Copyright (C) 2007 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */

package com.android.gl2jni;

import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.WindowManager;

import java.io.File;

public class GL2JNIActivity extends Activity {

    GL2JNIView mView;

    @Override protected void onCreate(Bundle icicle) {         super.onCreate(icicle);         mView = new GL2JNIView(getApplication());  setContentView(mView);     }

    @Override protected void onPause() {         super.onPause();         mView.onPause();     }

    @Override protected void onResume() {         super.onResume();         mView.onResume();     } }

 

/*  * Copyright (C) 2007 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */

package com.android.gl2jni;

// Wrapper for native library

public class GL2JNILib {

     static {          System.loadLibrary("gl2jni");      }

    /**      * @param width the current view width      * @param height the current view height      */      public static native void init(int width, int height);      public static native void step(); }

/*  * Copyright (C) 2009 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */

package com.android.gl2jni; /*  * Copyright (C) 2008 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */

import android.content.Context; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent;

import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10;

/**  * A simple GLSurfaceView sub-class that demonstrate how to perform  * OpenGL ES 2.0 rendering into a GL Surface. Note the following important  * details:  *  * - The class must use a custom context factory to enable 2.0 rendering.  *   See ContextFactory class definition below.  *  * - The class must use a custom EGLConfigChooser to be able to select  *   an EGLConfig that supports 2.0. This is done by providing a config  *   specification to eglChooseConfig() that has the attribute  *   EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag  *   set. See ConfigChooser class definition below.  *  * - The class must select the surface's format, then choose an EGLConfig  *   that matches it exactly (with regards to red/green/blue/alpha channels  *   bit depths). Failure to do so would result in an EGL_BAD_MATCH error.  */ class GL2JNIView extends GLSurfaceView {     private static String TAG = "GL2JNIView";     private static final boolean DEBUG = false;

    public GL2JNIView(Context context) {         super(context);         init(false, 0, 0);     }

    public GL2JNIView(Context context, boolean translucent, int depth, int stencil) {         super(context);         init(translucent, depth, stencil);     }

    private void init(boolean translucent, int depth, int stencil) {

        /* By default, GLSurfaceView() creates a RGB_565 opaque surface.          * If we want a translucent one, we should change the surface's          * format here, using PixelFormat.TRANSLUCENT for GL Surfaces          * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.          */         if (translucent) {             this.getHolder().setFormat(PixelFormat.TRANSLUCENT);         }

        /* Setup the context factory for 2.0 rendering.          * See ContextFactory class definition below          */         setEGLContextFactory(new ContextFactory());

        /* We need to choose an EGLConfig that matches the format of          * our surface exactly. This is going to be done in our          * custom config chooser. See ConfigChooser class definition          * below.          */         setEGLConfigChooser( translucent ?                              new ConfigChooser(8, 8, 8, 8, depth, stencil) :                              new ConfigChooser(5, 6, 5, 0, depth, stencil) );

        /* Set the renderer responsible for frame rendering */         setRenderer(new Renderer());     }

    private static class ContextFactory implements GLSurfaceView.EGLContextFactory {         private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {             Log.w(TAG, "creating OpenGL ES 2.0 context");             checkEglError("Before eglCreateContext", egl);             int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };             EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);             checkEglError("After eglCreateContext", egl);             return context;         }

        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {             egl.eglDestroyContext(display, context);         }     }

    private static void checkEglError(String prompt, EGL10 egl) {         int error;         while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {             Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));         }     }

    private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {

        public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {             mRedSize = r;             mGreenSize = g;             mBlueSize = b;             mAlphaSize = a;             mDepthSize = depth;             mStencilSize = stencil;         }

        /* This EGL config specification is used to specify 2.0 rendering.          * We use a minimum size of 4 bits for red/green/blue, but will          * perform actual matching in chooseConfig() below.          */         private static int EGL_OPENGL_ES2_BIT = 4;         private static int[] s_configAttribs2 =         {             EGL10.EGL_RED_SIZE, 4,             EGL10.EGL_GREEN_SIZE, 4,             EGL10.EGL_BLUE_SIZE, 4,             EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,             EGL10.EGL_NONE         };

        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {

            /* Get the number of minimally matching EGL configurations              */             int[] num_config = new int[1];             egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);

            int numConfigs = num_config[0];

            if (numConfigs <= 0) {                 throw new IllegalArgumentException("No configs match configSpec");             }

            /* Allocate then read the array of minimally matching EGL configs              */             EGLConfig[] configs = new EGLConfig[numConfigs];             egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);

            if (DEBUG) {                  printConfigs(egl, display, configs);             }             /* Now return the "best" one              */             return chooseConfig(egl, display, configs);         }

        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,                 EGLConfig[] configs) {             for(EGLConfig config : configs) {                 int d = findConfigAttrib(egl, display, config,                         EGL10.EGL_DEPTH_SIZE, 0);                 int s = findConfigAttrib(egl, display, config,                         EGL10.EGL_STENCIL_SIZE, 0);

                // We need at least mDepthSize and mStencilSize bits                 if (d < mDepthSize || s < mStencilSize)                     continue;

                // We want an *exact* match for red/green/blue/alpha                 int r = findConfigAttrib(egl, display, config,                         EGL10.EGL_RED_SIZE, 0);                 int g = findConfigAttrib(egl, display, config,                             EGL10.EGL_GREEN_SIZE, 0);                 int b = findConfigAttrib(egl, display, config,                             EGL10.EGL_BLUE_SIZE, 0);                 int a = findConfigAttrib(egl, display, config,                         EGL10.EGL_ALPHA_SIZE, 0);

                if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)                     return config;             }             return null;         }

        private int findConfigAttrib(EGL10 egl, EGLDisplay display,                 EGLConfig config, int attribute, int defaultValue) {

            if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {                 return mValue[0];             }             return defaultValue;         }

        private void printConfigs(EGL10 egl, EGLDisplay display,             EGLConfig[] configs) {             int numConfigs = configs.length;             Log.w(TAG, String.format("%d configurations", numConfigs));             for (int i = 0; i < numConfigs; i++) {                 Log.w(TAG, String.format("Configuration %d:\n", i));                 printConfig(egl, display, configs[i]);             }         }

        private void printConfig(EGL10 egl, EGLDisplay display,                 EGLConfig config) {             int[] attributes = {                     EGL10.EGL_BUFFER_SIZE,                     EGL10.EGL_ALPHA_SIZE,                     EGL10.EGL_BLUE_SIZE,                     EGL10.EGL_GREEN_SIZE,                     EGL10.EGL_RED_SIZE,                     EGL10.EGL_DEPTH_SIZE,                     EGL10.EGL_STENCIL_SIZE,                     EGL10.EGL_CONFIG_CAVEAT,                     EGL10.EGL_CONFIG_ID,                     EGL10.EGL_LEVEL,                     EGL10.EGL_MAX_PBUFFER_HEIGHT,                     EGL10.EGL_MAX_PBUFFER_PIXELS,                     EGL10.EGL_MAX_PBUFFER_WIDTH,                     EGL10.EGL_NATIVE_RENDERABLE,                     EGL10.EGL_NATIVE_VISUAL_ID,                     EGL10.EGL_NATIVE_VISUAL_TYPE,                     0x3030, // EGL10.EGL_PRESERVED_RESOURCES,                     EGL10.EGL_SAMPLES,                     EGL10.EGL_SAMPLE_BUFFERS,                     EGL10.EGL_SURFACE_TYPE,                     EGL10.EGL_TRANSPARENT_TYPE,                     EGL10.EGL_TRANSPARENT_RED_VALUE,                     EGL10.EGL_TRANSPARENT_GREEN_VALUE,                     EGL10.EGL_TRANSPARENT_BLUE_VALUE,                     0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,                     0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,                     0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,                     0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,                     EGL10.EGL_LUMINANCE_SIZE,                     EGL10.EGL_ALPHA_MASK_SIZE,                     EGL10.EGL_COLOR_BUFFER_TYPE,                     EGL10.EGL_RENDERABLE_TYPE,                     0x3042 // EGL10.EGL_CONFORMANT             };             String[] names = {                     "EGL_BUFFER_SIZE",                     "EGL_ALPHA_SIZE",                     "EGL_BLUE_SIZE",                     "EGL_GREEN_SIZE",                     "EGL_RED_SIZE",                     "EGL_DEPTH_SIZE",                     "EGL_STENCIL_SIZE",                     "EGL_CONFIG_CAVEAT",                     "EGL_CONFIG_ID",                     "EGL_LEVEL",                     "EGL_MAX_PBUFFER_HEIGHT",                     "EGL_MAX_PBUFFER_PIXELS",                     "EGL_MAX_PBUFFER_WIDTH",                     "EGL_NATIVE_RENDERABLE",                     "EGL_NATIVE_VISUAL_ID",                     "EGL_NATIVE_VISUAL_TYPE",                     "EGL_PRESERVED_RESOURCES",                     "EGL_SAMPLES",                     "EGL_SAMPLE_BUFFERS",                     "EGL_SURFACE_TYPE",                     "EGL_TRANSPARENT_TYPE",                     "EGL_TRANSPARENT_RED_VALUE",                     "EGL_TRANSPARENT_GREEN_VALUE",                     "EGL_TRANSPARENT_BLUE_VALUE",                     "EGL_BIND_TO_TEXTURE_RGB",                     "EGL_BIND_TO_TEXTURE_RGBA",                     "EGL_MIN_SWAP_INTERVAL",                     "EGL_MAX_SWAP_INTERVAL",                     "EGL_LUMINANCE_SIZE",                     "EGL_ALPHA_MASK_SIZE",                     "EGL_COLOR_BUFFER_TYPE",                     "EGL_RENDERABLE_TYPE",                     "EGL_CONFORMANT"             };             int[] value = new int[1];             for (int i = 0; i < attributes.length; i++) {                 int attribute = attributes[i];                 String name = names[i];                 if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {                     Log.w(TAG, String.format("  %s: %d\n", name, value[0]));                 } else {                     // Log.w(TAG, String.format("  %s: failed\n", name));                     while (egl.eglGetError() != EGL10.EGL_SUCCESS);                 }             }         }

        // Subclasses can adjust these values:         protected int mRedSize;         protected int mGreenSize;         protected int mBlueSize;         protected int mAlphaSize;         protected int mDepthSize;         protected int mStencilSize;         private int[] mValue = new int[1];     }

    private static class Renderer implements GLSurfaceView.Renderer {         public void onDrawFrame(GL10 gl) {             GL2JNILib.step();         }

        public void onSurfaceChanged(GL10 gl, int width, int height) {             GL2JNILib.init(width, height);         }

        public void onSurfaceCreated(GL10 gl, EGLConfig config) {             // Do nothing.         }     } }

 

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// OpenGL ES 2.0 code

#include <jni.h>
#include <android/log.h>

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

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

#define  LOG_TAG    "libgl2jni"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

static void printGLString(const char *name, GLenum s) {
    const char *v = (const char *) glGetString(s);
    LOGI("GL %s = %s\n", name, v);
}

static void checkGlError(const char* op) {
    for (GLint error = glGetError(); error; error
            = glGetError()) {
        LOGI("after %s() glError (0x%x)\n", op, error);
    }
}

static const char gVertexShader[] = 
    "attribute vec4 aPosition;\n"
	"attribute vec4 aColor;\n"
	"varying vec4 vColor;\n"
    "void main() {\n"
    " gl_Position = aPosition;\n"
	" vColor = aColor;\n"
    "}\n";

static const char gFragmentShader[] = 
    "precision mediump float;\n"
	"varying vec4 vColor;"
    "void main() {\n"
    "  gl_FragColor = vColor;\n"
    "}\n";

GLuint loadShader(GLenum shaderType, const char* pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        glShaderSource(shader, 1, &pSource, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf) {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    LOGE("Could not compile shader %d:\n%s\n",
                            shaderType, buf);
                    free(buf);
                }
                glDeleteShader(shader);
                shader = 0;
            }
        }
    }
    return shader;
}

GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
    if (!vertexShader) {
        return 0;
    }

    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
    if (!pixelShader) {
        return 0;
    }

    GLuint program = glCreateProgram();
    if (program) {
        glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus != GL_TRUE) {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    LOGE("Could not link program:\n%s\n", buf);
                    free(buf);
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

GLuint gProgram;
GLuint gvPositionHandle;
GLuint gvColorHandle;

bool setupGraphics(int w, int h) {
    printGLString("Version", GL_VERSION);
    printGLString("Vendor", GL_VENDOR);
    printGLString("Renderer", GL_RENDERER);
    printGLString("Extensions", GL_EXTENSIONS);

    LOGI("setupGraphics(%d, %d)", w, h);
    gProgram = createProgram(gVertexShader, gFragmentShader);
    if (!gProgram) {
        LOGE("Could not create program.");
        return false;
    }
    gvPositionHandle = glGetAttribLocation(gProgram, "aPosition");
    gvColorHandle = glGetAttribLocation(gProgram, "aColor");
    checkGlError("glGetAttribLocation");
    LOGI("glGetAttribLocation(\"aPosition\") = %d\n",
            gvPositionHandle);

    glViewport(0, 0, w, h);
    checkGlError("glViewport");
    return true;
}

const GLfloat gTriangleVertices[] = { 0.0f, 0.0f,
		                              0.0f, 0.5f,
									 -0.5f, -0.5f,
									 0.5f, -0.5f ,
									 0.0f, 0.5f};
const GLfloat gTriangleColor[] = { 1.0f, 0.0f, 0.0f, 1.0f,
		                           0.0f, 0.0f, 1.0f, 1.0f,
		                           0.0f, 0.0f, 1.0f, 1.0f,
                                   0.0f, 0.0f, 1.0f, 1.0f,
                                   0.0f, 0.0f, 1.0f, 1.0f};

void renderFrame() {
    float grey = 0.1;
    glClearColor(grey, grey, grey, 1.0f);
    checkGlError("glClearColor");
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear");

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvPositionHandle);
    glVertexAttribPointer(gvColorHandle, 4, GL_FLOAT, GL_FALSE, 0, gTriangleColor);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvColorHandle);
    checkGlError("glEnableVertexAttribArray");
    glDrawArrays(GL_TRIANGLE_FAN, 0, 5);
    checkGlError("glDrawArrays");
}

extern "C" {
    JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height);
    JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);
};

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)
{
    setupGraphics(width, height);
}

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
{
    renderFrame();
}
顶部