Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedFramebuffer.java @ 46e25345

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.opengl.GLES20;
23
import android.opengl.Matrix;
24

    
25
import java.util.Iterator;
26
import java.util.LinkedList;
27

    
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29
/**
30
 * Class which represents a OpenGL Framebuffer object.
31
 * <p>
32
 * User is able to create either Framebuffers from objects already constructed outside
33
 * of the library (the first constructor; primary use case: the screen) or an offscreen
34
 * FBOs (used by the DistortedObjectTree, but also can be used by external users of the library)
35
 * <p>
36
 * Also, keep all objects created in a static LinkedList. The point: we need to be able to mark
37
 * Framebuffers 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 DistortedFramebuffer
43
  {
44
  private static final int TEXTURE_FAILED_TO_CREATE = -1;
45
  private static final int TEXTURE_NOT_CREATED_YET  = -2;
46
  private static final int TEXTURE_DONT_CREATE      = -3;
47

    
48
  private static boolean mListMarked = false;
49
  private static LinkedList<DistortedFramebuffer> mList = new LinkedList<>();
50

    
51
  private float mX, mY;
52
  private float mFOV;
53

    
54
  private int[] texIds = new int[1];
55
  private int[] fboIds = new int[1];
56

    
57
  private boolean mMarked;
58

    
59
  int mWidth,mHeight,mDepth;
60
  float mDistance;
61
  float[] mProjectionMatrix;
62

    
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

    
65
  private void createProjection()
66
    {
67
    if( mWidth>0 && mHeight>1 )
68
      {
69
      if( mFOV>0.0f )  // perspective projection
70
        {
71
        float left   = (-mX-mWidth /2.0f)/mHeight;
72
        float right  = (-mX+mWidth /2.0f)/mHeight;
73
        float bottom = (-mY-mHeight/2.0f)/mHeight;
74
        float top    = (-mY+mHeight/2.0f)/mHeight;
75
        float near   = (top-bottom) / (2.0f*(float)Math.tan(mFOV*Math.PI/360));
76
        mDistance    = mHeight*near/(top-bottom);
77
        float far    = 2*mDistance-near;
78
        mDepth       = (int)((far-near)/2);
79

    
80
        Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
81
        }
82
      else             // parallel projection
83
        {
84
        float left   = -mX-mWidth /2.0f;
85
        float right  = -mX+mWidth /2.0f;
86
        float bottom = -mY-mHeight/2.0f;
87
        float top    = -mY+mHeight/2.0f;
88
        float near   = (mWidth+mHeight)/2;
89
        mDistance    = 2*near;
90
        float far    = 3*near;
91
        mDepth       = (int)near;
92

    
93
        Matrix.orthoM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
94
        }
95
      }
96
    }
97

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

    
101
  private boolean createFBO()
102
    {
103
    GLES20.glGenTextures(1, texIds, 0);
104
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
105
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
106
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
107
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
108
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
109
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mWidth, mHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
110

    
111
    GLES20.glGenFramebuffers(1, fboIds, 0);
112
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
113
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texIds[0], 0);
114

    
115
    int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
116

    
117
    if(status != GLES20.GL_FRAMEBUFFER_COMPLETE)
118
      {
119
      android.util.Log.e("DistortedFramebuffer", "failed to create framebuffer, error="+status);
120
      GLES20.glDeleteTextures(1, texIds, 0);
121
      GLES20.glDeleteFramebuffers(1, fboIds, 0);
122
      fboIds[0] = 0;
123
      texIds[0] = TEXTURE_FAILED_TO_CREATE;
124
      return false;
125
      }
126

    
127
    mList.add(this);
128
    //android.util.Log.e("FBO", "created ("+mWidth+","+mHeight+") "+fboIds[0]);
129

    
130
    return true;
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
// must be called from a thread holding OpenGL Context
135

    
136
  private void deleteFBO()
137
    {
138
    if( texIds[0]>=0 )
139
      {
140
      //android.util.Log.e("FBO", "deleting ("+mWidth+","+mHeight+") "+fboIds[0]);
141

    
142
      GLES20.glDeleteTextures(1, texIds, 0);
143
      GLES20.glDeleteFramebuffers(1, fboIds, 0);
144

    
145
      fboIds[0] = 0;
146
      texIds[0] = TEXTURE_NOT_CREATED_YET;
147
      }
148

    
149
    mMarked = false;
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  void reset()
155
    {
156
    texIds[0] = TEXTURE_NOT_CREATED_YET;
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

    
161
  static synchronized void release()
162
    {
163
    mListMarked = false;
164
    mList.clear();
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
// must be called form a thread holding OpenGL Context
169

    
170
  static synchronized void deleteAllMarked()
171
    {
172
    if( mListMarked )
173
      {
174
      DistortedFramebuffer tmp;
175
      Iterator<DistortedFramebuffer> iterator = mList.iterator();
176

    
177
      while(iterator.hasNext())
178
        {
179
        tmp = iterator.next();
180

    
181
        if( tmp.mMarked )
182
          {
183
          tmp.deleteFBO();
184
          iterator.remove();
185
          }
186
        }
187

    
188
      mListMarked = false;
189
      }
190
    }
191

    
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
// PUBLIC API
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195
/**
196
 * Create a new offscreen Framebuffer.
197
 *
198
 * @param width Width of the COLOR attachment.
199
 * @param height Height of the COLOR attachment.
200
 */
