利用android_ndk以及OpenGLES开发动态壁纸

本文是一个android动态壁纸的例子,利用android_ndk调用底层的C++代码,使用OpenGLES来绘制动态壁纸。仅作参考。

首先是定义我们自己的Renderer类,FireWallpaperRenderer实现了GLWallpaperService.Renderer接口(GLWallpaperService的代码在《android利用OpenGLES开发动态壁纸用到的GLWallpaperService类》的那篇博客里

import java.io.IOException;
import java.io.InputStream;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.util.Log;

public class FireWallpaperRenderer implements GLWallpaperService.Renderer {
	//用于纹理映射的绑定,并把绑定后的地址传递给C++代码,供其调用
	private int[] texture = new int[2];
	//用于加载Bitmap的context
	private Context mContext;
	
	//FireWallpaperRenderer构造函数,用来初始化mContext
	public FireWallpaperRenderer(Context context){
		mContext = context;
	}
	
	/**
	 * 渲染场景的代码,这里我们是通过调用底层C++的代码来实现的,
	 * 这样能得到更好地运行速度
	 * */
	@Override
	public void onDrawFrame(GL10 gl) {
		//调用本地onDrawFrame方法
		FireNativeMethod.onDrawFrame(gl);
	}
	
	
	/**
	 * 处理屏幕尺寸发生变化时的代码,
	 * 用来重新设置场景的大小和其他一些属性,
	 * 也是通过调用底层C++代码来实现
	 * */
	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		//调用本地onSurfaceChanged方法
		FireNativeMethod.onSurfaceChanged(gl, width, height);
	}

	/**
	 * 初始化OpenGL场景,
	 * 用来设置场景的一些属性,
	 * 也是通过调用底层C++代码来实现
	 * */
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		//用来绑定Bitmap纹理
		bindTexture(gl, mContext);
		//调用本地setTexture方法,把纹理绑定的地址传递给C++代码,以供其调用
		FireNativeMethod.setTexture(texture);
		//调用本地onSurfaceCreated方法
		FireNativeMethod.onSurfaceCreated(gl, config);

	}
	
	/**
	 * 用来绑定Bitmap纹理的代码,
	 * 因为暂时没有找到在C++代码中绑定Bitmap纹理的方法,
	 * 所以暂且在java层绑定Bitmap纹理
	 * */

	private void bindTexture(GL10 gl, Context context) {
		//生成纹理
		gl.glGenTextures(2, texture, 0);
		//加载Bitmap
		Bitmap bitmap = loadBitmap(context, R.drawable.floor);
		if (bitmap != null) {
			Log.i("firewallpaperrenderer", "bind the floor texture");
			//如果bitmap加载成功,则生成此bitmap的纹理映射
			gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
			//设置纹理映射的属性
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
					GL10.GL_NEAREST);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
					GL10.GL_NEAREST);
			//生成纹理映射
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
			//释放bitmap资源
			bitmap.recycle();
		}
		bitmap = loadBitmap(context, R.drawable.fire);
		if (bitmap != null) {
			//同上
			Log.i("firewallpaperrenderer", "bind the fire texture");
			gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
					GL10.GL_NEAREST);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
					GL10.GL_NEAREST);
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
			bitmap.recycle();
		}

	}

	/**
	 * 加载Bitmap的方法,
	 * 用来从res中加载Bitmap资源
	 * */
	private Bitmap loadBitmap(Context context, int resourceId) {
		InputStream is = context.getResources().openRawResource(resourceId);
		Bitmap bitmap = null;
		try {

			// 利用BitmapFactory生成Bitmap
			bitmap = BitmapFactory.decodeStream(is);
		} finally {
			try {

				// 关闭流
				is.close();
				is = null;
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
		return bitmap;

	}

}

然后定义我们的WallpaperService,FireWallpaperService继承自GLWallpaperService:

public class FireWallpaperService extends GLWallpaperService {
	//定义FireWallpaperRenderer实例
	private FireWallpaperRenderer mRenderer;
	
	
	public Engine onCreateEngine() {
		if (mRenderer == null) {
			mRenderer = new FireWallpaperRenderer(this);
		}
		return new FireWallpaperEngine();
	}

	class FireWallpaperEngine extends GLWallpaperService.GLEngine {

		public FireWallpaperEngine() {
			//设置Renderer和RendererMode
			setRenderer(mRenderer);
			setRenderMode(RENDERMODE_CONTINUOUSLY);
		}

	}

}

完成后编辑Manifest.xml文件,如下:

application android:icon="@drawable/icon" android:label="@string/app_name">
		<service android:name=".FireWallpaperService" android:label="@string/firewallpaper"
			android:permission="android.permission.BIND_WALLPAPER">
			<intent-filter>
				<action android:name="android.service.wallpaper.WallpaperService" />
			</intent-filter>
			<meta-data android:name="android.service.wallpaper"
				android:resource="@xml/wallpaper" />
		</service>

	</application>


Manifest.xml文件中,FireWallpaperService使用到的wallpaper文件

(<meta-dataandroid:name="android.service.wallpaper"android:resource="@xml/wallpaper" />)在res/xml目录下定义,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
	android:description="@string/description" android:thumbnail="@drawable/firelivewallpaper" />


然后是我们的本地方法类——FireNativeMethod:

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class FireNativeMethod {
	//加载本地库文件
	static{
		System.loadLibrary("fire_native_method");
	}
	
	//渲染场景本地方法
	public static native void onDrawFrame(GL10 gl);
	//处理屏幕尺寸变化本地方法
	public static native void onSurfaceChanged(GL10 gl, int width, int height);
	//初始化OpenGL场景本地方法
	public static native void onSurfaceCreated(GL10 gl, EGLConfig config);
	//传递纹理映射地址本地方法
	public static native void setTexture(int [] textureString);

}


之后就是我们的本地C++代码部分了。

首先我们要定义和篝火粒子属性设置相关的类的头文件(Fire.h):

#ifndef _FIRE
#define _FIRE
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES/gl.h>
#include <stdlib.h>
#include <math.h>
//声明用来调用纹理映射的数组
extern GLuint *texture;
/**
 * Fire类
 * */
class Fire
{
public:
	Fire(void);
	~Fire(void);
	void InitFire();   //初始化篝火粒子
	//下面两个方法用来设置篝火粒子的属性值,以供渲染篝火粒子所用
	void PrepareFire();
	void ActivateFireParticles();
	void RenderFire();  //渲染篝火粒子

	// 粒子结构体

	struct PARTICLE {

		float X,Y,Z; // 当前位置
		float sX,sY,sZ; // 当前移动速度
		float tX,tY,tZ; // 目标移动速度
		float R,B,G; // 粒子颜色
		float Size; // 粒子大小
		bool Active; // 粒子是否可见
		int Age; // 粒子的生命值
		int MaxAge; // 粒子消失前的最大生命值

	};

	//粒子结构体数组
	PARTICLE * FireParticles;

	//粒子个数
	int FireParticleCount;

	//每帧活动粒子数
	int ActivateFirePerFrame;

};
#endif


然后是其相关的C++文件(Fire.cpp):

#include "Fire.h"

//初始化纹理数组
GLuint *texture = 0;
Fire::Fire(void) {
}


/**
 * 释放粒子结构体数组
 * */
Fire::~Fire(void) {
	delete[] FireParticles;
	FireParticles = 0;
}

/**
 * 初始化粒子
 * */
void Fire::InitFire() {

	int p;

	//粒子的个数
	FireParticleCount = 500;


	//每帧粒子个数
	ActivateFirePerFrame = 40;

	//初始化粒子结构体数组
	FireParticles = new PARTICLE[FireParticleCount];

	//初始粒子不可见
	for (p = 0; p < FireParticleCount; p++) {

		FireParticles[p].Active = false;

	}
}

void Fire::PrepareFire() {

	int p;

	for (p = 0; p < FireParticleCount; p++) {

		// 调整粒子的速度
		FireParticles[p].sX += (FireParticles[p].tX - FireParticles[p].sX)
				/ 10.0f;
		FireParticles[p].sY += (FireParticles[p].tY - FireParticles[p].sY)
				/ 20.0f;
		FireParticles[p].sZ += (FireParticles[p].tZ - FireParticles[p].sZ)
				/ 10.0f;
		// 通过新的速度调整粒子的位置
		FireParticles[p].X += FireParticles[p].sX;
		FireParticles[p].Y += FireParticles[p].sY;
		FireParticles[p].Z += FireParticles[p].sZ;

		// 调整粒子尺寸
		FireParticles[p].Size -= 0.002f;
		if (FireParticles[p].Size < 0.0f) {
			FireParticles[p].Active = false;
		}

		// 调整粒子颜色
		FireParticles[p].R -= 0.01f;
		FireParticles[p].G -= 0.03f;

		if (FireParticles[p].R < 0.1f)
			FireParticles[p].R = 0.1f;
		if (FireParticles[p].G < 0.1f)
			FireParticles[p].G = 0.0f;

		// 最后检查粒子的生命值,如果生命值大于最大生命值,设置粒子不可见
		FireParticles[p].Age++;
		if (FireParticles[p].Age > FireParticles[p].MaxAge) {
			FireParticles[p].Active = false;
		}

	}

}

void Fire::ActivateFireParticles() {

	int p;

	for (p = 0; p < FireParticleCount; p++) {

		if (!FireParticles[p].Active) {

			// 设置粒子的起始位置
			FireParticles[p].X = (((float) ((rand() % 50) + 1)) / 100.0f)
					- 0.25f;
			FireParticles[p].Y = 0.0f;
			FireParticles[p].Z = (((float) ((rand() % 50) + 1)) / 100.0f)
					- 0.25f;

			// 设置粒子的目标速度
			FireParticles[p].tX = 0.0f;
			FireParticles[p].tY = 0.01f;
			FireParticles[p].tZ = 0.0f;

			// 生成粒子随机速度
			FireParticles[p].sX = (((float) ((rand() % 30) + 1)) / 1000.0f)
					- 0.015f;
			FireParticles[p].sY = (((float) ((rand() % 50) + 1)) / 1000.0f);
			FireParticles[p].sZ = (((float) ((rand() % 30) + 1)) / 1000.0f)
					- 0.015f;

			//设置粒子可见
			FireParticles[p].Active = true;
			// 设置粒子的生命值为0
			FireParticles[p].Age = 0;
			// 设置粒子的最大生命值为300
			FireParticles[p].MaxAge = 300;

			// 设置粒子颜色
			FireParticles[p].R = 0.7f;
			FireParticles[p].G = 0.6f;
			FireParticles[p].B = 0.0f;

			// 设置粒子尺寸
			FireParticles[p].Size = (((float) ((rand() % 15))) / 100.0f);

			return;
		}
	}
}

void Fire::RenderFire() {

	for (int i = 0; i < ActivateFirePerFrame; i++) {
		ActivateFireParticles();
	}

	PrepareFire();

	int p;

	GLfloat fogColor[4] = { 0.0f, 0.0f, 0.0f, 0.5f };

	glFogx(GL_FOG_MODE, GL_LINEAR); // 设置雾模式
	glFogfv(GL_FOG_COLOR, fogColor); // 设置雾颜色
	glFogf(GL_FOG_DENSITY, 0.35f); // 设置雾密度
	glHint(GL_FOG_HINT, GL_DONT_CARE); // Fog Hint Value
	glFogf(GL_FOG_START, 1.0f); // 设置雾的开始深度
	glFogf(GL_FOG_END, 2.0f); // 设置雾的结束深度
	glEnable(GL_FOG); // 启用雾模式


	GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
	GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightPosition[] = { 0.0f, 0.1f, 0.0f, 1.0f };

	glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
	glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHTING);

	/**
	 * 开始渲染地面
	 * */
	//启用纹理,并绑定地面纹理,禁用混合
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	glDisable(GL_BLEND);

	//设置颜色
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

	//法线向量
	float normals[] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 1.0f, 0.0f };
	//纹理坐标
	float texCoords[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f };
	//顶点坐标
	float vertecies[] = { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f,
			-0.5f, 0.5f, 0.0f, -0.5f };
	//绘制地面
	for (int y = 0; y < 20; y++) {
		for (int x = 0; x < 20; x++) {
			glPushMatrix();
			glTranslatef(-5.0f, 0.0f, 5.0f);
			glTranslatef((float) x / 2, 0.0f, -(float) y / 2);
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glEnableClientState(GL_NORMAL_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertecies);
			glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
			glNormalPointer(GL_FLOAT, 0, normals);
			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
			glDisableClientState(GL_VERTEX_ARRAY);
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
			glDisableClientState(GL_NORMAL_ARRAY);
			glPopMatrix();
		}
	}

	//禁用光照和雾模式
	glDisable(GL_LIGHTING);
	glDisable(GL_FOG);
	/**
	 * 渲染地面结束
	 * */

	/**
	 * 开始渲染篝火
	 * */
	// 启用纹理,绑定我们的粒子纹理
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture[1]);

	// 禁用深度测试
	glDisable(GL_DEPTH_TEST);

	// 启用混合
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);

	//绘制我们的篝火
	for (p = 0; p < FireParticleCount; p++) {

		if (FireParticles[p].Active) {
			glColor4f(FireParticles[p].R, FireParticles[p].G,
					FireParticles[p].B, 1.0f);

			glPushMatrix();

			glTranslatef(FireParticles[p].X, FireParticles[p].Y,
					FireParticles[p].Z);
			glNormal3f(0.0f, 0.0f, 1.0f);
			float vertecies[] = { -FireParticles[p].Size,
					-FireParticles[p].Size, 0.0f, FireParticles[p].Size,
					-FireParticles[p].Size, 0.0f, -FireParticles[p].Size,
					FireParticles[p].Size, 0.0f, FireParticles[p].Size,
					FireParticles[p].Size, 0.0f };
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertecies);
			glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
			glDisableClientState(GL_VERTEX_ARRAY);
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);

			glPopMatrix();
		}
	}

	/**
	 * 渲染篝火结束
	 * */
	//重新启用深度测试
	glEnable(GL_DEPTH_TEST);

}


