Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedFramebuffer.java @ dedacd82

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