blob: 5a3850de65a761b81b6fb335376caff5a4900373 [file] [log] [blame]
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dianne Hackbornba398392011-08-01 16:11:57 -070017package com.android.systemui;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070018
Romain Guy407ec782011-08-24 17:06:58 -070019import android.app.ActivityManager;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070020import android.app.WallpaperManager;
Romain Guy407ec782011-08-24 17:06:58 -070021import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.graphics.Bitmap;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070025import android.graphics.Canvas;
Dianne Hackborn759a39e2009-08-09 17:20:27 -070026import android.graphics.Rect;
Mathias Agopiane2d034c2009-09-23 21:06:17 -070027import android.graphics.Region.Op;
Romain Guy407ec782011-08-24 17:06:58 -070028import android.opengl.GLUtils;
29import android.renderscript.Matrix4f;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070030import android.service.wallpaper.WallpaperService;
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -080031import android.util.Log;
Romain Guy407ec782011-08-24 17:06:58 -070032import android.view.Display;
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -070033import android.view.MotionEvent;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070034import android.view.SurfaceHolder;
Romain Guy407ec782011-08-24 17:06:58 -070035import android.view.WindowManager;
36
37import javax.microedition.khronos.egl.EGL10;
38import javax.microedition.khronos.egl.EGLConfig;
39import javax.microedition.khronos.egl.EGLContext;
40import javax.microedition.khronos.egl.EGLDisplay;
41import javax.microedition.khronos.egl.EGLSurface;
42import javax.microedition.khronos.opengles.GL;
43import java.io.IOException;
44import java.nio.ByteBuffer;
45import java.nio.ByteOrder;
46import java.nio.FloatBuffer;
47
48import static android.opengl.GLES20.*;
49import static javax.microedition.khronos.egl.EGL10.*;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070050
51/**
52 * Default built-in wallpaper that simply shows a static image.
53 */
Romain Guy407ec782011-08-24 17:06:58 -070054@SuppressWarnings({"UnusedDeclaration"})
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070055public class ImageWallpaper extends WallpaperService {
Jeff Brownfa2e5042011-01-23 13:14:23 -080056 private static final String TAG = "ImageWallpaper";
Romain Guy407ec782011-08-24 17:06:58 -070057 private static final String GL_LOG_TAG = "ImageWallpaperGL";
Jeff Brownfa2e5042011-01-23 13:14:23 -080058 private static final boolean DEBUG = false;
59
Dianne Hackbornba398392011-08-01 16:11:57 -070060 static final boolean FIXED_SIZED_SURFACE = true;
Romain Guy407ec782011-08-24 17:06:58 -070061 static final boolean USE_OPENGL = false;
Dianne Hackbornba398392011-08-01 16:11:57 -070062
Romain Guyef654bd2009-08-11 19:12:17 -070063 WallpaperManager mWallpaperManager;
Romain Guy407ec782011-08-24 17:06:58 -070064
65 boolean mIsHwAccelerated;
Dianne Hackborn759a39e2009-08-09 17:20:27 -070066
Romain Guyef654bd2009-08-11 19:12:17 -070067 @Override
68 public void onCreate() {
69 super.onCreate();
70 mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
Romain Guy407ec782011-08-24 17:06:58 -070071
72 //noinspection PointlessBooleanExpression,ConstantConditions
73 if (FIXED_SIZED_SURFACE && USE_OPENGL) {
74 WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
75 Display display = windowManager.getDefaultDisplay();
76 mIsHwAccelerated = ActivityManager.isHighEndGfx(display);
77 }
Romain Guyef654bd2009-08-11 19:12:17 -070078 }
79
80 public Engine onCreateEngine() {
Dianne Hackborn284ac932009-08-28 10:34:25 -070081 return new DrawableEngine();
Romain Guyef654bd2009-08-11 19:12:17 -070082 }
83
84 class DrawableEngine extends Engine {
Romain Guy407ec782011-08-24 17:06:58 -070085 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
86 static final int EGL_OPENGL_ES2_BIT = 4;
87
88 private final Object mLock = new Object[0];
89
90 // TODO: Not currently used, keeping around until we know we don't need it
91 @SuppressWarnings({"UnusedDeclaration"})
Dianne Hackborn284ac932009-08-28 10:34:25 -070092 private WallpaperObserver mReceiver;
Romain Guy407ec782011-08-24 17:06:58 -070093
94 Bitmap mBackground;
Dianne Hackbornba398392011-08-01 16:11:57 -070095 int mBackgroundWidth = -1, mBackgroundHeight = -1;
Dianne Hackborn7341d7a2009-08-14 11:37:52 -070096 float mXOffset;
97 float mYOffset;
Romain Guyef654bd2009-08-11 19:12:17 -070098
Jeff Brownfa2e5042011-01-23 13:14:23 -080099 boolean mVisible = true;
100 boolean mRedrawNeeded;
101 boolean mOffsetsChanged;
102 int mLastXTranslation;
103 int mLastYTranslation;
104
Romain Guy407ec782011-08-24 17:06:58 -0700105 private EGL10 mEgl;
106 private EGLDisplay mEglDisplay;
107 private EGLConfig mEglConfig;
108 private EGLContext mEglContext;
109 private EGLSurface mEglSurface;
110 private GL mGL;
111
112 private static final String sSimpleVS =
113 "attribute vec4 position;\n" +
114 "attribute vec2 texCoords;\n" +
115 "varying vec2 outTexCoords;\n" +
116 "uniform mat4 projection;\n" +
117 "\nvoid main(void) {\n" +
118 " outTexCoords = texCoords;\n" +
119 " gl_Position = projection * position;\n" +
120 "}\n\n";
121 private static final String sSimpleFS =
122 "precision mediump float;\n\n" +
123 "varying vec2 outTexCoords;\n" +
124 "uniform sampler2D texture;\n" +
125 "\nvoid main(void) {\n" +
126 " gl_FragColor = texture2D(texture, outTexCoords);\n" +
127 "}\n\n";
128
129 private static final int FLOAT_SIZE_BYTES = 4;
130 private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
131 private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
132 private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
133
Dianne Hackborn284ac932009-08-28 10:34:25 -0700134 class WallpaperObserver extends BroadcastReceiver {
135 public void onReceive(Context context, Intent intent) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800136 if (DEBUG) {
137 Log.d(TAG, "onReceive");
138 }
139
Jeff Brownfa2e5042011-01-23 13:14:23 -0800140 synchronized (mLock) {
Dianne Hackbornba398392011-08-01 16:11:57 -0700141 mBackgroundWidth = mBackgroundHeight = -1;
142 mBackground = null;
143 mRedrawNeeded = true;
Jeff Brown30bc34f2011-01-25 12:56:56 -0800144 drawFrameLocked();
Jeff Brownfa2e5042011-01-23 13:14:23 -0800145 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700146 }
147 }
148
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700149 @Override
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700150 public void onCreate(SurfaceHolder surfaceHolder) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800151 if (DEBUG) {
152 Log.d(TAG, "onCreate");
153 }
154
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700155 super.onCreate(surfaceHolder);
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700156
Romain Guy407ec782011-08-24 17:06:58 -0700157 // TODO: Don't need this currently because the wallpaper service
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700158 // will restart the image wallpaper whenever the image changes.
159 //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
160 //mReceiver = new WallpaperObserver();
161 //registerReceiver(mReceiver, filter, null, mHandler);
Jeff Brownfa2e5042011-01-23 13:14:23 -0800162
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800163 updateSurfaceSize(surfaceHolder);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700164 }
165
166 @Override
Dianne Hackborn284ac932009-08-28 10:34:25 -0700167 public void onDestroy() {
168 super.onDestroy();
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700169 if (mReceiver != null) {
170 unregisterReceiver(mReceiver);
171 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700172 }
173
174 @Override
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800175 public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
Dianne Hackborn912d9d12011-02-04 10:35:36 -0800176 super.onDesiredSizeChanged(desiredWidth, desiredHeight);
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800177 SurfaceHolder surfaceHolder = getSurfaceHolder();
178 if (surfaceHolder != null) {
179 updateSurfaceSize(surfaceHolder);
180 }
181 }
182
183 void updateSurfaceSize(SurfaceHolder surfaceHolder) {
Dianne Hackbornba398392011-08-01 16:11:57 -0700184 if (FIXED_SIZED_SURFACE) {
185 // Used a fixed size surface, because we are special. We can do
186 // this because we know the current design of window animations doesn't
187 // cause this to break.
188 surfaceHolder.setFixedSize(getDesiredMinimumWidth(), getDesiredMinimumHeight());
189 } else {
190 surfaceHolder.setSizeFromLayout();
191 }
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800192 }
193
194 @Override
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700195 public void onVisibilityChanged(boolean visible) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800196 if (DEBUG) {
197 Log.d(TAG, "onVisibilityChanged: visible=" + visible);
198 }
199
Jeff Brownfa2e5042011-01-23 13:14:23 -0800200 synchronized (mLock) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800201 if (mVisible != visible) {
202 if (DEBUG) {
203 Log.d(TAG, "Visibility changed to visible=" + visible);
204 }
205 mVisible = visible;
206 drawFrameLocked();
207 }
Jeff Brownfa2e5042011-01-23 13:14:23 -0800208 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700209 }
Jeff Brownfa2e5042011-01-23 13:14:23 -0800210
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700211 @Override
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700212 public void onTouchEvent(MotionEvent event) {
213 super.onTouchEvent(event);
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700214 }
215
216 @Override
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700217 public void onOffsetsChanged(float xOffset, float yOffset,
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800218 float xOffsetStep, float yOffsetStep,
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700219 int xPixels, int yPixels) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800220 if (DEBUG) {
221 Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset
222 + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep
223 + ", xPixels=" + xPixels + ", yPixels=" + yPixels);
224 }
225
Jeff Brownfa2e5042011-01-23 13:14:23 -0800226 synchronized (mLock) {
227 if (mXOffset != xOffset || mYOffset != yOffset) {
228 if (DEBUG) {
229 Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ").");
230 }
231 mXOffset = xOffset;
232 mYOffset = yOffset;
Jeff Brown30bc34f2011-01-25 12:56:56 -0800233 mOffsetsChanged = true;
Jeff Brownfa2e5042011-01-23 13:14:23 -0800234 }
Jeff Brown30bc34f2011-01-25 12:56:56 -0800235 drawFrameLocked();
Jeff Brownfa2e5042011-01-23 13:14:23 -0800236 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700237 }
238
239 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700240 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800241 if (DEBUG) {
242 Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height);
243 }
244
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700245 super.onSurfaceChanged(holder, format, width, height);
Jeff Brown30bc34f2011-01-25 12:56:56 -0800246
Jeff Brownfa2e5042011-01-23 13:14:23 -0800247 synchronized (mLock) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800248 mRedrawNeeded = true;
249 drawFrameLocked();
Jeff Brownfa2e5042011-01-23 13:14:23 -0800250 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700251 }
252
Jeff Brown30bc34f2011-01-25 12:56:56 -0800253 void drawFrameLocked() {
Jeff Brownfa2e5042011-01-23 13:14:23 -0800254 if (!mVisible) {
255 if (DEBUG) {
256 Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible.");
257 }
258 return;
259 }
260 if (!mRedrawNeeded && !mOffsetsChanged) {
261 if (DEBUG) {
262 Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
263 + "and offsets have not changed.");
264 }
265 return;
266 }
267
Dianne Hackbornba398392011-08-01 16:11:57 -0700268 if (mBackgroundWidth < 0 || mBackgroundHeight < 0) {
269 // If we don't yet know the size of the wallpaper bitmap,
270 // we need to get it now.
271 updateWallpaperLocked();
272 }
273
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700274 SurfaceHolder sh = getSurfaceHolder();
Jeff Brown033f63a2011-01-23 22:01:49 -0800275 final Rect frame = sh.getSurfaceFrame();
Jeff Brown033f63a2011-01-23 22:01:49 -0800276 final int dw = frame.width();
277 final int dh = frame.height();
Dianne Hackbornba398392011-08-01 16:11:57 -0700278 final int availw = dw - mBackgroundWidth;
279 final int availh = dh - mBackgroundHeight;
Jeff Brown033f63a2011-01-23 22:01:49 -0800280 int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2);
281 int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2);
282
283 mOffsetsChanged = false;
Romain Guy407ec782011-08-24 17:06:58 -0700284 if (!mRedrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
Jeff Brown033f63a2011-01-23 22:01:49 -0800285 if (DEBUG) {
286 Log.d(TAG, "Suppressed drawFrame since the image has not "
287 + "actually moved an integral number of pixels.");
288 }
289 return;
290 }
291 mRedrawNeeded = false;
292 mLastXTranslation = xPixels;
293 mLastYTranslation = yPixels;
294
Dianne Hackbornba398392011-08-01 16:11:57 -0700295 if (mBackground == null) {
296 // If we somehow got to this point after we have last flushed
297 // the wallpaper, well we really need it to draw again. So
298 // seems like we need to reload it. Ouch.
299 updateWallpaperLocked();
300 }
301
Romain Guy407ec782011-08-24 17:06:58 -0700302 if (mIsHwAccelerated) {
303 drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels);
304 } else {
305 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700306 }
Dianne Hackbornba398392011-08-01 16:11:57 -0700307
308 if (FIXED_SIZED_SURFACE) {
309 // If the surface is fixed-size, we should only need to
310 // draw it once and then we'll let the window manager
311 // position it appropriately. As such, we no longer needed
312 // the loaded bitmap. Yay!
313 mBackground = null;
314 mWallpaperManager.forgetLoadedWallpaper();
315 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700316 }
Romain Guyef654bd2009-08-11 19:12:17 -0700317
Jeff Brownfa2e5042011-01-23 13:14:23 -0800318 void updateWallpaperLocked() {
319 Throwable exception = null;
320 try {
Romain Guy407ec782011-08-24 17:06:58 -0700321 mBackground = mWallpaperManager.getBitmap();
Jeff Brownfa2e5042011-01-23 13:14:23 -0800322 } catch (RuntimeException e) {
323 exception = e;
324 } catch (OutOfMemoryError e) {
325 exception = e;
326 }
Romain Guy407ec782011-08-24 17:06:58 -0700327
Jeff Brownfa2e5042011-01-23 13:14:23 -0800328 if (exception != null) {
329 mBackground = null;
330 // Note that if we do fail at this, and the default wallpaper can't
331 // be loaded, we will go into a cycle. Don't do a build where the
332 // default wallpaper can't be loaded.
333 Log.w(TAG, "Unable to load wallpaper!", exception);
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800334 try {
Jeff Brownfa2e5042011-01-23 13:14:23 -0800335 mWallpaperManager.clear();
336 } catch (IOException ex) {
337 // now we're really screwed.
338 Log.w(TAG, "Unable reset to default wallpaper!", ex);
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800339 }
Romain Guyef654bd2009-08-11 19:12:17 -0700340 }
Romain Guy407ec782011-08-24 17:06:58 -0700341
342 mBackgroundWidth = mBackground != null ? mBackground.getWidth() : 0;
343 mBackgroundHeight = mBackground != null ? mBackground.getHeight() : 0;
344 }
345
346 private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) {
347 Canvas c = sh.lockCanvas();
348 if (c != null) {
349 try {
350 if (DEBUG) {
351 Log.d(TAG, "Redrawing: x=" + x + ", y=" + y);
352 }
353
354 c.translate(x, y);
355 if (w < 0 || h < 0) {
356 c.save(Canvas.CLIP_SAVE_FLAG);
357 c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE);
358 c.drawColor(0xff000000);
359 c.restore();
360 }
361 if (mBackground != null) {
362 c.drawBitmap(mBackground, 0, 0, null);
363 }
364 } finally {
365 sh.unlockCanvasAndPost(c);
366 }
367 }
368 }
369
370 private void drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
371 initGL(sh);
372
373 final float right = left + mBackgroundWidth;
374 final float bottom = top + mBackgroundHeight;
375
376 final Rect frame = sh.getSurfaceFrame();
377
378 final Matrix4f ortho = new Matrix4f();
379 ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
380
381 final FloatBuffer triangleVertices = createMesh(left, top, right, bottom);
382
383 final int texture = loadTexture(mBackground);
384 final int program = buildProgram(sSimpleVS, sSimpleFS);
385
386 final int attribPosition = glGetAttribLocation(program, "position");
387 final int attribTexCoords = glGetAttribLocation(program, "texCoords");
388 final int uniformTexture = glGetUniformLocation(program, "texture");
389 final int uniformProjection = glGetUniformLocation(program, "projection");
390
391 checkGlError();
392
393 glViewport(0, 0, frame.width(), frame.height());
394 glBindTexture(GL_TEXTURE_2D, texture);
395
396 glUseProgram(program);
397 glEnableVertexAttribArray(attribPosition);
398 glEnableVertexAttribArray(attribTexCoords);
399 glUniform1i(uniformTexture, 0);
400 glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0);
401
402 checkGlError();
403
404 if (w < 0 || h < 0) {
405 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
406 glClear(GL_COLOR_BUFFER_BIT);
407 }
408
409 // drawQuad
410 triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
411 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
412 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
413
414 triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
415 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
416 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
417
418 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
419
420 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
421 throw new RuntimeException("Cannot swap buffers");
422 }
423 checkEglError();
424
425 finishGL();
426 }
427
428 private FloatBuffer createMesh(int left, int top, float right, float bottom) {
429 final float[] verticesData = {
430 // X, Y, Z, U, V
431 left, bottom, 0.0f, 0.0f, 1.0f,
432 right, bottom, 0.0f, 1.0f, 1.0f,
433 left, top, 0.0f, 0.0f, 0.0f,
434 right, top, 0.0f, 1.0f, 0.0f,
435 };
436
437 final int bytes = verticesData.length * FLOAT_SIZE_BYTES;
438 final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order(
439 ByteOrder.nativeOrder()).asFloatBuffer();
440 triangleVertices.put(verticesData).position(0);
441 return triangleVertices;
442 }
443
444 private int loadTexture(Bitmap bitmap) {
445 int[] textures = new int[1];
446
447 glActiveTexture(GL_TEXTURE0);
448 glGenTextures(1, textures, 0);
449 checkGlError();
450
451 int texture = textures[0];
452 glBindTexture(GL_TEXTURE_2D, texture);
453 checkGlError();
454
455 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
456 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
457
458 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
459 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
460
461 GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
462 checkGlError();
463
464 bitmap.recycle();
465
466 return texture;
467 }
468
469 private int buildProgram(String vertex, String fragment) {
470 int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
471 if (vertexShader == 0) return 0;
472
473 int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
474 if (fragmentShader == 0) return 0;
475
476 int program = glCreateProgram();
477 glAttachShader(program, vertexShader);
478 checkGlError();
479
480 glAttachShader(program, fragmentShader);
481 checkGlError();
482
483 glLinkProgram(program);
484 checkGlError();
485
486 int[] status = new int[1];
487 glGetProgramiv(program, GL_LINK_STATUS, status, 0);
488 if (status[0] != GL_TRUE) {
489 String error = glGetProgramInfoLog(program);
490 Log.d(GL_LOG_TAG, "Error while linking program:\n" + error);
491 glDeleteShader(vertexShader);
492 glDeleteShader(fragmentShader);
493 glDeleteProgram(program);
494 return 0;
495 }
496
497 return program;
498 }
499
500 private int buildShader(String source, int type) {
501 int shader = glCreateShader(type);
502
503 glShaderSource(shader, source);
504 checkGlError();
505
506 glCompileShader(shader);
507 checkGlError();
508
509 int[] status = new int[1];
510 glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
511 if (status[0] != GL_TRUE) {
512 String error = glGetShaderInfoLog(shader);
513 Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error);
514 glDeleteShader(shader);
515 return 0;
516 }
517
518 return shader;
519 }
520
521 private void checkEglError() {
522 int error = mEgl.eglGetError();
523 if (error != EGL_SUCCESS) {
524 Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error));
525 }
526 }
527
528 private void checkGlError() {
529 int error = glGetError();
530 if (error != GL_NO_ERROR) {
531 Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable());
532 }
533 }
534
535 private void finishGL() {
536 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
537 mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
538 }
539
540 private void initGL(SurfaceHolder surfaceHolder) {
541 mEgl = (EGL10) EGLContext.getEGL();
542
543 mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
544 if (mEglDisplay == EGL_NO_DISPLAY) {
545 throw new RuntimeException("eglGetDisplay failed " +
546 GLUtils.getEGLErrorString(mEgl.eglGetError()));
547 }
548
549 int[] version = new int[2];
550 if (!mEgl.eglInitialize(mEglDisplay, version)) {
551 throw new RuntimeException("eglInitialize failed " +
552 GLUtils.getEGLErrorString(mEgl.eglGetError()));
553 }
554
555 mEglConfig = chooseEglConfig();
556 if (mEglConfig == null) {
557 throw new RuntimeException("eglConfig not initialized");
558 }
559
560 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
561
562 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
563
564 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
565 int error = mEgl.eglGetError();
566 if (error == EGL_BAD_NATIVE_WINDOW) {
567 Log.e(GL_LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
568 return;
569 }
570 throw new RuntimeException("createWindowSurface failed " +
571 GLUtils.getEGLErrorString(error));
572 }
573
574 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
575 throw new RuntimeException("eglMakeCurrent failed " +
576 GLUtils.getEGLErrorString(mEgl.eglGetError()));
577 }
578
579 mGL = mEglContext.getGL();
580 }
581
582
583 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
584 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
585 return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);
586 }
587
588 private EGLConfig chooseEglConfig() {
589 int[] configsCount = new int[1];
590 EGLConfig[] configs = new EGLConfig[1];
591 int[] configSpec = getConfig();
592 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
593 throw new IllegalArgumentException("eglChooseConfig failed " +
594 GLUtils.getEGLErrorString(mEgl.eglGetError()));
595 } else if (configsCount[0] > 0) {
596 return configs[0];
597 }
598 return null;
599 }
600
601 private int[] getConfig() {
602 return new int[] {
603 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
604 EGL_RED_SIZE, 8,
605 EGL_GREEN_SIZE, 8,
606 EGL_BLUE_SIZE, 8,
607 EGL_ALPHA_SIZE, 0,
608 EGL_DEPTH_SIZE, 0,
609 EGL_STENCIL_SIZE, 0,
610 EGL_NONE
611 };
Romain Guyef654bd2009-08-11 19:12:17 -0700612 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700613 }
614}