Project

General

Profile

Download (10.3 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / DistortedTexture.java @ f8686932

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.library;
21

    
22
import android.graphics.Bitmap;
23
import android.graphics.Matrix;
24
import android.opengl.GLES20;
25
import android.opengl.GLUtils;
26

    
27
import java.util.Iterator;
28
import java.util.LinkedList;
29

    
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31
/**
32
 * Class which represents a OpenGL Texture object.
33
 * <p>
34
 * Create a Texture of arbitrary size and feed some pixels to it via the setTexture() method.
35
 * <p>
36
 * Keep all objects created in a static LinkedList. The point: we need to be able to mark
37
 * Textures for deletion, and delete all marked objects later at a convenient time (that's
38
 * because we can only delete from a thread that holds the OpenGL context so here we provide a
39
 * framework where one is able to mark for deletion at any time and actual deletion takes place
40
 * on the next render).
41
 */
42
public class DistortedTexture
43
  {
44
  private static boolean mListMarked = false;
45
  private static LinkedList<DistortedTexture> mList = new LinkedList<>();
46

    
47
  private static int mTextureH;
48

    
49
  private int mSizeX, mSizeY;  // in screen space
50
  float mHalfX, mHalfY;        // halves of the above
51
  private long mID;
52
  private boolean mMarked;
53

    
54
  private Bitmap[] mBmp= null; //
55
  int[] mTextureDataH;         // have to be shared among all the cloned Objects
56
  boolean[] mBitmapSet;        //
57

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59
// We have to flip vertically every single Bitmap that we get fed with.
60
//
61
// Reason: textures read from files are the only objects in OpenGL which have their origins at the
62
// upper-left corner. Everywhere else the origin is in the lower-left corner. Thus we have to flip.
63
// The alternative solution, namely inverting the y-coordinate of the TexCoord does not really work-
64
// i.e. it works only in case of rendering directly to the screen, but if we render to an FBO and
65
// then take the FBO and render to screen, (DistortedTree does so!) things get inverted as textures
66
// created from FBO have their origins in the lower-left... Mindfuck!
67

    
68
  private static Bitmap flipBitmap(Bitmap src)
69
    {
70
    Matrix matrix = new Matrix();
71
    matrix.preScale(1.0f,-1.0f);
72

    
73
    return Bitmap.createBitmap(src,0,0,src.getWidth(),src.getHeight(), matrix,true);
74
    }
75

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77
// must be called from a thread holding OpenGL Context
78

    
79
  void createTexture()
80
    {
81
    if( mBmp[0]!=null && mTextureDataH!=null )
82
      {
83
      //android.util.Log.e("Texture", "creating "+mID);
84

    
85
      if( mTextureDataH[0]==0 ) GLES20.glGenTextures(1, mTextureDataH, 0);
86

    
87
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
88
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
89
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
90
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
91
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );
92

    
93
      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, flipBitmap(mBmp[0]), 0);
94
      mBmp[0] = null;
95
      }
96
    }
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99
// must be called from a thread holding OpenGL Context
100

    
101
  private void deleteTexture()
