本文是一个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;
- }
- }
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);
- }
- }
- }
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>
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目录下定义,内容如下:
- <SPAN style="COLOR: #000000"><?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" /></SPAN>
<?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);
- }
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
#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);
- }
#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
#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); // 获得良好的透视效果
- }
#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);
- }
#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)
本文介绍了一个使用Android NDK和OpenGLES开发的动态壁纸示例,重点在于如何结合C++和Java实现高效的动态壁纸渲染,包括粒子效果的实现。
1199

被折叠的 条评论
为什么被折叠?



