Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedFramebuffer.java @ 8e34674e

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
 *
32
 * User is able to create either WRITE-only Framebuffers from objects already constructed outside
33
 * of the library (the first constructor; primary use case: the screen) or an offscreen READ-WRITE
34
 * FBOs (used by the DistortedNode, but also can be used by external users of the library)
35
 *
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 place 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,mDistance;
60
  float[] mProjectionMatrix;
61

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

    
64
  private void createProjection()
65
    {
66
    float ratio  = (float) mWidth / mHeight;
67
    float left   =-ratio;          //
68
    float right  = ratio;          // Create a new perspective projection matrix.
69
    float bottom = -1.0f;          //
70
    float top    =  1.0f;          // any change to those values will have serious consequences!
71
    float near, far;
72

    
73
    if( mFOV>0.0f )  // perspective projection
74
      {
75
      near= (float)(top / Math.tan(mFOV*Math.PI/360));
76
      mDistance = (int)(mHeight*near/(top-bottom));
77
      far = 2*mDistance-near;
78

    
79
      if( far<=0 )
80
        {
81
        android.util.Log.e("FBO", "error: far<=0. width="+mWidth+" height="+mHeight+
82
                           " mFOV="+mFOV+" mDistance="+mDistance+" far="+far+" near="+near);
83
        }
84
      else
85
        Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
86
      }
87
    else                      // parallel projection
88
      {
89
      near= (float)(top / Math.tan(Math.PI/360));
90
      mDistance = (int)(mHeight*near/(top-bottom));
91
      far = 2*mDistance-near;
92

    
93
      Matrix.orthoM(mProjectionMatrix, 0, -mWidth/2, mWidth/2,-mHeight/2, mHeight/2, near, far);
94
      }
95

    
96
    mDepth = (int)((far-near)/2);
97
    }
98

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

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

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

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

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

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

    
131
    return true;
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135
// must be called form a thread holding OpenGL Context
136

    
137
  private void deleteFBO()
138
    {
139
    android.util.Log.e("FBO", "deleting ("+mWidth+","+mHeight+") "+fboIds[0]);
140

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

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

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149
// must be called from a thread holding OpenGL Context
150

    
151
  private void delete()
152
    {
153
    if( texIds[0]>=0 ) deleteFBO();
154

    
155
    mProjectionMatrix = null;
156
    mMarked = false;
157
    }
158

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

    
161
  void reset()
162
    {
163
    texIds[0] = TEXTURE_NOT_CREATED_YET;
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  static synchronized void release()
169
    {
170
    mListMarked = false;
171
    mList.clear();
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175
// must be called form a thread holding OpenGL Context
176

    
177
  static synchronized void deleteAllMarked()
178
    {
179
    if( mListMarked )
180
      {
181
      DistortedFramebuffer tmp;
182
      Iterator<DistortedFramebuffer> iterator = mList.iterator();
183

    
184
      while(iterator.hasNext())
185
        {
186
        tmp = iterator.next();
187

    
188
        if( tmp.mMarked )
189
          {
190
          tmp.delete();
191
          iterator.remove();
192
          }
193
        }
194

    
195
      mListMarked = false;
196
      }
197
    }
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199
// PUBLIC API
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201
/**
202
 * Create a new offscreen FBO.
203
 *
204
 * @param width Width of the COLOR attachment.
205
 * @param height Height of the COLOR attachment.
206
 */
207
  public DistortedFramebuffer(int width, int height)
208
    {
209
    mProjectionMatrix = new float[16];
210

    
211
    mHeight        = height;
212
    mWidth         = width;
213
    fboIds[0]      = -1;
214
    texIds[0]      = TEXTURE_NOT_CREATED_YET;
215
    mFOV           = 60.0f;
216
    mX             = 0.0f;
217
    mY             = 0.0f;
218

    
219
    mMarked = false;
220

    
221
    createProjection();
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225
/**
226
 * Create a new DistortedFramebuffer from an already created OpenGL Framebuffer.
227
 *
228
 * @param fbo the ID of a OpenGL Framebuffer object. Typically 0 (the screen)
229
 */
230
  public DistortedFramebuffer(int fbo)
231
    {
232
    mProjectionMatrix = new float[16];
233

    
234
    fboIds[0]      = fbo;
235
    texIds[0]      = TEXTURE_DONT_CREATE;
236
    mFOV           = 60.0f;
237
    mX             = 0.0f;
238
    mY             = 0.0f;
239

    
240
    mMarked = false;
241
    }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244
/**
245
 * Mark the underlying OpenGL object for deletion. Actual deletion will take place on the next render.
246
 */
247
  public void markForDeletion()
248
    {
249
    android.util.Log.e("FBO", "marking for deletion ("+mWidth+","+mHeight+") "+fboIds[0]);
250

    
251
    mListMarked = true;
252
    mMarked     = true;
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256
/**
257
 * Create new Projection matrix.
258
 *
259
 * @param fov Vertical 'field of view' of the Projection frustrum (in degrees).
260
 * @param x X-coordinate of the point at which our camera looks at. -1<x<1
261
 * @param y Y-coordinate of the point at which our camera looks at. -1<y<1
262
 */
263
  public void setProjection(float fov, float x, float y)
264
    {
265
    mFOV = fov;
266
    mX   = x;
267
    mY   = y;
268

    
269
    createProjection();
270
    }
271

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

    
292
      createProjection();
293

    
294
      if( texIds[0]>0 ) markForDeletion();
295
      }
296
    }
297

    
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299
/**
300
 * Set this as the Framebuffer to write to.
301
 */
302

    
303
  public void setOutput()
304
    {
305
    if( texIds[0]==TEXTURE_NOT_CREATED_YET ) createFBO();
306

    
307
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
308
    }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311
/**
312
 * Set this as the Framebuffer to read from.
313
 */
314

    
315
  public void setInput()
316
    {
317
    if( texIds[0]==TEXTURE_NOT_CREATED_YET ) createFBO();
318

    
319
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
320
    }
321

    
322
  }
(6-6/17)