102
    {
103
    if( mTextureDataH!=null && mTextureDataH[0]>0 )
104
      {
105
      //android.util.Log.e("Texture", "deleting "+mID);
106

    
107
      GLES20.glDeleteTextures(1, mTextureDataH, 0);
108

    
109
      mTextureDataH[0] = 0;
110
      mBitmapSet[0] = false;
111
      }
112

    
113
    mMarked = false;
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  long getID()
119
    {
120
    return mID;
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

    
125
  static void getUniforms(int mProgramH)
126
    {
127
    mTextureH= GLES20.glGetUniformLocation( mProgramH, "u_Texture");
128

    
129
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
130
    GLES20.glUniform1i(mTextureH, 0);
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  static synchronized void onDestroy()
136
    {
137
    mListMarked = false;
138
    mList.clear();
139
    }
140

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142
// must be called form a thread holding OpenGL Context
143

    
144
  static synchronized void deleteAllMarked()
145
    {
146
    if( mListMarked )
147
      {
148
      DistortedTexture tmp;
149
      Iterator<DistortedTexture> iterator = mList.iterator();
150

    
151
      while(iterator.hasNext())
152
        {
153
        tmp = iterator.next();
154

    
155
        if( tmp.mMarked )
156
          {
157
          tmp.deleteTexture();
158
          iterator.remove();
159
          }
160
        }
161

    
162
      mListMarked = false;
163
      }
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167
// PUBLIC API
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169
/**
170
 * Create empty texture of given dimensions.
171
 */
172
  public DistortedTexture(int width, int height)
173
    {
174
    mSizeX= width ; mHalfX = mSizeX/2.0f;
175
    mSizeY= height; mHalfY = mSizeY/2.0f;
176

    
177
    mTextureDataH   = new int[1];
178
    mTextureDataH[0]= 0;
179
    mBmp            = new Bitmap[1];
180
    mBmp[0]         = null;
181
    mBitmapSet      = new boolean[1];
182
    mBitmapSet[0]   = false;
183
    mID             = 0;
184
    mMarked         = false;
185

    
186
    mList.add(this);
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
/**
192
 * Copy constructor.
193
 * <p>
194
 * Whatever we do not clone gets created just like in the default constructor.
195
 *
196
 * @param dt    Source object to create our object from
197
 * @param flags A bitmask of values specifying what to copy.
198
 *              Only possibilities: CLONE_BITMAP or CLONE_NOTHING.
199
 */
200

    
201
  public DistortedTexture(DistortedTexture dt, int flags)
202
    {
203
    mSizeX= dt.mSizeX ; mHalfX = mSizeX/2.0f;
204
    mSizeY= dt.mSizeY ; mHalfY = mSizeY/2.0f;
205

    
206
    if( (flags & Distorted.CLONE_BITMAP) != 0 )
207
      {
208
      mTextureDataH = dt.mTextureDataH;
209
      mBmp          = dt.mBmp;
210
      mBitmapSet    = dt.mBitmapSet;
211
      mID           = dt.getID();
212
      }
213
    else
214
      {
215
      mTextureDataH   = new int[1];
216
      mTextureDataH[0]= 0;
217
      mBitmapSet      = new boolean[1];
218
      mBitmapSet[0]   = false;
219
      mBmp            = new Bitmap[1];
220
      mBmp[0]         = null;
221
      mID             = 0;
222
      }
223

    
224
    mMarked = false;
225

    
226
    mList.add(this);
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230
/**
231
 * Mark the underlying OpenGL object for deletion. Actual deletion will take place on the next render.
232
 */
233
  public void markForDeletion()
234
    {
235
    //android.util.Log.e("Texture", "marking for deletion "+mID);
236

    
237
    mListMarked = true;
238
    mMarked     = true;
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242
/**
243
 * Sets the underlying android.graphics.Bitmap object.
244
 * <p>
245
 * You can only recycle() the passed Bitmap once the OpenGL context gets created (i.e. after call
246
 * to GLSurfaceView.onSurfaceCreated) because only after this point can the Library upload it to the GPU!
247
 *
248
 * @param bmp The android.graphics.Bitmap object to apply effects to and display.
249
 */
250

    
251
  public void setTexture(Bitmap bmp)
252
    {
253
    mBitmapSet[0] = true;
254
    mBmp[0]       = bmp;
255
    mID           = bmp.hashCode();
256

    
257
    //android.util.Log.e("Texture", "setting new bitmap "+mID);
258
    }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261
/**
262
 * Returns the height of the Texture.
263
 *
264
 * @return height of the object, in pixels.
265
 */
266
  public int getWidth()
267
    {
268
    return mSizeX;
269
    }
270

    
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272
/**
273
 * Returns the width of the Texture.
274
 *
275
 * @return width of the Object, in pixels.
276
 */
277
  public int getHeight()
278
    {
279
    return mSizeY;
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283
/**
284
 * Returns the depth of the Texture.
285
 * <p>
286
 * Admittedly quite a strange method. Why do we need to pass a Grid to it? Because one cannot determine
287
 * 'depth' of a texture when rendered based only on the texture itself, that depends on the Grid it is
288
 * rendered with.
289
 *
290
 * @return depth of the Object, in pixels.
291
 */
292
  public int getDepth(GridObject grid)
293
    {
294
    return grid==null ? 0 : (int)(mSizeX*grid.zFactor);
295
    }
296
  }
(4-4/16)