Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedFramebuffer.java @ 390ebefc

1 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 8e34674e Leszek Koltunski
import java.util.Iterator;
26
import java.util.LinkedList;
27
28 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
29 dedacd82 Leszek Koltunski
/**
30
 * Class which represents a OpenGL Framebuffer object.
31 71c3fecc Leszek Koltunski
 * <p>
32 dedacd82 Leszek Koltunski
 * 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 71c3fecc Leszek Koltunski
 * <p>
36 8e34674e Leszek Koltunski
 * 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 dedacd82 Leszek Koltunski
 */
42 ed13a5de Leszek Koltunski
public class DistortedFramebuffer
43 f6fb3c6d Leszek Koltunski
  {
44
  private static final int TEXTURE_FAILED_TO_CREATE = -1;
45
  private static final int TEXTURE_NOT_CREATED_YET  = -2;
46 b448e6b9 Leszek Koltunski
  private static final int TEXTURE_DONT_CREATE      = -3;
47 f6fb3c6d Leszek Koltunski
48 8e34674e Leszek Koltunski
  private static boolean mListMarked = false;
49
  private static LinkedList<DistortedFramebuffer> mList = new LinkedList<>();
50
51 f6fb3c6d Leszek Koltunski
  private float mX, mY;
52
  private float mFOV;
53
54 7304d89f Leszek Koltunski
  private int[] texIds = new int[1];
55
  private int[] fboIds = new int[1];
56
57 8e34674e Leszek Koltunski
  private boolean mMarked;
58
59 f6fb3c6d Leszek Koltunski
  int mWidth,mHeight,mDepth,mDistance;
60
  float[] mProjectionMatrix;
61 bd3da5b2 Leszek Koltunski
62 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
63
64
  private void createProjection()
65
    {
66 98455aa2 Leszek Koltunski
    if( mWidth>0 && mHeight>0 )
67 f6fb3c6d Leszek Koltunski
      {
68 98455aa2 Leszek Koltunski
      if( mFOV>0.0f )  // perspective projection
69 16d8b8f3 Leszek Koltunski
        {
70 390ebefc Leszek Koltunski
        float left   =(-mX-mWidth/2 )/mHeight;
71
        float right  =(-mX+mWidth/2 )/mHeight;
72
        float bottom =(-mY-mHeight/2)/mHeight;
73
        float top    =(-mY+mHeight/2)/mHeight;
74 98455aa2 Leszek Koltunski
        float near= (float)( (top-bottom) / (2*Math.tan(mFOV*Math.PI/360)) );
75
        mDistance = (int)(mHeight*near/(top-bottom));
76
        float far = 2*mDistance-near;
77
        mDepth = (int)((far-near)/2);
78
79 16d8b8f3 Leszek Koltunski
        Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
80 98455aa2 Leszek Koltunski
        }
81
      else             // parallel projection
82
        {
83
        float left   =-mX-mWidth/2;
84
        float right  =-mX+mWidth/2;
85
        float bottom =-mY-mHeight/2;
86
        float top    =-mY+mHeight/2;
87
        float near= (float)( (top-bottom) / (2*Math.tan(Math.PI/360)) );
88
        mDistance = (int)(mHeight*near/(top-bottom));
89
        float far = 2*mDistance-near;
90
        mDepth = (int)((far-near)/2);
91 f6fb3c6d Leszek Koltunski
92 98455aa2 Leszek Koltunski
        Matrix.orthoM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
93
        }
94 f6fb3c6d Leszek Koltunski
      }
95
    }
96
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98
// must be called form a thread holding OpenGL Context
99
100
  private boolean createFBO()
101
    {
102 64a642c1 Leszek Koltunski
    GLES20.glGenTextures(1, texIds, 0);
103 7304d89f Leszek Koltunski
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
104 f6fb3c6d Leszek Koltunski
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
105
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
106
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
107
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
108
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mWidth, mHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
109
110 64a642c1 Leszek Koltunski
    GLES20.glGenFramebuffers(1, fboIds, 0);
111
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
112 7304d89f Leszek Koltunski
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texIds[0], 0);
113 dedacd82 Leszek Koltunski
114 f6fb3c6d Leszek Koltunski
    int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
115
116
    if(status != GLES20.GL_FRAMEBUFFER_COMPLETE)
117
      {
118 64a642c1 Leszek Koltunski
      android.util.Log.e("DistortedFramebuffer", "failed to create framebuffer, error="+status);
119
      GLES20.glDeleteTextures(1, texIds, 0);
120
      GLES20.glDeleteFramebuffers(1, fboIds, 0);
121 7304d89f Leszek Koltunski
      fboIds[0] = 0;
122
      texIds[0] = TEXTURE_FAILED_TO_CREATE;
123 f6fb3c6d Leszek Koltunski
      return false;
124
      }
125
126 8e34674e Leszek Koltunski
    mList.add(this);
127 dedacd82 Leszek Koltunski
    android.util.Log.e("FBO", "created ("+mWidth+","+mHeight+") "+fboIds[0]);
128 16d8b8f3 Leszek Koltunski
129 f6fb3c6d Leszek Koltunski
    return true;
130
    }
