1/*
2 * Copyright (C) 2010 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
17package com.android.camera.ui;
18
19import android.graphics.Bitmap;
20import android.graphics.Bitmap.Config;
21import android.opengl.GLUtils;
22
23import com.android.camera.Util;
24
25import javax.microedition.khronos.opengles.GL11;
26import javax.microedition.khronos.opengles.GL11Ext;
27
28public abstract class Texture {
29
30    @SuppressWarnings("unused")
31    private static final String TAG = "Texture";
32    protected static final int UNSPECIFIED = -1;
33
34    public static final int STATE_UNLOADED = 0;
35    public static final int STATE_LOADED = 1;
36    public static final int STATE_ERROR = -1;
37
38    protected GL11 mGL;
39
40    protected int mId;
41    protected int mState;
42
43    protected int mWidth = UNSPECIFIED;
44    protected int mHeight = UNSPECIFIED;
45
46    private float mTexCoordWidth = 1.0f;
47    private float mTexCoordHeight = 1.0f;
48
49    protected Texture(GL11 gl, int id, int state) {
50        mGL = gl;
51        mId = id;
52        mState = state;
53    }
54
55    protected Texture() {
56        this(null, 0, STATE_UNLOADED);
57    }
58
59    protected void setSize(int width, int height) {
60        mWidth = width;
61        mHeight = height;
62    }
63
64    protected void setTexCoordSize(float width, float height) {
65        mTexCoordWidth = width;
66        mTexCoordHeight = height;
67    }
68
69    public int getId() {
70        return mId;
71    }
72
73    public int getWidth() {
74        return mWidth;
75    }
76
77    public int getHeight() {
78        return mHeight;
79    }
80
81    protected abstract Bitmap getBitmap();
82
83    protected abstract void freeBitmap(Bitmap bitmap);
84
85    public void deleteFromGL() {
86        if (mState == STATE_LOADED) {
87            mGL.glDeleteTextures(1, new int[]{mId}, 0);
88        }
89        mState = STATE_UNLOADED;
90    }
91
92    private void uploadToGL(GL11 gl) throws GLOutOfMemoryException {
93        Bitmap bitmap = getBitmap();
94        int glError = GL11.GL_NO_ERROR;
95        if (bitmap != null) {
96            int[] textureId = new int[1];
97            try {
98                // Define a vertically flipped crop rectangle for
99                // OES_draw_texture.
100                int[] cropRect = {0,  mHeight, mWidth, - mHeight};
101
102                // Upload the bitmap to a new texture.
103                gl.glGenTextures(1, textureId, 0);
104                gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId[0]);
105                gl.glTexParameteriv(GL11.GL_TEXTURE_2D,
106                        GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, 0);
107                gl.glTexParameteri(GL11.GL_TEXTURE_2D,
108                        GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE);
109                gl.glTexParameteri(GL11.GL_TEXTURE_2D,
110                        GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE);
111                gl.glTexParameterf(GL11.GL_TEXTURE_2D,
112                        GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
113                gl.glTexParameterf(GL11.GL_TEXTURE_2D,
114                        GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
115                GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0);
116            } finally {
117                freeBitmap(bitmap);
118            }
119            if (glError == GL11.GL_OUT_OF_MEMORY) {
120                throw new GLOutOfMemoryException();
121            }
122            if (glError != GL11.GL_NO_ERROR) {
123                mId = 0;
124                mState = STATE_UNLOADED;
125                throw new RuntimeException(
126                        "Texture upload fail, glError " + glError);
127            } else {
128                // Update texture state.
129                mGL = gl;
130                mId = textureId[0];
131                mState = Texture.STATE_LOADED;
132            }
133        } else {
134            mState = STATE_ERROR;
135            throw new RuntimeException("Texture load fail, no bitmap");
136        }
137    }
138
139    public void draw(GLRootView root, int x, int y) {
140        root.drawTexture(this, x, y, mWidth, mHeight);
141    }
142
143    public void draw(GLRootView root, int x, int y, int w, int h, float alpha) {
144        root.drawTexture(this, x, y, w, h, alpha);
145    }
146
147    protected boolean bind(GLRootView root, GL11 gl) {
148        if (mState == Texture.STATE_UNLOADED || mGL != gl) {
149            mState = Texture.STATE_UNLOADED;
150            try {
151                uploadToGL(gl);
152            } catch (GLOutOfMemoryException e) {
153                root.handleLowMemory();
154                return false;
155            }
156        } else {
157            gl.glBindTexture(GL11.GL_TEXTURE_2D, getId());
158        }
159        return true;
160    }
161
162    public void getTextureCoords(float coord[], int offset) {
163        float w = mTexCoordWidth;
164        float h = mTexCoordHeight;
165
166        coord[offset++] = 0;
167        coord[offset++] = 0;
168        coord[offset++] = w;
169        coord[offset++] = 0;
170        coord[offset++] = 0;
171        coord[offset++] = h;
172        coord[offset++] = w;
173        coord[offset] = h;
174    }
175
176    protected Bitmap generateGLCompatibleBitmap(int width, int height) {
177        int newWidth = Util.nextPowerOf2(width);
178        int newHeight = Util.nextPowerOf2(height);
179        mTexCoordWidth = (float) width / newWidth;
180        mTexCoordHeight = (float) height / newHeight;
181        return Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);
182    }
183}
184