1f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka/*
2f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Copyright (C) 2010 The Android Open Source Project
3f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka *
4f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
5f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * you may not use this file except in compliance with the License.
6f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * You may obtain a copy of the License at
7f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka *
8f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
9f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka *
10f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Unless required by applicable law or agreed to in writing, software
11f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
12f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * See the License for the specific language governing permissions and
14f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * limitations under the License.
15f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */
16f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
17f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapackage com.android.gallery3d.glrenderer;
18f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
19f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.util.Log;
20f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
21f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport com.android.gallery3d.common.Utils;
22f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
23f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.util.WeakHashMap;
24f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
25f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// BasicTexture is a Texture corresponds to a real GL texture.
26f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// The state of a BasicTexture indicates whether its data is loaded to GL memory.
27f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// If a BasicTexture is loaded into GL memory, it has a GL texture id.
28f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapublic abstract class BasicTexture implements Texture {
29f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
30f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    private static final String TAG = "BasicTexture";
31f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected static final int UNSPECIFIED = -1;
32f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
33f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected static final int STATE_UNLOADED = 0;
34f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected static final int STATE_LOADED = 1;
35f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected static final int STATE_ERROR = -1;
36f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
37f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // Log a warning if a texture is larger along a dimension
38f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    private static final int MAX_TEXTURE_SIZE = 4096;
39f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
40f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected int mId = -1;
41f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected int mState;
42f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
43f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected int mWidth = UNSPECIFIED;
44f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected int mHeight = UNSPECIFIED;
45f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
46f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected int mTextureWidth;
47f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected int mTextureHeight;
48f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
49f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected GLCanvas mCanvasRef = null;
50f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    private static WeakHashMap<BasicTexture, Object> sAllTextures
51f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            = new WeakHashMap<BasicTexture, Object>();
52f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    private static ThreadLocal sInFinalizer = new ThreadLocal();
53f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
54f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected BasicTexture(GLCanvas canvas, int id, int state) {
55f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        setAssociatedCanvas(canvas);
56f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mId = id;
57f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mState = state;
58f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        synchronized (sAllTextures) {
59f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            sAllTextures.put(this, null);
60f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        }
61f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
62f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
63f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected BasicTexture() {
64f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        this(null, 0, STATE_UNLOADED);
65f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
66f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
67f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected void setAssociatedCanvas(GLCanvas canvas) {
68f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mCanvasRef = canvas;
69f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
70f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
71f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    /**
72f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka     * Sets the content size of this texture. In OpenGL, the actual texture
73f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka     * size must be of power of 2, the size of the content may be smaller.
74f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka     */
75f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public void setSize(int width, int height) {
76f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mWidth = width;
77f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mHeight = height;
78f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0;
79f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0;
80f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) {
81f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            Log.w(TAG, String.format("texture is too large: %d x %d",
82f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka                    mTextureWidth, mTextureHeight), new Exception());
83f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        }
84f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
85f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
86f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public int getId() {
87f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        return mId;
88f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
89f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
90f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    @Override
91f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public int getWidth() {
92f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        return mWidth;
93f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
94f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
95f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    @Override
96f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public int getHeight() {
97f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        return mHeight;
98f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
99f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
100f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // Returns the width rounded to the next power of 2.
101f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public int getTextureWidth() {
102f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        return mTextureWidth;
103f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
104f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
105f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // Returns the height rounded to the next power of 2.
106f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public int getTextureHeight() {
107f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        return mTextureHeight;
108f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
109f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
110f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    @Override
111f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public void draw(GLCanvas canvas, int x, int y) {
112f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        canvas.drawTexture(this, x, y, getWidth(), getHeight());
113f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
114f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
115f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    @Override
116f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public void draw(GLCanvas canvas, int x, int y, int w, int h) {
117f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        canvas.drawTexture(this, x, y, w, h);
118f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
119f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
120f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // onBind is called before GLCanvas binds this texture.
121f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // It should make sure the data is uploaded to GL memory.
122f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    abstract protected boolean onBind(GLCanvas canvas);
123f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
124f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public boolean isLoaded() {
125f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        return mState == STATE_LOADED;
126f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
127f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
128f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // recycle() is called when the texture will never be used again,
129f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // so it can free all resources.
130f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public void recycle() {
131f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        freeResource();
132f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
133f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
134f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // yield() is called when the texture will not be used temporarily,
135f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // so it can free some resources.
136f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // The default implementation unloads the texture from GL memory, so
137f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // the subclass should make sure it can reload the texture to GL memory
138f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    // later, or it will have to override this method.
139f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public void yield() {
140f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        freeResource();
141f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
142f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
143f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    private void freeResource() {
144f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        GLCanvas canvas = mCanvasRef;
145f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        if (canvas != null && mId != -1) {
146f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            canvas.unloadTexture(this);
147f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            mId = -1; // Don't free it again.
148f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        }
149f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        mState = STATE_UNLOADED;
150f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        setAssociatedCanvas(null);
151f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
152f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
153f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    @Override
154f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    protected void finalize() {
155f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        sInFinalizer.set(BasicTexture.class);
156f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        recycle();
157f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        sInFinalizer.set(null);
158f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
159f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
160f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public static void yieldAllTextures() {
161f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        synchronized (sAllTextures) {
162f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            for (BasicTexture t : sAllTextures.keySet()) {
163f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka                t.yield();
164f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            }
165f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        }
166f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
167f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka
168f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    public static void invalidateAllTextures() {
169f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        synchronized (sAllTextures) {
170f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            for (BasicTexture t : sAllTextures.keySet()) {
171f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka                t.mState = STATE_UNLOADED;
172f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka                t.setAssociatedCanvas(null);
173f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka            }
174f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka        }
175f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka    }
176f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka}
177