131
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133 bd3da5b2 Leszek Koltunski
// must be called form a thread holding OpenGL Context
134 f6fb3c6d Leszek Koltunski
135
  private void deleteFBO()
136
    {
137 7304d89f Leszek Koltunski
    android.util.Log.e("FBO", "deleting ("+mWidth+","+mHeight+") "+fboIds[0]);
138 f6fb3c6d Leszek Koltunski
139 64a642c1 Leszek Koltunski
    GLES20.glDeleteTextures(1, texIds, 0);
140
    GLES20.glDeleteFramebuffers(1, fboIds, 0);
141 f6fb3c6d Leszek Koltunski
142 7304d89f Leszek Koltunski
    fboIds[0] = 0;
143
    texIds[0] = TEXTURE_NOT_CREATED_YET;
144 f6fb3c6d Leszek Koltunski
    }
145
146 bd3da5b2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
147 16d8b8f3 Leszek Koltunski
// must be called from a thread holding OpenGL Context
148 bd3da5b2 Leszek Koltunski
149 8e34674e Leszek Koltunski
  private void delete()
150 bd3da5b2 Leszek Koltunski
    {
151 7304d89f Leszek Koltunski
    if( texIds[0]>=0 ) deleteFBO();
152 bd3da5b2 Leszek Koltunski
153
    mProjectionMatrix = null;
154
    mMarked = false;
155
    }
156
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158
159
  void reset()
160
    {
161 7304d89f Leszek Koltunski
    texIds[0] = TEXTURE_NOT_CREATED_YET;
162 bd3da5b2 Leszek Koltunski
    }
163
164 8e34674e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
165
166
  static synchronized void release()
167
    {
168
    mListMarked = false;
169
    mList.clear();
170
    }
171
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173
// must be called form a thread holding OpenGL Context
174
175
  static synchronized void deleteAllMarked()
176
    {
177
    if( mListMarked )
178
      {
179
      DistortedFramebuffer tmp;
180
      Iterator<DistortedFramebuffer> iterator = mList.iterator();
181
182
      while(iterator.hasNext())
183
        {
184
        tmp = iterator.next();
185
186
        if( tmp.mMarked )
187
          {
188
          tmp.delete();
189
          iterator.remove();
190
          }
191
        }
192
193
      mListMarked = false;
194
      }
195
    }
196 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
197
// PUBLIC API
198 dedacd82 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
199
/**
200
 * Create a new offscreen FBO.
201
 *
202
 * @param width Width of the COLOR attachment.
203
 * @param height Height of the COLOR attachment.
204
 */
205 ed13a5de Leszek Koltunski
  public DistortedFramebuffer(int width, int height)
206 f6fb3c6d Leszek Koltunski
    {
207
    mProjectionMatrix = new float[16];
208
209
    mHeight        = height;
210
    mWidth         = width;
211 7304d89f Leszek Koltunski
    fboIds[0]      = -1;
212
    texIds[0]      = TEXTURE_NOT_CREATED_YET;
213 b448e6b9 Leszek Koltunski
    mFOV           = 60.0f;
214 f6fb3c6d Leszek Koltunski
    mX             = 0.0f;
215
    mY             = 0.0f;
216
217 bd3da5b2 Leszek Koltunski
    mMarked = false;
218
219 f6fb3c6d Leszek Koltunski
    createProjection();
220
    }
221
222 b448e6b9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
223 dedacd82 Leszek Koltunski
/**
224
 * Create a new DistortedFramebuffer from an already created OpenGL Framebuffer.
225
 *
226
 * @param fbo the ID of a OpenGL Framebuffer object. Typically 0 (the screen)
227
 */
228 ed13a5de Leszek Koltunski
  public DistortedFramebuffer(int fbo)