201
  public DistortedFramebuffer(int width, int height)
202
    {
203
    mProjectionMatrix = new float[16];
204

    
205
    mHeight  = height;
206
    mWidth   = width;
207
    fboIds[0]= -1;
208
    texIds[0]= TEXTURE_NOT_CREATED_YET;
209
    mFOV     = 60.0f;
210
    mX       = 0.0f;
211
    mY       = 0.0f;
212
    mMarked  = false;
213

    
214
    createProjection();
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218
/**
219
 * Create a new Framebuffer from an already created OpenGL Framebuffer.
220
 * <p>
221
 * Has to be followed by a 'resize()' to set the size.
222
 *
223
 * @param fbo the ID of a OpenGL Framebuffer object. Typically 0 (the screen)
224
 */
225
  public DistortedFramebuffer(int fbo)
226
    {
227
    mProjectionMatrix = new float[16];
228

    
229
    fboIds[0]= fbo;
230
    texIds[0]= TEXTURE_DONT_CREATE;
231
    mFOV     = 60.0f;
232
    mX       = 0.0f;
233
    mY       = 0.0f;
234
    mMarked  = false;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238
/**
239
 * Mark the underlying OpenGL object for deletion. Actual deletion will take place on the next render.
240
 */
241
  public void markForDeletion()
242
    {
243
    //android.util.Log.e("FBO", "marking for deletion ("+mWidth+","+mHeight+") "+fboIds[0]);
244

    
245
    mListMarked = true;
246
    mMarked     = true;
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250
/**
251
 * Create new Projection matrix.
252
 *
253
 * @param fov Vertical 'field of view' of the Projection frustrum (in degrees).
254
 * @param x X-coordinate of the point at which our camera looks at. 0 is the center.
255
 * @param y Y-coordinate of the point at which our camera looks at. 0 is the center.
256
 */
257
  public void setProjection(float fov, float x, float y)
258
    {
259
    mFOV = fov;
260
    mX   = x;
261
    mY   = y;
262

    
263
    createProjection();
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267
/**
268
 * Resize the underlying Framebuffer.
269
 *
270
 * As the Framebuffer is not created until the first render, typical usage of this API is actually
271
 * to set the size of an not-yet-created Framebuffer of an object that has been created with the
272
 * second constructor.
273
 * <p>
274
 * Fully creating an object, rendering to it, then resizing mid-render is also possible. Actual
275
 * resize takes place on the next render.
276
 *
277
 * @param width The new width.
278
 * @param height The new height.
279
 */
280
  public void resize(int width, int height)
281
    {
282
    if( mWidth!=width || mHeight!=height )
283
      {
284
      mWidth = width;
285
      mHeight= height;
286

    
287
      createProjection();
288

    
289
      if( texIds[0]>0 ) markForDeletion();
290
      }
291
    }
292

    
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294
/**
295
 *  Set this as the Framebuffer to write to.
296
 */
297
  public void setAsOutput()
298
    {
299
    if( texIds[0]==TEXTURE_NOT_CREATED_YET ) createFBO();
300

    
301
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305
/**
306
 *  Set this as the Framebuffer to read from.
307
 */
308
  public void setAsInput()
309
    {
310
    if( texIds[0]==TEXTURE_NOT_CREATED_YET ) createFBO();
311

    
312
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
313
    }
314

    
315
  }
(3-3/15)