@cxm-2016
2017-04-05T14:26:21.000000Z
字数 5594
阅读 7781
OpenGL-ES
版本:1
作者:陈小默
版权声明:禁止商用,禁止转载
参考书目:
[1]Donald Hearn,M.Pauline Barker.计算机图形学 第四版(蔡士杰 译).北京:电子工业出版社
[2]Dave Shreiner,Graham Sellers.OpenGL编程指南 第八版(王锐 译).北京:机械工业出版社
[3]Dan Ginsburg,Budirjanto Purnomo.OpenGL ES 3.0 编程指南 第二版(姚军 译).北京:机械工业出版社
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
OpenGL ES 3.0主要新功能有:
Android Studio在其2.0及以上版本继承了流行的C++编译器CMake,于是我们很方便的就能够搭建出NDK开发环境。
在Android Studio 2.0 及以上版本创建NDK的工程只需要勾选Include C++ Support
即可。
剩下的一路next就行。
在工程创建完成之后,我们将目录视图切换到Project
,我们发现app目录下多了一个CMakeList.txt文件,打开文件我们会看见如下内容(注释已精简)。
# 这里指定了CMake的最低版本为3.4.1
cmake_minimum_required(VERSION 3.4.1)
# 这里用来添加一个库
add_library( # 这里设置so库的名称为native-lib
native-lib
# 这里设置该库为共享
SHARED
# 这里是源文件的路径,可以有多个,最终这个源文件将被编译并打包进native-lib库。
src/main/cpp/native-lib.cpp )
# 这里用来查找一个库,并设置到路径变量中去
find_library( # 设置路径变量
log-lib
# 你希望CMake编译器加载的NDK函数库
log )
# 将一个库关联到目标函数库中
target_link_libraries( # 目标函数库
native-lib
# 想要在目标函数库中使用的函数库,其中${路径变量}
${log-lib} )
更详细的CMakeList.txt可以参照这里CMakeList.txt说明。
工程创建完成之后,我们在src/main/cpp文件夹下可以看到一个native-lib.cpp源文件(我们也可以改名成其他),由于其被指定到了add_library操作中,所以其最终会被编译并链接称为native-lib.so文件。
我们来看自动生成的MainActivity:
public class MainActivity extends AppCompatActivity {
// 这里加载的库名必须在CMakeList.txt中使用add_library指定
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
//该本地方法需要在某一个源文件中被实现,并且System.loadLibrary加载的库必须编译了了此源文件
public native String stringFromJNI();
}
我们可以直接运行这个程序,并且在屏幕上打印Hello from C++
这句话。
如果你对上面自动生成的代码还是不好理解的话,我们可以手动创建一个CPP文件,并配置。
这里演示一个方法传入字符串,并且在另一个方法接收的示例:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
setString("在这里传入新的字符串");
tv.setText(getString());
}
public native String getString();
public native void setString(String str);
}
加入我们写到这一步,AS就会报错说找不到方法,接下来我们需要在cpp文件中实现这个本地方法
mySource.cpp
//mySource.cpp
#include <jni.h>
#include <string>
static char * static_str=NULL;//使用全局变量缓存传入的字符串
extern "C"
void
Java_com_github_cccxm_gles_MainActivity_setString(JNIEnv *env, jobject instance, jstring str_) {
const char *str = env->GetStringUTFChars(str_, 0);//获取传入的字符串
jsize len = env->GetStringLength(str_);//计算字符串的长度
if(static_str!=NULL)free(static_str);//释放之前保存的字符串
static_str = (char*)malloc(sizeof(char)*len+1);//重新从内存中分配内存给字符串
for(int i=0;static_str[i]=str[i];i++);//复制传入的字符串
env->ReleaseStringUTFChars(str_, str);//释放原始的字符串
}
extern "C"
jstring
Java_com_github_cccxm_gles_MainActivity_getString(JNIEnv *env,jobject /* this */) {
return env->NewStringUTF(static_str);//回传缓存的字符串
}
add_library( native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/mySource.cpp)
然后我们运行就可以看到结果了。
本系列教程除了需要定义native方法的地方使用Java语言,其他地方全部使用Kotlin语言。Android开发不会Kotlin?你out啦!这里我们配置Kotlin环境,对于与Java语法不同的地方会有解释说明。目前kotlin语言的版本是1.0.4
首先我们需要修改整个应用的build.gradle文件,并在其中声明一个全局变量ext.kotlin_version = '1.0.4'
,然后增加一个kotlin的插件classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
,这里我们会使用到kotlin语言的扩展功能,所以还需要添加其扩展库classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
。
以下是应用的build.gradle文件示例:
buildscript {
ext.kotlin_version = '1.0.4'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
接下来修改app的build.gradle文件,我们在文件头部添加启用插件的语句
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
接下来在dependencies项中添加类库compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
注意:这里使用$kotlin_version来引用全局变量,其优点显而易见,每次版本更新的时候只需要修改一处即可。但是在目前2.2.0版本的AS中这样写可能会导致后续一些操作出错。这里建议手写版本号
compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.4"
删除原来的MainActivity和资源文件activity_main.xml,然后在包目录上单击右键/New/Kotlin Activity
,这里就跟平常创建一个Activity是一样的过程。这里Activity Name
输入MainActivity
,然后勾选Launcher Activity
最后产生的Activity是这个样子的
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Kotlin小贴士:
- kotlin中不需要分号表示语句结束