229 b448e6b9 Leszek Koltunski
    {
230
    mProjectionMatrix = new float[16];
231
232 7304d89f Leszek Koltunski
    fboIds[0]      = fbo;
233
    texIds[0]      = TEXTURE_DONT_CREATE;
234 b448e6b9 Leszek Koltunski
    mFOV           = 60.0f;
235
    mX             = 0.0f;
236
    mY             = 0.0f;
237 bd3da5b2 Leszek Koltunski
238
    mMarked = false;
239 b448e6b9 Leszek Koltunski
    }
240
241 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
242 dedacd82 Leszek Koltunski
/**
243
 * Mark the underlying OpenGL object for deletion. Actual deletion will take place on the next render.
244
 */
245 bd3da5b2 Leszek Koltunski
  public void markForDeletion()
246 f6fb3c6d Leszek Koltunski
    {
247 7304d89f Leszek Koltunski
    android.util.Log.e("FBO", "marking for deletion ("+mWidth+","+mHeight+") "+fboIds[0]);
248 16d8b8f3 Leszek Koltunski
249 8e34674e Leszek Koltunski
    mListMarked = true;
250
    mMarked     = true;
251 f6fb3c6d Leszek Koltunski
    }
252
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254 dedacd82 Leszek Koltunski
/**
255
 * Create new Projection matrix.
256
 *
257
 * @param fov Vertical 'field of view' of the Projection frustrum (in degrees).
258 71c3fecc Leszek Koltunski
 * @param x X-coordinate of the point at which our camera looks at. -mWidth/2 &lt; x &lt; mWidth/2
259
 * @param y Y-coordinate of the point at which our camera looks at. -mHeight/2 &lt; y &lt; mHeight/2
260 dedacd82 Leszek Koltunski
 */
261
  public void setProjection(float fov, float x, float y)
262 f6fb3c6d Leszek Koltunski
    {
263 dedacd82 Leszek Koltunski
    mFOV = fov;
264 f6fb3c6d Leszek Koltunski
    mX   = x;
265
    mY   = y;
266
267
    createProjection();
268
    }
269
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271 dedacd82 Leszek Koltunski
/**
272
 * Resize the underlying Framebuffer.
273
 *
274
 * As the Framebuffer is not created until the first render, typical usage of this API is actually
275
 * to set the size of an not-yet-created Framebuffer of an object that has been created with the
276
 * second constructor.
277 71c3fecc Leszek Koltunski
 * <p>
278 dedacd82 Leszek Koltunski
 * Fully creating an object, rendering to it, then resizing mid-render is also possible.
279
 *
280
 * @param width The new width.
281
 * @param height The new height.
282
 */
283 f6fb3c6d Leszek Koltunski
  public void resize(int width, int height)
284
    {
285 bd3da5b2 Leszek Koltunski
    if( mWidth!=width || mHeight!=height )
286
      {
287
      mWidth = width;
288
      mHeight= height;
289 f6fb3c6d Leszek Koltunski
290 bd3da5b2 Leszek Koltunski
      createProjection();
291 f6fb3c6d Leszek Koltunski
292 7304d89f Leszek Koltunski
      if( texIds[0]>0 ) markForDeletion();
293 bd3da5b2 Leszek Koltunski
      }
294 f6fb3c6d Leszek Koltunski
    }
295
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297 dedacd82 Leszek Koltunski
/**
298
 * Set this as the Framebuffer to write to.
299
 */
300 f6fb3c6d Leszek Koltunski
301 71c3fecc Leszek Koltunski
  public void setAsOutput()
302 f6fb3c6d Leszek Koltunski
    {
303 7304d89f Leszek Koltunski
    if( texIds[0]==TEXTURE_NOT_CREATED_YET ) createFBO();
304 f6fb3c6d Leszek Koltunski
305 7304d89f Leszek Koltunski
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
306 f6fb3c6d Leszek Koltunski
    }
307 bd3da5b2 Leszek Koltunski
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309 dedacd82 Leszek Koltunski
/**
310
 * Set this as the Framebuffer to read from.
311
 */
312 bd3da5b2 Leszek Koltunski
313 71c3fecc Leszek Koltunski
  public void setAsInput()
314 bd3da5b2 Leszek Koltunski
    {
315 7304d89f Leszek Koltunski
    if( texIds[0]==TEXTURE_NOT_CREATED_YET ) createFBO();
316 bd3da5b2 Leszek Koltunski
317 7304d89f Leszek Koltunski
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
318 bd3da5b2 Leszek Koltunski
    }
319
320 f6fb3c6d Leszek Koltunski
  }