本節(jié)書摘來自異步社區(qū)《Android 應(yīng)用案例開發(fā)大全(第二版)》一書中的第2章,第2.4節(jié)壁紙的實(shí)現(xiàn),作者 吳亞峰 , 于復(fù)興 , 杜化美,更多章節(jié)內(nèi)容可以訪問云棲社區(qū)“異步社區(qū)”公眾號查看
2.4 壁紙的實(shí)現(xiàn)
Android 應(yīng)用案例開發(fā)大全(第二版)
上一節(jié)介紹了壁紙的框架,讓讀者對壁紙的整體框架有了初步認(rèn)識,本節(jié)將要對壁紙實(shí)現(xiàn)服務(wù)類GLWallpaperService、動態(tài)壁紙類LiveWallpaper、自定義渲染器類TDRender的開發(fā)進(jìn)行詳細(xì)介紹。
2.4.1 壁紙服務(wù)類——GLWallpaperService
該類是本項(xiàng)目中最基礎(chǔ)的一個類,沒有這個類就不可能使用壁紙這個功能。這個類為開發(fā)人員提供了壁紙服務(wù),開發(fā)人員可以通過繼承該類,重寫此類中的方法來實(shí)現(xiàn)壁紙的后續(xù)開發(fā)。本小節(jié)只對該類中的兩個地方進(jìn)行介紹,一個是setRender方法,另一個是觸控的響應(yīng)事件onTouchEvent。
(1)首先對setRender方法進(jìn)行介紹,具體代碼如下所示。
1 public void setRenderer(Renderer renderer) {
2 checkRenderThreadState(); // 檢查線程是否啟動
3 if (mEGLConfigChooser == null) { // 創(chuàng)建EGLConfigChooser
4 mEGLConfigChooser = new SimpleEGLConfigChooser(true);
5 }
6 if (mEGLContextFactory == null) { // 創(chuàng)建EGLContextFactory
7 mEGLContextFactory = new DefaultContextFactory();
8 }
9 if (mEGLWindowSurfaceFactory == null) { // 創(chuàng)建EGLWindowSurfaceFactory
10 mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
11 }
12 mGLThread = new GLThread(renderer, mEGLConfigChooser,
13 mEGLContextFactory, mEGLWindowSurfaceFactory, mGLWrapper);
14 mGLThread.start(); // 啟動線程
15 this.renderer=(TDRender) renderer; // 設(shè)置渲染器
16 }
第2~8行為檢查渲染器線程是否啟動,然后判斷是否已經(jīng)創(chuàng)建了EGLConfigChooser對象,如果沒有則創(chuàng)建,再判斷是否已創(chuàng)建EGLContextFactory對象,同樣如果沒有則創(chuàng)建。
第9~16行先判斷是否已經(jīng)創(chuàng)建了EGLWindowSurfaceFactory對象,如果沒有則創(chuàng)建。然后啟動渲染線程,再將渲染器設(shè)置為自定義的渲染器。
(2)下面將對屏幕觸控的相應(yīng)事件進(jìn)行介紹,屏幕的觸控事件分為3部分:第一部分是滑動屏幕使背景圖跟著屏幕移動,第二部分是點(diǎn)擊屏幕下方修改標(biāo)志位,最后一部分是手指抬起時判斷是否進(jìn)行喂食,具體代碼如下所示。
1 private float mPreviousX; // 上次的觸控位置_y_坐標(biāo)
2 private TDRender renderer; // 場景渲染器
3 @Override
4 public void onTouchEvent(MotionEvent e) {
5 float y = e.getY(); // 獲得觸控點(diǎn)的_y_坐標(biāo)
6 float x = e.getX(); // 獲得觸控點(diǎn)的_x_坐標(biāo)
7 switch (e.getAction()) {
8 case MotionEvent.ACTION_DOWN:
9 Constant.feeding = true; // 將喂食標(biāo)志位設(shè)為true
10 break;
11 case MotionEvent.ACTION_MOVE:
12 float dy = y - mPreviousY; // 計(jì)算觸控筆_y_位移
13 float dx = x - mPreviousX; // 計(jì)算觸控筆_y_位移
14 if (dx < 0){ // 觸摸左邊_x_為正,觸摸右邊_x_為負(fù)
15 if (Constant.CameraX < Constant.MaxCameraMove) {// 攝像機(jī)移動最大值
16 if(dx<- Constant.Thold){
17 Constant.feeding = false; // 喂食標(biāo)志位
18 }
19 Constant.CameraX = Constant.cameraX - dx / Constant.Camera ove_SCALE ;
20 Constant.TargetX=Constant.CameraX;
21 }} else {
22 if (Constant.CameraX < -Constant.MaxCameraMove {// 攝像機(jī)移動最大值
23 if(dx> Constant.Thold){
24 Constant.feeding = false; // 喂食標(biāo)志位
25 }
26 Constant.CmeraX = Constant.CameraX - dx / Constant.CameraMove _SCALE ;
27 Constant.TargetX=Constant.CameraX;
28 }}
29 MatrixUtil.setCamera ( // 將攝像機(jī)的位置信息存入到矩陣中
30 Constant.CameraX, // 攝像機(jī)_x_位置
31 Constant.CameraY, // 攝像機(jī)_y_位置
32 Constant.CameraZ, // 攝像機(jī)_y_位置
33 Constant.TargetX, // 觀測點(diǎn)的_x_位置
34 Constant.TargetY, // 觀測點(diǎn)的_y_位置
35 Constant.TargetZ, // 觀測點(diǎn)的_z_位置
36 Constant.UpX, // UP向量的x分量
37 Constant.UpY, // UP向量的y分量
38 Constant.UpZ); // UP向量的z分量
39 break;
40 case MotionEvent.ACTION_UP:
41 if (Constant.feeding) { // 標(biāo)志位,如果開始喂食
42 if (Constant.isFeed) {
43 Constant.isFeed = false; // 把標(biāo)志位置為false
44 Vector3f[]AB=IntersectantUtil
45 .calculateABPosition( // 通過變換獲得世界坐標(biāo)系中的點(diǎn)
46 x, // 觸控點(diǎn)_x_坐標(biāo)
47 y, // 觸控點(diǎn)_y_坐標(biāo)
48 Constant.SCREEN_WIDTH,// 屏幕寬度
49 Constant.SCREEN_HEGHT, // 屏幕長度
50 Constant.leftABS, // 視角left絕對值
51 Constant.topABS, // 視角top絕對值
52 Constant.nearABS, // 視角near值
53 Constant.farABS); // 視角far值
54 Vector3f Start = AB[0]; // 獲得拾取后世界坐標(biāo)系中被觸控到的近平面的點(diǎn)
55 Vector3f End = AB[1];// 獲得拾取后世界坐標(biāo)系中被觸控到的遠(yuǎn)平面的點(diǎn)
56 if (renderer.feedFish != null) { // 判斷不為空,則開始喂食
57 renderer.feedFish.startFeed(Start, End); // 開始喂食
58 }}}
59 requestRender(); // 重繪畫面
60 break;
61 }
62 mPreviousX = x; // 記錄觸控筆位置
63 super.onTouchEvent(e);
64 }}
第1~10行定義上次觸控點(diǎn)的x、y坐標(biāo),創(chuàng)建渲染器對象,獲得觸控點(diǎn)的x坐標(biāo)和y坐標(biāo),對ACTION_DOWN事件進(jìn)行監(jiān)聽,當(dāng)觸發(fā)時將喂食標(biāo)志位設(shè)為true。
第11~21行獲得手指在屏幕上的觸控點(diǎn),從而得到手指在屏幕上的移動距離,然后按照一定比例移動攝像機(jī)x坐標(biāo),同時,如果攝像機(jī)x坐標(biāo)達(dá)到閾值,則攝像機(jī)不會向滑動方向移動。
第22~32行將攝像機(jī)的位置信息存入到矩陣中,設(shè)置攝像機(jī)位置的坐標(biāo)、觀測點(diǎn)的坐標(biāo)和up向量,最后再次記錄觸控筆的x、y位置。
第33~46行為判斷喂食的標(biāo)志位,喂食有兩個標(biāo)志位,一個是在點(diǎn)擊喂食的時候?yàn)閠rue,另一個是在沒有喂食之前為true,因?yàn)榛瑒悠聊徊荒芪故?#xff0c;當(dāng)前喂的食物在沒有消失之前也不能喂食,所以,用了兩個標(biāo)志位對其進(jìn)行控制。然后通過矩陣變化獲取觸控點(diǎn)的世界坐標(biāo)系坐標(biāo)。
第47~57行通過拾取計(jì)算得到觸控點(diǎn)在世界坐標(biāo)系中的起點(diǎn)(近平面點(diǎn))、終點(diǎn)(遠(yuǎn)平面點(diǎn))坐標(biāo),并且開始進(jìn)行喂食。然后重繪畫面,記錄觸控筆的位置,回調(diào)父類的方法。
2.4.2 動態(tài)壁紙類——LiveWallpaper
只有壁紙的服務(wù)類還遠(yuǎn)遠(yuǎn)不夠,還要新建一個類繼承自壁紙服務(wù)類,然后重寫壁紙服務(wù)類的onCreateEngine方法才行,具體代碼如下所示。
1 package com.bn.ld.wallpaper;
2 import com.bn.gl.GLWallpaperService;
3 public class LiveWallpaper extends GLWallpaperService{
4 private TDRender renderer; // 場景渲染器
5 @Override
6 public Engine onCreateEngine() { // 重寫onCreateEngine方法
7 renderer=new TDRender(this);
8 return new GLEngine() { {
9 setRenderer(renderer); // 設(shè)置渲染器
10 setRenderMode(RENDERMODE_CONTINUOUSLY); // 設(shè)置主動渲染
11 }};}}
說明
定義渲染器類,繼承自GLWallpaperService類 ,創(chuàng)建私有的場景渲染器對象。然后重寫onCreateEngine方法,將渲染器設(shè)置為自定義的渲染器,并且把渲染器的渲染模式設(shè)置為主動渲染。
2.4.3 自定義渲染器類——TDRender
下面將介紹自定義的渲染器代碼,在自定義的渲染器類里,可以進(jìn)行魚、魚群、氣泡、水草、背景圖、石頭、魚食的繪制和初始化紋理等。
(1)由于該類中繪制代碼比較多,在此就先介紹整個渲染器的框架,具體代碼如下所示。
1 package com.bn.ld.wallpaper;
2 ……//此處省略部分類和包的引入代碼,讀者可自行查閱光盤的源代碼
3 public class TDRender extends GLSurfaceView implements GLSurfaceView.Renderer,
4 GLWallpaperService.Renderer {
5 public TDRender(Context context) {
6 super(context); // 獲得上下文對象
7 }
8 ……//此處省略相關(guān)成員變量的聲明代碼,讀者可自行查閱光盤的源代碼
9 public void onDrawFrame(GL10 gl) {
10 gl.glEnable(GL10.GL_CULL_FACE); // 設(shè)置為打開背面剪裁
11 gl.glShadeModel(GL10.GL_SMOOTH); // 設(shè)置著色模型為平滑著色
12 gl.glFrontFace(GL10.GL_CCW); // 設(shè)置為默認(rèn)卷繞順序逆時針
13 gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
14 GL10.GL_DEPTH_BUFFER_BIT); // 清除緩存
15 gl.glMatrixMode(GL10.GL_MODELVIEW); // 設(shè)置當(dāng)前矩陣為模式矩陣
16 gl.glLoadIdentity(); // 設(shè)置當(dāng)前矩陣為單位矩陣
17 GLU.gluLookAt( // 設(shè)置攝像機(jī)
18 gl,
19 Constant.CameraX, // 攝像機(jī)_x_位置
20 Constant.CameraY, // 攝像機(jī)_y_位置
21 Constant.CameraZ, // 攝像機(jī)_z_位置
22 Constant.TargetX, // 觀測點(diǎn)的_x_位置
23 Constant.TargetY, // 觀測點(diǎn)的_y_位置
24 Constant.TargetZ, // 觀測點(diǎn)的_z_位置
25 Constant.UpX, // UP向量x分量
26 Constant.UpY, // UP向量y分量
27 Constant.UpZ); // UP向量z分量
28 ……此處代碼是繪制代碼,將在后面給出
29 }
30 public void onSurfaceChanged(GL10 gl, int width, int height) {
31 gl.glViewport(0, 0, width, height); // 設(shè)置視窗大小及位置
32 gl.glMatrixMode(GL10.GL_PROJECTION); // 設(shè)置當(dāng)前矩陣為投影矩陣
33 gl.glLoadIdentity(); // 設(shè)置當(dāng)前矩陣為單位矩陣
34 float ratio = (float) width / height; // 計(jì)算透視投影的比例
35 Constant.SCREEN_HEGHT=height; // 獲取手機(jī)的高
36 Constant.SCREEN_WIDTH=width; // 獲取手機(jī)的寬
37 Constant.leftABS=ratio*Constant.View_SCALE; // 透視投影的left絕對值
38 Constant.topABS=1 * Constant.View_SCALE; // 透視投影的top絕對
39 Constant.SCREEN_SCALEX=Constant.View_SCALE*((ratio>1)?ratio:(1/ratio));
40 gl.glFrustumf(-Constant.leftABS, Constant.leftABS, -Constant.topABS, // 產(chǎn)生透視投影矩陣
41 Constant.topABS, Constant.nearABS,Constant.farABS);
42 MatrixUtil.setCamera ( // 將攝像機(jī)的位置信息存入到矩陣中
43 Constant.CameraX, // 攝像機(jī)_x_位置
44 Constant.CameraY, // 攝像機(jī)_y_位置
45 Constant.CameraZ, // 攝像機(jī)_z_位置
46 Constant.TargetX, // 觀測點(diǎn)的_x_位置
47 Constant.TargetY, // 觀測點(diǎn)的_y_位置
48 Constant.TargetZ, // 觀測點(diǎn)的_z_位置
49 Constant.UpX, // UP向量的x分量
50 Constant.UpY, // UP向量的y分量
51 Constant.UpZ); // UP向量的z分量
52 if (backgrounds == null) {
53 backgrounds = new BackGround(); // 初始化背景圖
54 }}
55 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
56 gl.glDisable(GL10.GL_DITHER); // 關(guān)閉抗抖動
57 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
58 GL10.GL_FASTEST); // 快速模式
59 gl.glClearColor(0, 0, 0, 0); // 設(shè)置屏幕背景色黑色RGBA
60 gl.glEnable(GL10.GL_DEPTH_TEST); // 啟用深度測試
61 gl.glEnable(GL10.GL_CULL_FACE); // 設(shè)置為打開背面剪裁
62 ……此處代碼是加載圖片、OBJ文件、創(chuàng)建各種對象,將在后面介紹
63 }}
第1~8行為部分類和包的引入代碼、相關(guān)成員變量的聲明,這些代碼在此處省略,讀者可自行查閱光盤代碼。創(chuàng)建構(gòu)造器并獲得上下文對象。
第9~29行為進(jìn)行繪制時的各種設(shè)置,如打開背面剪裁、設(shè)置平滑著色、設(shè)置默認(rèn)卷繞方式、設(shè)置模式矩陣和單位矩陣,最后設(shè)置攝像機(jī)位置,初始化背景圖對象。
第30~54行重寫onSurfaceChanged方法設(shè)置視口的大小,將當(dāng)前矩陣設(shè)為投影矩陣、設(shè)置單位矩陣、產(chǎn)生透視投影矩陣、并且生成攝像機(jī)觀察矩陣。
第55~63行重寫onSurfaceCreated方法。關(guān)閉抗抖動、設(shè)置Hint模式為快速模式、設(shè)置屏幕背景顏色、啟用深度檢測、打開背面剪裁。
(2)下面開始對本案例中魚類、氣泡、魚食、石頭等對象的創(chuàng)建以及本案例中用到的紋理ID的初始化進(jìn)行詳細(xì)介紹,具體代碼如下所示。
1 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
2 gl.glDisable(GL10.GL_DITHER); // 關(guān)閉抗抖動
3 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
4 GL10.GL_FASTEST); // 快速模式
5 gl.glClearColor(0, 0, 0, 0); // 設(shè)置屏幕背景色
6 gl.glEnable(GL10.GL_DEPTH_TEST); // 啟用深度測試
7 gl.glEnable(GL10.GL_CULL_FACE);
8 if (fishAl.size() == 0) {
9 bubbles = initTexture(gl, "bubble.png"); // 氣泡的紋理ID
10 fish0 = initTexture(gl, "fish0.png"); // 魚的紋理ID
11 fish1 = initTexture(gl, "fish1.png");
12 fish2 = initTexture(gl, "fish2.png");
13 fish3 = initTexture(gl, "fish3.png");
14 fish4 = initTexture(gl, "fish4.png");
15 fish5 = initTexture(gl, "fish5.png");
16 fishfood = initTexture(gl, "fishfood.png"); // 魚食的紋理ID
17 waterweeds = initTexture(gl, "waterweeds.png");// 水草的紋理ID
18 background = initTexture(gl, "background.png");// 背景的紋理ID
19 stone=initTexture(gl, "stone.png"); // 石頭的紋理
20 fishAl.add(new SingleFish(fish1, TDRender.this, "fish1.obj", // 將單個魚加入魚類列表
21 new Vector3f(-1, 2, 0), // 初始位置
22 new Vector3f(-0.02f, -0.02f, 0.00f), new Vector3f(0, 0, 0), // 初始速度和外力
23 new Vector3f(0, 0, 0), 70)); // 初始吸引力和魚的質(zhì)量
24 fishAl.add(new SingleFish(fish0, TDRender.this, "fish0.obj",
25 new Vector3f(-7, 5, 0), // 初始位置
26 new Vector3f(-0.04f, 0.01f, -0.04f),new Vector3f(0, 0, 0), // 初始速度和外力
27 new Vector3f(0, 0, 0), 150)); // 初始吸引力和魚的質(zhì)量
28 fishAl.add(new SingleFish(fish2, TDRender.this, "fish2.obj",
29 new Vector3f(-0, 3, 0), // 初始位置
30 new Vector3f(0.02f, 0.01f, -0.01f),new Vector3f(0, 0, 0), // 初始速度和外力
31 new Vector3f(0, 0, 0), 70)); // 初始吸引力和魚的質(zhì)量
32 fishAl.add(new SingleFish(fish4, TDRender.this, "fish4.obj",
33 new Vector3f(-1, 0, 0), // 初始位置
34 new Vector3f(-0.03f, 0.02f, -0.02f), new Vector3f(0, 0, 0), // 初始速度和外力
35 new Vector3f(0, 0, 0), 90)); // 初始吸引力和魚的質(zhì)量
36 fishAl.add(new SingleFish(fish4, TDRender.this, "fish4.obj",
37 new Vector3f(-5, 0, 0), // 初始位置
38 new Vector3f(-0.02f, 0.03f, -0.02f), new Vector3f(0, 0, 0), // 初始速度和外力
39 new Vector3f(0, 0, 0), 50)); // 初始吸引力和魚的質(zhì)量
40 fishAl.add(new SingleFish(fish4, TDRender.this, "fish4.obj",
41 new Vector3f(-5, 3, 0), // 初始位置
42 new Vector3f(-0.01f, 0.02f, -0.04f), new Vector3f(0, 0, 0), // 初始速度和外力
43 new Vector3f(0, 0, 0), 60)); // 初始吸引力和魚的質(zhì)量
44 fishAl.add(new SingleFish(fish5, TDRender.this, "fish5.obj",
45 new Vector3f(1, -3, 0), // 初始位置
46 new Vector3f(0.03f, 0.01f, -0.03f),new Vector3f(0, 0, 0f), // 初始速度和外力
47 new Vector3f(0, 0, 0), 80)); // 初始吸引力和魚的質(zhì)量
48 fishAl.add(new SingleFish(fish5, TDRender.this, "fish5.obj",
49 new Vector3f(-4, -1, 0), // 初始位置
50 new Vector3f(0.045f, 0.02f, -0.05f),new Vector3f(0, 0, 0f), // 初始速度和外力
51 new Vector3f(0, 0, 0), 40)); // 初始吸引力和魚的質(zhì)量
52 }
53 if (waterweeds1 == null) { // 創(chuàng)建水草類對象
54 waterweeds1 = LoadUtil.loadFromFileVertexOnly("waterweeds.obj",
55 this.getResources()); // 加載水草模型
56 }
57 if(stones==null){ // 創(chuàng)建石頭類對象
58 stones=LoadUtil.loadFromFileVertexOnly("stone.obj",
59 this.getResources()); // 加載石頭模型
60 }
61 if (fishfoods == null) { // 創(chuàng)建魚食對象
62 fishfoods = LoadUtil.loadFromFileVertexOnly("fishfood.obj",
63 this.getResources()); // 加載魚食模型
64 }
65 if (bubbleControl == null) { // 創(chuàng)建氣泡的Control對象
66 bubbleControl = new BubbleControl(bubbles);
67 }
68 if (fishControl == null) { // 創(chuàng)建魚類的Control對象
69 fishControl = new FishControl(fishAl, TDRender.this);
70 }
71 if (fishSchool == null) { // 創(chuàng)建魚群的Control
72 fishSchool = new FishSchoolControl(fish3, TDRender.this);
73 }
74 if (singleFood == null) { // 食物類
75 singleFood = new FeedFish(fishfoods, TDRender.this);
76 }
77 if (feedFish == null) { // 創(chuàng)建控制喂食的對象
78 feedFish = new SingleFood(TDRender.this);
79 }}
第2~7行為關(guān)閉抗抖動,將Hint的模式設(shè)置為快速模式,設(shè)置屏幕背景顏色為黑色,啟用深度檢測,打開背面剪裁。
第8~52行獲得圖片的紋理ID ,對單個魚進(jìn)行初始化設(shè)置魚的初始位置、初始速度、受到的外力和吸引力,以及魚的質(zhì)量(力的縮放比)。
第53~79行創(chuàng)建背景圖、水草、石頭、氣泡、魚食、群魚、魚群對象。并且只有當(dāng)這些對象為空的時候才會對這些對象進(jìn)行實(shí)例化。
(3)下面開始對3D水族館動態(tài)壁紙案例中各個對象的繪制進(jìn)行介紹,繪制代碼在onDrawFrame方法中,具體代碼如下所示。
1 public void onDrawFrame(GL10 gl) {
2 gl.glEnable(GL10.GL_CULL_FACE); // 設(shè)置為打開背面剪裁
3 gl.glShadeModel(GL10.GL_SMOOTH); // 設(shè)置著色模型為平滑著色
4 gl.glFrontFace(GL10.GL_CCW); // 設(shè)置為默認(rèn)卷繞順序逆時針為正
5 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 清除顏色緩存
6 gl.glMatrixMode(GL10.GL_MODELVIEW); // 設(shè)置當(dāng)前矩陣為模式矩陣
7 gl.glLoadIdentity(); // 設(shè)置矩陣為單位矩陣
8 GLU.gluLookAt( gl, // 設(shè)置攝像機(jī)
9 Constant.CameraX, // 攝像機(jī)_x_位置
10 Constant.CameraY, // 攝像機(jī)_y_位置
11 Constant.CameraZ, // 攝像機(jī)_z_位置
12 Constant.TargetX, // 觀測點(diǎn)的_x_位置
13 Constant.TargetY, // 觀測點(diǎn)的_y_位置
14 Constant.TargetZ, // 觀測點(diǎn)的_z_位置
15 Constant.UpX, // UP向量x分量
16 Constant.UpY, // UP向量y分量
17 Constant.UpZ); // UP向量z分量
18 gl.glPushMatrix(); // 保護(hù)矩陣
19 if (backgrounds != null) { // 背景圖不為空就繪制
20 backgrounds.drawSelf(gl,background); // 繪制背景圖
21 }
22 gl.glPopMatrix(); // 恢復(fù)矩陣
23 gl.glPushMatrix(); // 保護(hù)矩陣
24 if (waterweeds1 != null&&stones!=null) { // 如果沒有繪制過水草和石頭則繪制
25 gl.glPushMatrix(); // 左后邊的水草、石頭
26 gl.glTranslatef(-17, -5.5f,-14); // 平移坐標(biāo)系
27 stones.drawSelf(gl,stone); // 繪制石頭
28 gl.glTranslatef(1.5f, 0, 1); // 平移坐標(biāo)系
29 waterweeds1.drawSelf(gl,waterweeds); // 繪制水草
30 gl.glTranslatef(2, 0, 1); // 平移坐標(biāo)系
31 gl.glPushMatrix(); // 保護(hù)矩陣
32 gl.glScalef(1.5f, 1.5f, 1.5f); // 設(shè)置縮放
33 stones.drawSelf(gl,stone); // 繪制石頭
34 gl.glPopMatrix(); // 恢復(fù)矩陣
35 ……下面的水草和石頭的繪制和上面的類似就不再給出程序,讀者可自行查看源代碼
36 }
37 gl.glPopMatrix(); // 恢復(fù)矩陣
38 gl.glPushMatrix(); // 保護(hù)矩陣
39 if (fishControl != null) {
40 fishControl.drawSelf(gl); // 繪制魚
41 }
42 if (fishSchool != null) {
43 fishSchool.drawSelf(gl); // 繪制魚群
44 }
45 gl.glPopMatrix(); // 恢復(fù)矩陣
46 gl.glPushMatrix(); // 保護(hù)矩陣
47 if (singleFood != null) {
48 singleFood.drawSelf(gl); // 繪制魚食
49 }
50 gl.glPopMatrix(); // 恢復(fù)矩陣
51 gl.glPushMatrix(); // 保護(hù)矩陣
52 gl.glEnable(GL10.GL_BLEND); // 開啟混合
53 gl.glBlendFunc(GL10.GL_SRC_ALPHA,
54 GL10.GL_ONE_MINUS_SRC_ALPHA); // 設(shè)置源混合因子與目標(biāo)混合因子
55 gl.glTranslatef(0, 0, 15f); // 平移
56 if (bubbleControl != null) {
57 bubbleControl.drawSelf(gl); // 繪制氣泡
58 }
59 gl.glDisable(GL10.GL_BLEND); // 關(guān)閉混合
60 gl.glPopMatrix(); // 恢復(fù)矩陣
61 }
第1~17行設(shè)置背面剪裁、卷繞方式、平滑著色、清除顏色緩存和深度緩存,設(shè)置當(dāng)前矩陣為模式矩陣,設(shè)置當(dāng)前矩陣為單位矩陣,設(shè)置攝像機(jī)位置。
第18~36行繪制背景圖、水草和石頭。由于水草和石頭要重復(fù)繪制很多次,在此就不一一列舉了,只給了出其中的部分代碼,其余代碼讀者可自行查看光盤中的源代碼。
第37~61行繪制群魚、魚群、魚食和氣泡。因?yàn)闅馀菔前胪该鞯?#xff0c;所以要開啟混合(繪制氣泡時要根據(jù)氣泡的位置對氣泡進(jìn)行排序),并且要將氣泡在最后繪制,最后不要忘了關(guān)閉混合。
(4)最后將對初始化紋理的initTexture方法進(jìn)行介紹,具體代碼如下所示。
1 public int initTexture(GL10 gl, String pname){ // 初始化紋理
2 int[] textures = new int[1]; // 紋理ID
3 gl.glGenTextures(1, textures, 0); // 生成紋理ID
4 int currTextureId = textures[0];
5 gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId); // 綁定紋理
6 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
7 GL10.GL_NEAREST); // 最近點(diǎn)采樣
8 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
9 GL10.GL_LINEAR); // 線性紋理過濾
10 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
11 GL10.GL_CLAMP_TO_EDGE); // 紋理的橫向拉伸方式
12 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
13 GL10.GL_CLAMP_TO_EDGE); // 紋理的縱向拉伸方式
14 InputStream in = null; // 創(chuàng)建輸入流
15 try {
16 in = this.getResources().getAssets().open(pname); // 加載紋理圖片
17 } catch (IOException e1) {
18 e1.printStackTrace(); // 異常處理
19 }
20 Bitmap bitmapTmp; // 創(chuàng)建bitmap對象
21 try {
22 bitmapTmp = BitmapFactory.decodeStream(in); // 對獲取的圖片解碼
23 } finally {
24 try {
25 in.close(); // 關(guān)閉輸入流
26 } catch (IOException e) {
27 e.printStackTrace(); // 異常處理
28 }}
29 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0); // 指定紋理
30 bitmapTmp.recycle(); // 釋放bitmap
31 return currTextureId;
32 }
第2~13行定義紋理ID、生成紋理ID、綁定紋理、設(shè)置紋理的過濾方式分為最近點(diǎn)采樣和線性紋理過濾,設(shè)置紋理的拉伸方式分為橫向拉伸方式和縱向拉伸方式。
第14~32行創(chuàng)建輸入流,讀取紋理圖片,進(jìn)行異常處理。創(chuàng)建bitmap對象,對獲取的圖片進(jìn)行解碼,關(guān)閉輸入流,異常處理,最后釋放bitmap。
總結(jié)
以上是生活随笔為你收集整理的《Android 应用案例开发大全(第二版)》——2.4节壁纸的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。