接着是我们处理OpenGL初始化、设置和渲染的方法的头文件——Stdx.h:

#ifndef _STDX
#define _STDX
#include "Fire.h"
//初始化OpenGL场景
extern void InitGL();
//处理屏幕尺寸变化
extern void SizeChanged(int width ,int height);
//渲染场景
extern void RendererGL();
//计算场景透视
extern void gluPerspective(double fovy, double aspect, double zNear,
		double zFar);
#endif


 

然后是其相关的C++文件——main.cpp:

#include "Stdx.h"
Fire Fire;  //Fire实例
float aspectRatio;   //用于透视计算
void InitGL() {
	glShadeModel(GL_SMOOTH);   // 启用平滑模式
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);   // 设置黑色背景
	glClearDepthf(1.0f);    // 设置深度缓存
	glEnable(GL_DEPTH_TEST);   // 启用深度测试
	glDepthFunc(GL_LEQUAL);   // 深度测试类型
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   // 获得良好的透视效果
	Fire.InitFire();   //初始化粒子
}

void SizeChanged(int width ,int height) {
	glViewport(0, 0, width, height);  //重设窗口大小
	glMatrixMode(GL_PROJECTION);  //启用投影矩阵
	glLoadIdentity();     //重置投影矩阵
	aspectRatio = float(width) / float(height);  //获得屏幕宽、高比
	gluPerspective(45.0, aspectRatio, 0.1, 100.0);  //计算透视
	glMatrixMode(GL_MODELVIEW);  //启用模型视图矩阵
	glLoadIdentity();   //重置模型视图矩阵
}

void RendererGL() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // 首先清除颜色和深度缓存
	glLoadIdentity();	// 重设模型视图矩阵
	glTranslatef(0.0f, -0.5f, -2.2f);  //移动场景
	Fire.RenderFire(); //渲染篝火


}

void gluPerspective(double fovy, double aspect, double zNear, double zFar) {
	glMatrixMode(GL_PROJECTION);   //启用投影矩阵
	glLoadIdentity();   //重置投影矩阵

	//计算透视
	double xmin, xmax, ymin, ymax;
	ymax = zNear * tan(fovy * M_PI / 360.0);
	ymin = -ymax;
	xmin = ymin * aspect;
	xmax = ymax * aspect;

	//设置透视
	glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);
	glMatrixMode(GL_MODELVIEW);  //启用模型视图矩阵
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);    // 获得良好的透视效果
}


之后我们需要把我们的本地方法类——FireNativeMethod利用javah命令生成正确的头文件,然后在其对应的C++文件(com_ygc_FireNativeMethod.cpp)中定义头文件中的方法,在其方法中调用相应的本地代码实现其功能:

#include "com_ygc_FireNativeMethod.h"
#include "Stdx.h"
/*
 * 调用RendererGL方法渲染场景
 */
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_onDrawFrame
  (JNIEnv *env, jclass cls, jobject obj){
	RendererGL();
}

/*
 * 调用SizeChanged调整场景
 */
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_onSurfaceChanged
  (JNIEnv *env, jclass cls, jobject obj, jint width, jint height){
	SizeChanged(width,height);
}

/*
 * 调用InitGL初始化场景
 */
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_onSurfaceCreated
  (JNIEnv *env, jclass cls, jobject obj1, jobject obj2){
	InitGL();
}
/*
 * 获得纹理绑定地址
 */
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_setTexture
  (JNIEnv *env, jclass cls, jintArray tex){
	texture = (GLuint *)env->GetIntArrayElements(tex,0);

}


 

最后是我们的Android.mk文件:

# 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.
#
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := fire_native_method
LOCAL_SRC_FILES := com_ygc_FireNativeMethod.cpp Fire.cpp main.cpp
LOCAL_LDLIBS	:=-L$(SYSROOT)/usr/lib -lGLESv2
LOCAL_LDLIBS	+=-L$(SYSROOT)/usr/lib -lGLESv1_CM
LOCAL_LDLIBS	+= -L$(SYSROOT)/usr/lib -llog

include $(BUILD_SHARED_LIBRARY)

你可能感兴趣的:(java,android,filter,float,Blend,permissions)